https://github.com/Ferdi265 updated 
https://github.com/llvm/llvm-project/pull/232458

>From d1c540ad942a4eb7c0da7622361bb3a606a1fa00 Mon Sep 17 00:00:00 2001
From: Ferdinand Bachmann <[email protected]>
Date: Thu, 15 Oct 2026 20:39:08 +0200
Subject: [PATCH] [Clang][Sema] Fix lambdas mistakenly inheriting
 InImmediateFunctionContext

As per [expr.const]/p14.1, only the innermost enclosing function
parameter scope matters for determining whether a function or lambda is
in an immediate function context. It does not matter whether the parent
is an immediate function or not.

However, synthesized functions such as Lambda conversion operators and
constructors do need to inherit immediate function context from the
parent. Fix this by explicitly exempting the lambda call operator from
this inheritance.

This fixes assertions on valid programs and miscompilations related to
immediate functions being callable from non-immediate contexts due to
missed escalation of lambdas to immediate functions.

Fixes #183415.

Signed-off-by: Ferdinand Bachmann <[email protected]>
---
 clang/lib/Sema/SemaExpr.cpp                   |  9 ++--
 .../SemaCXX/cxx2b-consteval-propagate.cpp     | 50 +++++++++++++++++++
 2 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e29caaab8e3f30..2e9a3b73e5c658 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18546,11 +18546,10 @@ void Sema::PushExpressionEvaluationContextForFunction(
     Current.InImmediateEscalatingFunctionContext =
         getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
 
-    if (isLambdaMethod(FD))
-      Current.InImmediateFunctionContext =
-          FD->isConsteval() ||
-          (isLambdaMethod(FD) && (Parent.isConstantEvaluated() ||
-                                  Parent.isImmediateFunctionContext()));
+    if (isLambdaMethod(FD) && !isLambdaCallOperator(FD))
+      Current.InImmediateFunctionContext = FD->isConsteval() ||
+                                           Parent.isConstantEvaluated() ||
+                                           Parent.isImmediateFunctionContext();
     else
       Current.InImmediateFunctionContext = FD->isConsteval();
   }
diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp 
b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
index 39097d17441f7c..19b66d4cb94e33 100644
--- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
+++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
@@ -659,3 +659,53 @@ scope_exit guard( // expected-note {{in instantiation of 
member function}}
 );
 
 }
+
+namespace GH183415 {
+consteval void f(int) {}
+
+void test1() {
+    auto g = []() consteval {
+        return [](int x) {
+            f(x);
+        };
+    }();
+
+    int x = 42; // expected-note {{declared here}}
+    g(x); // expected-error@-1 {{call to immediate function 
'GH183415::test1()::(lambda)::operator()::(lambda)::operator()' is not a 
constant expression}} \
+          // expected-note {{read of non-const variable 'x' is not allowed in 
a constant expression}}
+}
+
+struct F {
+    consteval F(int) {}
+};
+
+void test2() {
+    auto g = []() consteval {
+        return [](int x) {
+            return F(x);
+        };
+    }();
+
+    int x = 42; // expected-note {{declared here}}
+    g(x); // expected-error@-1 {{call to immediate function 
'GH183415::test2()::(lambda)::operator()::(lambda)::operator()' is not a 
constant expression}} \
+          // expected-note {{read of non-const variable 'x' is not allowed in 
a constant expression}}
+}
+
+consteval void f() {}
+
+template <auto a>
+auto id = a;
+
+void test3() {
+  id<[]{ f(); }>(); // ok, lambda is escalated to an immediate function
+}
+
+void test4(int a) { // expected-note {{declared here}}
+  auto g = id<[](int i){ f(i); }>;
+  g(a); // expected-error@-1 {{call to immediate function 
'GH183415::test4(int)::(lambda)::operator()' is not a constant expression}} \
+        // expected-note {{function parameter 'a' with unknown value cannot be 
used in a constant expression}}
+}
+
+static_assert(+[]{}); // ok, static_assert is manifestly-constant-evaluated, 
which should allow taking the address of lambda call operator
+
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to