Message ID | 20231107195244.1658781-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: decltype of (by-value captured reference) [PR79620] | expand |
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 > >
On 11/7/23 14:52, 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. > > 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)) Let's also have outer_automatic_var_p assert that its argument is not REFERENCE_REF_P. OK with that change (if no regressions). Jason
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& + }; + }; +}