We've been rejecting this valid code since r8-4571:

=== cut here ===
void foo (float);
int main () {
  constexpr float x = 0;
  (void) [&] () {
    foo (x);
    (void) [] () {
      foo (x);
    };
  };
}
=== cut here ===

The problem is that when processing X in the inner lambda,
process_outer_var_ref errors out even though it does find the capture
from the enclosing lambda.

This patch changes process_outer_var_ref to accept and return the outer
proxy if it finds any.

Successfully tested on x86_64-pc-linux-gnu.

        PR c++/110584

gcc/cp/ChangeLog:

        * semantics.cc (process_outer_var_ref): Use capture from
        enclosing lambda, if any.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/lambda/lambda-nested10.C: New test.

---
 gcc/cp/semantics.cc                           |  4 ++
 .../g++.dg/cpp0x/lambda/lambda-nested10.C     | 46 +++++++++++++++++++
 2 files changed, 50 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7c7d3e3c432..7bbc82f7dc1 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4598,6 +4598,10 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain, bool odr_use)
   if (!odr_use && context == containing_function)
     decl = add_default_capture (lambda_stack,
                                /*id=*/DECL_NAME (decl), initializer);
+  /* When doing lambda capture, if we found a capture in an enclosing lambda,
+     we can use it.  */
+  else if (!odr_use && is_capture_proxy (decl))
+    return decl;
   /* Only an odr-use of an outer automatic variable causes an
      error, and a constant variable can decay to a prvalue
      constant without odr-use.  So don't complain yet.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C 
b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
new file mode 100644
index 00000000000..2dd9dd4955e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
@@ -0,0 +1,46 @@
+// PR c++/110584
+// { dg-do "run" { target c++11 } }
+
+void foo (int i) {
+  if (i != 0)
+    __builtin_abort ();
+}
+
+int main () {
+  const int x = 0;
+
+  // We would error out on this.
+  (void) [&] () {
+    foo (x);
+    (void)[] () {
+      foo (x);
+    };
+  } ();
+  // As well as those.
+  (void) [&] () {
+    (void) [] () {
+      foo (x);
+    };
+  } ();
+  (void) [&x] () {
+    (void) [] () {
+      foo (x);
+    };
+  } ();
+  // But those would work already.
+  (void) [] () {
+    (void) [&] () {
+      foo (x);
+    };
+  } ();
+  (void) [&] () {
+    (void) [&] () {
+      foo (x);
+    };
+  } ();
+  (void) [=] () {
+    (void) [] () {
+      foo (x);
+    };
+  } ();
+}
-- 
2.44.0

Reply via email to