Skip to content

Revert "[Clang] Only remove lambda scope after computing evaluation context" #154382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ 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.
- Fix the dynamic_cast to final class optimization to correctly handle
Expand Down
22 changes: 8 additions & 14 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4176,15 +4176,8 @@ 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);

/// Performs semantic analysis at the end of a function body.
///
/// \param RetainFunctionScopeInfo If \c true, the client is responsible for
/// releasing the associated \p FunctionScopeInfo. This is useful when
/// building e.g. LambdaExprs.
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body,
bool IsInstantiation = false,
bool RetainFunctionScopeInfo = false);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
Decl *ActOnSkippedFunctionBody(Decl *Decl);
void ActOnFinishInlineFunctionDef(FunctionDecl *D);

Expand Down Expand Up @@ -6881,23 +6874,23 @@ class Sema final : public SemaBase {
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
return ExprEvalContexts.back();
}
};

ExpressionEvaluationContextRecord &currentEvaluationContext() {
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 ==
Expand Down Expand Up @@ -9147,7 +9140,8 @@ class Sema final : public SemaBase {

/// Complete a lambda-expression having processed and attached the
/// lambda body.
ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc);
ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
sema::LambdaScopeInfo *LSI);

/// Get the return type to use for a lambda's conversion function(s) to
/// function pointer type, given the type of the call operator.
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16228,6 +16228,10 @@ 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 {
Expand Down Expand Up @@ -16298,8 +16302,8 @@ void Sema::CheckCoroutineWrapper(FunctionDecl *FD) {
Diag(FD->getLocation(), diag::err_coroutine_return_type) << RD;
}

Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
bool RetainFunctionScopeInfo) {
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
bool IsInstantiation) {
FunctionScopeInfo *FSI = getCurFunction();
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;

Expand Down Expand Up @@ -16756,8 +16760,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
if (!IsInstantiation)
PopDeclContext();

if (!RetainFunctionScopeInfo)
PopFunctionScopeInfo(ActivePolicy, dcl);
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.
Expand Down
18 changes: 5 additions & 13 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1968,15 +1968,14 @@ 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, /*IsInstantiation=*/false,
/*RetainFunctionScopeInfo=*/true);
ActOnFinishFunctionBody(LSI.CallOperator, Body);

return BuildLambdaExpr(StartLoc, Body->getEndLoc());
return BuildLambdaExpr(StartLoc, Body->getEndLoc(), &LSI);
}

static LambdaCaptureDefault
Expand Down Expand Up @@ -2133,9 +2132,8 @@ ConstructFixItRangeForUnusedCapture(Sema &S, SourceRange CaptureRange,
return SourceRange(FixItStart, FixItEnd);
}

ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc,
SourceLocation EndLoc) {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(FunctionScopes.back());
ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
LambdaScopeInfo *LSI) {
// Collect information from the lambda scope.
SmallVector<LambdaCapture, 4> Captures;
SmallVector<Expr *, 4> CaptureInits;
Expand Down Expand Up @@ -2172,12 +2170,6 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc,

PopExpressionEvaluationContext();

sema::AnalysisBasedWarnings::Policy WP =
AnalysisWarnings.getPolicyInEffectAt(EndLoc);
// We cannot release LSI until we finish computing captures, which
// requires the scope to be popped.
PoppedFunctionScopePtr _ = 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 ?
Expand Down
13 changes: 8 additions & 5 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -4051,7 +4051,7 @@ class TreeTransform {
PVD->getUninstantiatedDefaultArg()
->containsUnexpandedParameterPack();
}
return getSema().BuildLambdaExpr(StartLoc, EndLoc);
return getSema().BuildLambdaExpr(StartLoc, EndLoc, LSI);
}

/// Build an empty C++1z fold-expression with the given operator.
Expand Down Expand Up @@ -15712,9 +15712,12 @@ 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,
/*RetainFunctionScopeInfo=*/true);
/*IsInstantiation*/ true);
SavedContext.pop();

// Recompute the dependency of the lambda so that we can defer the lambda call
Expand Down Expand Up @@ -15750,11 +15753,11 @@ 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(LSI);
DependencyKind = getDerived().ComputeLambdaDependency(&LSICopy);
Class->setLambdaDependencyKind(DependencyKind);

return getDerived().RebuildLambdaExpr(E->getBeginLoc(),
Body.get()->getEndLoc(), LSI);
Body.get()->getEndLoc(), &LSICopy);
}

template<typename Derived>
Expand Down
16 changes: 0 additions & 16 deletions clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,19 +610,3 @@ 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;
}();
}();
}

}
Loading