[PATCH] c++: nested lambda capturing a capture proxy, part 2 [PR94376]

Jason Merrill jason@redhat.com
Thu Dec 16 21:14:11 GMT 2021


On 12/16/21 11:28, Patrick Palka wrote:
> On Wed, 15 Dec 2021, Jason Merrill wrote:
> 
>> On 12/15/21 15:36, Patrick Palka wrote:
>>> The r12-5403 fix apparently doesn't handle the case where the inner
>>> lambda explicitly rather implicitly captures the capture proxy from
>>> the outer lambda, and so we still reject the first example in the
>>> testcase below.
>>>
>>> The reason is that compared to an implicit capture, the effective
>>> initializer for an explicit capture is wrapped in a location wrapper
>>> (pointing to the source location of the explicit capture), and this
>>> wrapper foils the is_capture_proxy check.  The simplest fix appears to
>>> be to strip location wrappers accordingly.
>>>
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
>>> trunk?
>>>
>>> 	PR c++/94376
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	* lambda.c (lambda_capture_field_type): Strip location wrappers
>>> 	before checking for a capture proxy.
>>
>> I think either is_capture_proxy should strip location wrappers or
>> gcc_checking_assert that it doesn't see one.
> 
> Good idea, here's v2 which adds an assert to is_capture_proxy.  Only one
> other caller, mark_const_cap_r, had to be adjusted.

OK.

> -- >8 --
> 
> The r12-5403 fix apparently doesn't handle the case where the inner
> lambda explicitly rather implicitly captures the capture proxy from
> the outer lambda, which causes us to reject the first example in the
> testcase below.
> 
> This is because compared to an implicit capture, the effective initializer
> for an explicit capture is wrapped in a location wrapper (pointing to the
> capture list), and this wrapper foils the is_capture_proxy check added in
> r12-5403.
> 
> The simplest fix appears to be to strip location wrappers accordingly
> before checking is_capture_proxy.  To help prevent against other
> occurrences of this kind of bug, this patch also makes is_capture_proxy
> assert it doesn't see a location wrapper.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> 	PR c++/94376
> 
> gcc/cp/ChangeLog:
> 
> 	* lambda.c (lambda_capture_field_type): Strip location wrappers
> 	before checking for a capture proxy.
> 	(is_capture_proxy): Assert that we don't see a location wrapper.
> 	(mark_const_cap_r): Don't call is_constant_capture_proxy on a
> 	location wrapper.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/lambda/lambda-nested9a.C: New test.
> ---
>   gcc/cp/lambda.c                               |  7 ++++
>   .../g++.dg/cpp0x/lambda/lambda-nested9a.C     | 42 +++++++++++++++++++
>   2 files changed, 49 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C
> 
> diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
> index c39a2bca416..d14e12c48f0 100644
> --- a/gcc/cp/lambda.c
> +++ b/gcc/cp/lambda.c
> @@ -221,6 +221,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
>       }
>     else
>       {
> +      STRIP_ANY_LOCATION_WRAPPER (expr);
>         if (!by_reference_p && is_capture_proxy (expr))
>   	{
>   	  /* When capturing by-value another capture proxy from an enclosing
> @@ -246,6 +247,10 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
>   bool
>   is_capture_proxy (tree decl)
>   {
> +  /* Location wrappers should be stripped or otherwise handled by the
> +     caller before using this predicate.  */
> +  gcc_checking_assert (!location_wrapper_p (decl));
> +
>     return (VAR_P (decl)
>   	  && DECL_HAS_VALUE_EXPR_P (decl)
>   	  && !DECL_ANON_UNION_VAR_P (decl)
> @@ -1496,6 +1501,8 @@ mark_const_cap_r (tree *t, int *walk_subtrees, void *data)
>   	  *walk_subtrees = 0;
>   	}
>       }
> +  else if (location_wrapper_p (*t))
> +    /* is_capture_proxy dislikes location wrappers.  */;
>     else if (is_constant_capture_proxy (*t))
>       var = DECL_CAPTURED_VARIABLE (*t);
>   
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C
> new file mode 100644
> index 00000000000..d62f8f0c952
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C
> @@ -0,0 +1,42 @@
> +// PR c++/94376
> +// Like lambda-nested9.C but using explicit captures in the inner lambda.
> +// { dg-do compile { target c++11 } }
> +
> +int main() {
> +  // We used to incorrectly reject the first two cases.
> +  int i = 0;
> +  [=] () {
> +    [i] () mutable {
> +      ++i;
> +    };
> +  };
> +
> +#if __cpp_init_captures
> +  [j=0] () {
> +    [j] () mutable {
> +      ++j;
> +    };
> +  };
> +#endif
> +
> +  [=] () {
> +    [&i] () mutable {
> +      ++i; // { dg-error "read-only" }
> +    };
> +  };
> +
> +  const int j = 0;
> +  [=] () {
> +    [j] () mutable {
> +      ++j; // { dg-error "read-only" }
> +    };
> +  };
> +
> +#if __cpp_init_captures
> +  [j=0] () {
> +    [&j] () mutable {
> +      ++j; // { dg-error "read-only" "" { target c++14 } }
> +    };
> +  };
> +#endif
> +}



More information about the Gcc-patches mailing list