[PATCH] c++: nested lambda capturing a capture proxy [PR94376]
Patrick Palka
ppalka@redhat.com
Thu Nov 18 22:48:08 GMT 2021
On Thu, 18 Nov 2021, Jason Merrill wrote:
> 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?
IIRC that'd work for normal capture proxies, but DECL_CAPTURED_VARIABLE
is empty for explicitly-initialized captures and their capture proxies
have the same issue.
>
> > + }
> > +
> > 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