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" }
+}

Reply via email to