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