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

Jason Merrill jason@redhat.com
Thu Nov 18 22:18:44 GMT 2021


On 11/2/21 14:06, Patrick Palka wrote:
> Here when determining the type of the FIELD_DECL for the by-value
> capture of 'i' in the inner lambda, we incorrectly give it the
> type const int instead of int since the effective initializer is
> the proxy for the outer capture, and this proxy is const qualified
> since the outer lambda is non-mutable.
> 
> This patch fixes this by handling capturing of capture proxies specially
> in lambda_capture_field_type, namely we instead consider the type of
> their FIELD_DECL which unlike the proxy has the true cv-quals of the
> captured entity.
> 
> 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): Simplify by handling the
> 	is_this case first and specially.  When capturing by-value a
> 	capture proxy, consider the type of the corresponding field
> 	instead.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/lambda/lambda-nested9.C: New test.
> ---
>   gcc/cp/lambda.c                               | 19 +++++++--
>   .../g++.dg/cpp0x/lambda/lambda-nested9.C      | 41 +++++++++++++++++++
>   2 files changed, 56 insertions(+), 4 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C
> 
> diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
> index 2e9d38bbe83..f16c121dc78 100644
> --- a/gcc/cp/lambda.c
> +++ b/gcc/cp/lambda.c
> @@ -196,7 +196,9 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
>     tree type;
>     bool is_this = is_this_parameter (tree_strip_nop_conversions (expr));
>   
> -  if (!is_this && explicit_init_p)
> +  if (is_this)
> +    type = TREE_TYPE (expr);
> +  else if (explicit_init_p)
>       {
>         tree auto_node = make_auto ();
>         
> @@ -210,7 +212,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
>         else
>   	type = do_auto_deduction (type, expr, auto_node);
>       }
> -  else if (!is_this && type_dependent_expression_p (expr))
> +  else if (type_dependent_expression_p (expr))
>       {
>         type = cxx_make_type (DECLTYPE_TYPE);
>         DECLTYPE_TYPE_EXPR (type) = expr;
> @@ -220,10 +222,19 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
>       }
>     else
>       {
> +      if (!by_reference_p && is_capture_proxy (expr))
> +	{
> +	  /* When capturing by-value another capture proxy from an enclosing
> +	     lambda, consider the type of the corresponding field instead,
> +	     as the proxy may be const-qualifed if the enclosing lambda is
> +	     non-mutable (PR94376).  */
> +	  gcc_assert (TREE_CODE (DECL_VALUE_EXPR (expr)) == COMPONENT_REF);
> +	  expr = TREE_OPERAND (DECL_VALUE_EXPR (expr), 1);

Is there a reason not to use DECL_CAPTURED_VARIABLE?

> +	}
> +
>         type = non_reference (unlowered_expr_type (expr));
>   
> -      if (!is_this
> -	  && (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE))
> +      if (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE)
>   	type = build_reference_type (type);
>       }
>   
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C
> new file mode 100644
> index 00000000000..ff7da3b0ce1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C
> @@ -0,0 +1,41 @@
> +// PR c++/94376
> +// { dg-do compile { target c++11 } }
> +
> +int main() {
> +  // We used to incorrectly reject the first two cases.
> +  int i = 0;
> +  [=] () {
> +    [=] () mutable {
> +      ++i;
> +    };
> +  };
> +
> +#if __cpp_init_captures
> +  [j=0] () {
> +    [=] () mutable {
> +      ++j;
> +    };
> +  };
> +#endif
> +
> +  [=] () {
> +    [&] () mutable {
> +      ++i; // { dg-error "read-only" }
> +    };
> +  };
> +
> +  const int j = 0;
> +  [=] () {
> +    [=] () mutable {
> +      ++j; // { dg-error "read-only" }
> +    };
> +  };
> +
> +#if __cpp_init_captures
> +  [j=0] () {
> +    [&] () mutable {
> +      ++j; // { dg-error "read-only" }
> +    };
> +  };
> +#endif
> +}
> 



More information about the Gcc-patches mailing list