[clang] [Clang] Fix evaluation context of lambdas appearing in discarded statements (PR #146857)

Corentin Jabot via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 3 06:11:27 PDT 2025


https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/146857

>From 4ee72df191e9792be38195b00b0f6422de3a767a Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 3 Jul 2025 13:00:46 +0200
Subject: [PATCH 1/2] [Clang] Fix evaluation context of lambdas appearing in
 discarded statements

Fixes 2 bugs reported in #146063

 - The body of a lambda appearing in a discarded statement was sometimes
   considered discarded itself
 - A lambda conversion operator that was not odr-used was sometimes not
   defined even if it was needed

Fixes #146063
---
 clang/lib/Sema/SemaExpr.cpp                   |  5 +++++
 clang/lib/Sema/TreeTransform.h                | 10 +++------
 .../CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp  | 22 +++++++++++++++++++
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 437df742d572b..a23497afddefe 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18252,6 +18252,11 @@ static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
 
   if (Func->isImplicitlyInstantiable() || !Func->isUserProvided())
     return true;
+
+  // Lambda conversion operators are never user provided
+  if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Func))
+    return isLambdaConversionOperator(Conv);
+
   auto *CCD = dyn_cast<CXXConstructorDecl>(Func);
   return CCD && CCD->getInheritedConstructor();
 }
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0d58587cb8a99..2f57672375a01 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15723,13 +15723,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
 
   // FIXME: Sema's lambda-building mechanism expects us to push an expression
   // evaluation context even if we're not transforming the function body.
-  getSema().PushExpressionEvaluationContext(
-      E->getCallOperator()->isConsteval() ?
-      Sema::ExpressionEvaluationContext::ImmediateFunctionContext :
-      Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
-  getSema().currentEvaluationContext().InImmediateEscalatingFunctionContext =
-      getSema().getLangOpts().CPlusPlus20 &&
-      E->getCallOperator()->isImmediateEscalating();
+  getSema().PushExpressionEvaluationContextForFunction(
+      Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
+      E->getCallOperator());
 
   Sema::CodeSynthesisContext C;
   C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution;
diff --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
index ac21e36daf870..abb42447d3e0b 100644
--- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
@@ -218,4 +218,26 @@ void regression() {
 
 }
 
+namespace GH146063 {
+template <typename>
+struct A {
+  static_assert([]() constexpr { return true; }());
+};
+
+void f1() {
+  if constexpr (false) {
+    A<int> a;
+  }
+}
+
+void f2() {
+  if constexpr (false) {
+    static_assert([]{});
+    // expected-warning at -1 {{address of lambda function pointer conversion operator will always evaluate to 'true'}}
+  }
+}
+
+}
+
+
 #endif

>From 34b4b5e0f22b99dd04e5007ff4ea401908f3ac38 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 3 Jul 2025 15:11:19 +0200
Subject: [PATCH 2/2] Update clang/lib/Sema/SemaExpr.cpp

Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
 clang/lib/Sema/SemaExpr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a23497afddefe..f2954cb287c8d 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18253,7 +18253,7 @@ static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
   if (Func->isImplicitlyInstantiable() || !Func->isUserProvided())
     return true;
 
-  // Lambda conversion operators are never user provided
+  // Lambda conversion operators are never user provided.
   if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Func))
     return isLambdaConversionOperator(Conv);
 



More information about the cfe-commits mailing list