Skip to content

Commit 2b32ad1

Browse files
authored
[Clang] Only remove lambda scope after computing evaluation context (#154106)
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 #145776
1 parent f55dc08 commit 2b32ad1

File tree

6 files changed

+53
-28
lines changed

6 files changed

+53
-28
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ Bug Fixes to C++ Support
225225
- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665)
226226
- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293)
227227
- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
228+
- Fixed a mismatched lambda scope bug when propagating up ``consteval`` within nested lambdas. (#GH145776)
228229
- Fix an assertion failure when expression in assumption attribute
229230
(``[[assume(expr)]]``) creates temporary objects.
230231
- Fix the dynamic_cast to final class optimization to correctly handle

clang/include/clang/Sema/Sema.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4176,8 +4176,15 @@ class Sema final : public SemaBase {
41764176
/// return statement in the scope of a variable has the same NRVO candidate,
41774177
/// that candidate is an NRVO variable.
41784178
void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
4179-
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
4180-
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
4179+
4180+
/// Performs semantic analysis at the end of a function body.
4181+
///
4182+
/// \param RetainFunctionScopeInfo If \c true, the client is responsible for
4183+
/// releasing the associated \p FunctionScopeInfo. This is useful when
4184+
/// building e.g. LambdaExprs.
4185+
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body,
4186+
bool IsInstantiation = false,
4187+
bool RetainFunctionScopeInfo = false);
41814188
Decl *ActOnSkippedFunctionBody(Decl *Decl);
41824189
void ActOnFinishInlineFunctionDef(FunctionDecl *D);
41834190

@@ -6874,23 +6881,23 @@ class Sema final : public SemaBase {
68746881
assert(!ExprEvalContexts.empty() &&
68756882
"Must be in an expression evaluation context");
68766883
return ExprEvalContexts.back();
6877-
};
6884+
}
68786885

68796886
ExpressionEvaluationContextRecord &currentEvaluationContext() {
68806887
assert(!ExprEvalContexts.empty() &&
68816888
"Must be in an expression evaluation context");
68826889
return ExprEvalContexts.back();
6883-
};
6890+
}
68846891

68856892
ExpressionEvaluationContextRecord &parentEvaluationContext() {
68866893
assert(ExprEvalContexts.size() >= 2 &&
68876894
"Must be in an expression evaluation context");
68886895
return ExprEvalContexts[ExprEvalContexts.size() - 2];
6889-
};
6896+
}
68906897

68916898
const ExpressionEvaluationContextRecord &parentEvaluationContext() const {
68926899
return const_cast<Sema *>(this)->parentEvaluationContext();
6893-
};
6900+
}
68946901

68956902
bool isAttrContext() const {
68966903
return ExprEvalContexts.back().ExprContext ==
@@ -9140,8 +9147,7 @@ class Sema final : public SemaBase {
91409147

91419148
/// Complete a lambda-expression having processed and attached the
91429149
/// lambda body.
9143-
ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
9144-
sema::LambdaScopeInfo *LSI);
9150+
ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc);
91459151

91469152
/// Get the return type to use for a lambda's conversion function(s) to
91479153
/// function pointer type, given the type of the call operator.

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16228,10 +16228,6 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
1622816228
return Decl;
1622916229
}
1623016230

16231-
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
16232-
return ActOnFinishFunctionBody(D, BodyArg, /*IsInstantiation=*/false);
16233-
}
16234-
1623516231
/// RAII object that pops an ExpressionEvaluationContext when exiting a function
1623616232
/// body.
1623716233
class ExitFunctionBodyRAII {
@@ -16302,8 +16298,8 @@ void Sema::CheckCoroutineWrapper(FunctionDecl *FD) {
1630216298
Diag(FD->getLocation(), diag::err_coroutine_return_type) << RD;
1630316299
}
1630416300

16305-
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
16306-
bool IsInstantiation) {
16301+
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
16302+
bool RetainFunctionScopeInfo) {
1630716303
FunctionScopeInfo *FSI = getCurFunction();
1630816304
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
1630916305

@@ -16760,7 +16756,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1676016756
if (!IsInstantiation)
1676116757
PopDeclContext();
1676216758

16763-
PopFunctionScopeInfo(ActivePolicy, dcl);
16759+
if (!RetainFunctionScopeInfo)
16760+
PopFunctionScopeInfo(ActivePolicy, dcl);
1676416761
// If any errors have occurred, clear out any temporaries that may have
1676516762
// been leftover. This ensures that these temporaries won't be picked up for
1676616763
// deletion in some later function.

clang/lib/Sema/SemaLambda.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,14 +1968,15 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
19681968
}
19691969

19701970
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body) {
1971-
LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
1971+
LambdaScopeInfo &LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
19721972

19731973
if (LSI.CallOperator->hasAttr<SYCLKernelEntryPointAttr>())
19741974
SYCL().CheckSYCLEntryPointFunctionDecl(LSI.CallOperator);
19751975

1976-
ActOnFinishFunctionBody(LSI.CallOperator, Body);
1976+
ActOnFinishFunctionBody(LSI.CallOperator, Body, /*IsInstantiation=*/false,
1977+
/*RetainFunctionScopeInfo=*/true);
19771978

1978-
return BuildLambdaExpr(StartLoc, Body->getEndLoc(), &LSI);
1979+
return BuildLambdaExpr(StartLoc, Body->getEndLoc());
19791980
}
19801981

19811982
static LambdaCaptureDefault
@@ -2132,8 +2133,9 @@ ConstructFixItRangeForUnusedCapture(Sema &S, SourceRange CaptureRange,
21322133
return SourceRange(FixItStart, FixItEnd);
21332134
}
21342135

2135-
ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
2136-
LambdaScopeInfo *LSI) {
2136+
ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc,
2137+
SourceLocation EndLoc) {
2138+
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(FunctionScopes.back());
21372139
// Collect information from the lambda scope.
21382140
SmallVector<LambdaCapture, 4> Captures;
21392141
SmallVector<Expr *, 4> CaptureInits;
@@ -2170,6 +2172,12 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
21702172

21712173
PopExpressionEvaluationContext();
21722174

2175+
sema::AnalysisBasedWarnings::Policy WP =
2176+
AnalysisWarnings.getPolicyInEffectAt(EndLoc);
2177+
// We cannot release LSI until we finish computing captures, which
2178+
// requires the scope to be popped.
2179+
PoppedFunctionScopePtr _ = PopFunctionScopeInfo(&WP, LSI->CallOperator);
2180+
21732181
// True if the current capture has a used capture or default before it.
21742182
bool CurHasPreviousCapture = CaptureDefault != LCD_None;
21752183
SourceLocation PrevCaptureLoc = CurHasPreviousCapture ?

clang/lib/Sema/TreeTransform.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4051,7 +4051,7 @@ class TreeTransform {
40514051
PVD->getUninstantiatedDefaultArg()
40524052
->containsUnexpandedParameterPack();
40534053
}
4054-
return getSema().BuildLambdaExpr(StartLoc, EndLoc, LSI);
4054+
return getSema().BuildLambdaExpr(StartLoc, EndLoc);
40554055
}
40564056

40574057
/// Build an empty C++1z fold-expression with the given operator.
@@ -15694,12 +15694,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1569415694
return ExprError();
1569515695
}
1569615696

15697-
// Copy the LSI before ActOnFinishFunctionBody removes it.
15698-
// FIXME: This is dumb. Store the lambda information somewhere that outlives
15699-
// the call operator.
15700-
auto LSICopy = *LSI;
1570115697
getSema().ActOnFinishFunctionBody(NewCallOperator, Body.get(),
15702-
/*IsInstantiation*/ true);
15698+
/*IsInstantiation=*/true,
15699+
/*RetainFunctionScopeInfo=*/true);
1570315700
SavedContext.pop();
1570415701

1570515702
// Recompute the dependency of the lambda so that we can defer the lambda call
@@ -15735,11 +15732,11 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1573515732
// *after* the substitution in case we can't decide the dependency
1573615733
// so early, e.g. because we want to see if any of the *substituted*
1573715734
// parameters are dependent.
15738-
DependencyKind = getDerived().ComputeLambdaDependency(&LSICopy);
15735+
DependencyKind = getDerived().ComputeLambdaDependency(LSI);
1573915736
Class->setLambdaDependencyKind(DependencyKind);
1574015737

1574115738
return getDerived().RebuildLambdaExpr(E->getBeginLoc(),
15742-
Body.get()->getEndLoc(), &LSICopy);
15739+
Body.get()->getEndLoc(), LSI);
1574315740
}
1574415741

1574515742
template<typename Derived>

clang/test/SemaCXX/cxx2b-consteval-propagate.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,3 +610,19 @@ namespace GH135281 {
610610
void (*ff)() = f2<B>; // expected-note {{instantiation of function template specialization}}
611611
}
612612
#endif
613+
614+
namespace GH145776 {
615+
616+
void runtime_only() {}
617+
consteval void comptime_only() {}
618+
619+
void fn() {
620+
[]() {
621+
runtime_only();
622+
[]() {
623+
&comptime_only;
624+
}();
625+
}();
626+
}
627+
628+
}

0 commit comments

Comments
 (0)