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
