https://gcc.gnu.org/g:97bcbeb6e12d644442f69bca09110c5392584460
commit r17-5384-g97bcbeb6e12d644442f69bca09110c5392584460 Author: Shubham Nayak <[email protected]> Date: Tue Oct 20 01:36:00 2026 +0530 c++: remove redundant lvalue check for reference captures [PR87638] In add_capture, reference captures were unconditionally rejected whenever !lvalue_p (initializer) was true. This check predates C++14 init-captures and is redundant with build_lambda_object, which already validates the initialization of each capture field via finish_compound_literal and initialize_reference. Even worse was that checking !lvalue_p in add_capture rejects valid C++14 reference init-captures which are: 1. reference init-captures bound to const xvalues or const class prvalues, where auto deduction yields 'const T&' ([expr.prim.lambda.capture] p6, [dcl.init.ref] p5). 2. direct-list-initialized reference init-captures (per [expr.prim.lambda.capture] p6) where initializer is a CONSTRUCTOR node and hence not an lvalue. Remove the redundant check in add_capture and let build_lambda_object diagnose invalid reference bindings. This patch has been regtested on x86_64-pc-linux-gnu. PR c++/87638 PR c++/90789 PR c++/95069 PR c++/104411 PR c++/115471 gcc/cp/ChangeLog: * lambda.cc (add_capture): Remove redundant !lvalue_p check on reference captures. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/lambda-init-const-ref.C: New test. * g++.dg/cpp1y/lambda-init21.C: New test. Signed-off-by: Shubham Nayak <[email protected]> Diff: --- gcc/cp/lambda.cc | 12 +------ gcc/testsuite/g++.dg/cpp1y/lambda-init-const-ref.C | 41 ++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp1y/lambda-init21.C | 16 +++++++++ 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index ff76b98d6e78..5677c6e6e66d 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -630,17 +630,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, initializer = cp_build_fold_indirect_ref (initializer); } - if (dependent_type_p (type)) - ; - else if (id != this_identifier && by_reference_p) - { - if (!lvalue_p (initializer)) - { - error ("cannot capture %qE by reference", initializer); - return error_mark_node; - } - } - else + if (!dependent_type_p (type) && !by_reference_p) { /* Capture by copy requires a complete type. */ type = complete_type (type); diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init-const-ref.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init-const-ref.C new file mode 100644 index 000000000000..a0d90883b970 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init-const-ref.C @@ -0,0 +1,41 @@ +// PR c++/87638 +// PR c++/90789 +// PR c++/115471 +// { dg-do compile { target c++14 } } + +struct S { int x; }; +constexpr const S make_const_s () { return S{7}; } +constexpr const int&& make_const_xval (const int& x) { return static_cast<const int&&>(x); } + +template <typename T> +T +test_dependent (const T a) +{ + auto l = [&r = static_cast<const T&&>(a)] { return r; }; + return l (); +} + +void +test_valid () +{ + const int ca = 5; + // Const xvalue via static_cast or function call (PR c++/115471) + auto l1 = [&r = static_cast<const int&&>(ca)] { return r; }; + auto l2 = [&r = make_const_xval (ca)] { return r; }; + + // Const class prvalue (PR c++/87638, PR c++/90789) + auto l3 = [&r = make_const_s ()] { return r.x; }; + + test_dependent (42); +} + +void +test_invalid () +{ + int a = 5; + const volatile int cva = 5; + + auto b1 = [&r = static_cast<int&&>(a)] {}; // { dg-error "cannot bind" } + auto b2 = [&r = 5] {}; // { dg-error "cannot bind" } + auto b3 = [&r = static_cast<const volatile int&&>(cva)] {}; // { dg-error "cannot bind" } +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init21.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init21.C new file mode 100644 index 000000000000..9b4eb34ff551 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init21.C @@ -0,0 +1,16 @@ +// PR c++/95069 +// PR c++/104411 +// { dg-do compile { target c++14 } } + +int main() +{ + auto a = 5; + const int ca = 5; + + // Direct-list initialization of reference capture (PR c++/95069, PR c++/104411) + auto l1 = [&r{a}] { return r; }; + auto l2 = [&r{ca}] { return r; }; + + // Invalid, can't bind non-const lvalue reference to rvalue + auto wl = [&r{5}] {}; // { dg-error "cannot bind" } +}
