On Tue, 7 Nov 2023, Patrick Palka wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look > OK for trunk? > > -- >8 -- > > The capture decltype handling in finish_decltype_type wasn't looking > through implicit INDIRECT_REF (added by convert_from_reference), which > caused us to incorrectly resolve decltype((x)) to float& below.
Oops, this should say decltype((r)). We already correctly resolve decltype((x)) to const float& (since x isn't a reference). > > We still don't fully accept the example ultimately because when > processing the decltype inside the first lambda's trailing return type, > we're in lambda type scope but not yet in lambda function scope that > the check looks for, which seems like an orthogonal bug. > > PR c++/79620 > > gcc/cp/ChangeLog: > > * cp-tree.h (STRIP_REFERENCE_REF): Define. > * semantics.cc (finish_decltype_type): Use it to look > through implicit INDIRECT_REF when deciding whether to > call capture_decltype. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/lambda/lambda-decltype3.C: New test. > --- > gcc/cp/cp-tree.h | 4 +++ > gcc/cp/semantics.cc | 4 +-- > .../g++.dg/cpp0x/lambda/lambda-decltype3.C | 28 +++++++++++++++++++ > 3 files changed, 34 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index b2603d4830e..1fa710d7154 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -4084,6 +4084,10 @@ struct GTY(()) lang_decl { > && TREE_TYPE (TREE_OPERAND (NODE, 0)) \ > && TYPE_REF_P (TREE_TYPE (TREE_OPERAND ((NODE), 0)))) > > +/* Look through an implicit INDIRECT_REF from convert_from_reference. */ > +#define STRIP_REFERENCE_REF(NODE) \ > + (REFERENCE_REF_P (NODE) ? TREE_OPERAND (NODE, 0) : NODE) > + > /* True iff this represents an lvalue being treated as an rvalue during > return > or throw as per [class.copy.elision]. */ > #define IMPLICIT_RVALUE_P(NODE) \ > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index f583dedd6cf..8df4521bf7c 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > @@ -11717,10 +11717,10 @@ finish_decltype_type (tree expr, bool > id_expression_or_member_access_p, > transformed into an access to a corresponding data member > of the closure type that would have been declared if x > were a use of the denoted entity. */ > - if (outer_automatic_var_p (expr) > + if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr)) > && current_function_decl > && LAMBDA_FUNCTION_P (current_function_decl)) > - type = capture_decltype (expr); > + type = capture_decltype (STRIP_REFERENCE_REF (expr)); > else if (error_operand_p (expr)) > type = error_mark_node; > else if (expr == current_class_ptr) > diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C > b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C > new file mode 100644 > index 00000000000..7fc157aefb5 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C > @@ -0,0 +1,28 @@ > +// PR c++/79620 > +// [expr.prim.id.unqual] example 1 > +// { dg-do compile { target c++11 } } > + > +void f() { > + float x, &r = x; > + > + [=]() -> decltype((x)) { // lambda returns float const& because this > lambda is not mutable and > + // x is an lvalue > + decltype(x) y1; // y1 has type float > + decltype((x)) y2 = y1; // y2 has type float const& > + decltype(r) r1 = y1; // r1 has type float& > + decltype((r)) r2 = y2; // r2 has type float const& > + return y2; // { dg-bogus "'float&' to 'const float'" "" > { xfail *-*-* } } > + }; > + > + [=](decltype((x)) y) { > + decltype((x)) z = x; // OK, y has type float&, z has type float > const& > + }; > + > + [=] { > + [](decltype((x)) y) {}; // OK, lambda takes a parameter of type > float const& > + > + [x=1](decltype((x)) y) { > + decltype((x)) z = x; // OK, y has type int&, z has type int const& > + }; > + }; > +} > -- > 2.43.0.rc0.23.g8be77c5de6 > >