&& 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) \
static bool
outer_var_p (tree decl)
{
+ /* These should have been stripped or otherwise handled by the caller. */
+ gcc_checking_assert (!REFERENCE_REF_P (decl));
+
return ((VAR_P (decl) || TREE_CODE (decl) == PARM_DECL)
&& DECL_FUNCTION_SCOPE_P (decl)
/* Don't get confused by temporaries. */
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)
--- /dev/null
+// 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&
+ };
+ };
+}