[clang] [Clang] Only remove lambda scope after computing evaluation context (PR #154106)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 18 05:22:07 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Younan Zhang (zyn0217)
<details>
<summary>Changes</summary>
The immediate evaluation context needs the lambda scope info to propagate some flags, however that LSI was removed in ActOnFinishFunctionBody which happened before rebuilding a lambda expression.
This also converts the wrapper function to default arguments as a drive-by fix.
Fixes https://github.com/llvm/llvm-project/issues/145776
---
Full diff: https://github.com/llvm/llvm-project/pull/154106.diff
6 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+1)
- (modified) clang/include/clang/Sema/Sema.h (+7-6)
- (modified) clang/lib/Sema/SemaDecl.cpp (+4-7)
- (modified) clang/lib/Sema/SemaLambda.cpp (+12-2)
- (modified) clang/lib/Sema/TreeTransform.h (+4-7)
- (modified) clang/test/SemaCXX/cxx2b-consteval-propagate.cpp (+16)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9231f2cae9bfa..ca6fc663c9525 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -158,6 +158,7 @@ Bug Fixes to C++ Support
- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665)
- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293)
- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
+- Fixed a mismatched lambda scope bug when propagating up ``consteval`` within nested lambdas. (#GH145776)
- Fix an assertion failure when expression in assumption attribute
(``[[assume(expr)]]``) creates temporary objects.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5211373367677..160b0739b5aa2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4179,8 +4179,9 @@ class Sema final : public SemaBase {
/// return statement in the scope of a variable has the same NRVO candidate,
/// that candidate is an NRVO variable.
void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
- Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
- Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
+ Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body,
+ bool IsInstantiation = false,
+ bool RetainFunctionScopeInfo = false);
Decl *ActOnSkippedFunctionBody(Decl *Decl);
void ActOnFinishInlineFunctionDef(FunctionDecl *D);
@@ -6873,23 +6874,23 @@ class Sema final : public SemaBase {
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
return ExprEvalContexts.back();
- };
+ }
ExpressionEvaluationContextRecord ¤tEvaluationContext() {
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
return ExprEvalContexts.back();
- };
+ }
ExpressionEvaluationContextRecord &parentEvaluationContext() {
assert(ExprEvalContexts.size() >= 2 &&
"Must be in an expression evaluation context");
return ExprEvalContexts[ExprEvalContexts.size() - 2];
- };
+ }
const ExpressionEvaluationContextRecord &parentEvaluationContext() const {
return const_cast<Sema *>(this)->parentEvaluationContext();
- };
+ }
bool isAttrContext() const {
return ExprEvalContexts.back().ExprContext ==
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b5eb825eb52cc..4c8974b2e6c9a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16149,10 +16149,6 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
return Decl;
}
-Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
- return ActOnFinishFunctionBody(D, BodyArg, /*IsInstantiation=*/false);
-}
-
/// RAII object that pops an ExpressionEvaluationContext when exiting a function
/// body.
class ExitFunctionBodyRAII {
@@ -16223,8 +16219,8 @@ void Sema::CheckCoroutineWrapper(FunctionDecl *FD) {
Diag(FD->getLocation(), diag::err_coroutine_return_type) << RD;
}
-Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
- bool IsInstantiation) {
+Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
+ bool RetainFunctionScopeInfo) {
FunctionScopeInfo *FSI = getCurFunction();
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
@@ -16681,7 +16677,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (!IsInstantiation)
PopDeclContext();
- PopFunctionScopeInfo(ActivePolicy, dcl);
+ if (!RetainFunctionScopeInfo)
+ PopFunctionScopeInfo(ActivePolicy, dcl);
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index bc3c4b0addeba..eb6bc83cf861a 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1968,12 +1968,13 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body) {
- LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
+ LambdaScopeInfo &LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
if (LSI.CallOperator->hasAttr<SYCLKernelEntryPointAttr>())
SYCL().CheckSYCLEntryPointFunctionDecl(LSI.CallOperator);
- ActOnFinishFunctionBody(LSI.CallOperator, Body);
+ ActOnFinishFunctionBody(LSI.CallOperator, Body, /*IsInstantiation=*/false,
+ /*RetainFunctionScopeInfo=*/true);
return BuildLambdaExpr(StartLoc, Body->getEndLoc(), &LSI);
}
@@ -2134,6 +2135,11 @@ ConstructFixItRangeForUnusedCapture(Sema &S, SourceRange CaptureRange,
ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
LambdaScopeInfo *LSI) {
+ // Copy the LSI before PopFunctionScopeInfo removes it.
+ // FIXME: This is dumb. Store the lambda information somewhere that outlives
+ // the call operator.
+ LambdaScopeInfo LSICopy = *LSI;
+ LSI = &LSICopy;
// Collect information from the lambda scope.
SmallVector<LambdaCapture, 4> Captures;
SmallVector<Expr *, 4> CaptureInits;
@@ -2170,6 +2176,10 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
PopExpressionEvaluationContext();
+ sema::AnalysisBasedWarnings::Policy WP =
+ AnalysisWarnings.getPolicyInEffectAt(EndLoc);
+ PopFunctionScopeInfo(&WP, LSI->CallOperator);
+
// True if the current capture has a used capture or default before it.
bool CurHasPreviousCapture = CaptureDefault != LCD_None;
SourceLocation PrevCaptureLoc = CurHasPreviousCapture ?
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5ff5fbf52ae25..c3893959c85bf 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15791,12 +15791,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
return ExprError();
}
- // Copy the LSI before ActOnFinishFunctionBody removes it.
- // FIXME: This is dumb. Store the lambda information somewhere that outlives
- // the call operator.
- auto LSICopy = *LSI;
getSema().ActOnFinishFunctionBody(NewCallOperator, Body.get(),
- /*IsInstantiation*/ true);
+ /*IsInstantiation=*/true,
+ /*RetainFunctionScopeInfo=*/true);
SavedContext.pop();
// Recompute the dependency of the lambda so that we can defer the lambda call
@@ -15832,7 +15829,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// *after* the substitution in case we can't decide the dependency
// so early, e.g. because we want to see if any of the *substituted*
// parameters are dependent.
- DependencyKind = getDerived().ComputeLambdaDependency(&LSICopy);
+ DependencyKind = getDerived().ComputeLambdaDependency(LSI);
Class->setLambdaDependencyKind(DependencyKind);
// Clean up the type cache created previously. Then, we re-create a type for
// such Decl with the new DependencyKind.
@@ -15840,7 +15837,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().Context.getTypeDeclType(Class);
return getDerived().RebuildLambdaExpr(E->getBeginLoc(),
- Body.get()->getEndLoc(), &LSICopy);
+ Body.get()->getEndLoc(), LSI);
}
template<typename Derived>
diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
index c4cfd9398920a..6cf0e0251ab62 100644
--- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
+++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
@@ -610,3 +610,19 @@ namespace GH135281 {
void (*ff)() = f2<B>; // expected-note {{instantiation of function template specialization}}
}
#endif
+
+namespace GH145776 {
+
+void runtime_only() {}
+consteval void comptime_only() {}
+
+void fn() {
+ []() {
+ runtime_only();
+ []() {
+ &comptime_only;
+ }();
+ }();
+}
+
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/154106
More information about the cfe-commits
mailing list