Skip to content

Commit 5f9630b

Browse files
authored
[Clang] Reapply "Only remove lambda scope after computing evaluation context" (#154458)
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. The last attempt destroyed LSI at the end of the block scope, after which we still need it in DiagnoseShadowingLambdaDecls. This also converts the wrapper function to default arguments as a drive-by fix, as well as does some cleanup. Fixes #145776
1 parent 46e77eb commit 5f9630b

File tree

6 files changed

+171
-160
lines changed

6 files changed

+171
-160
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ Bug Fixes to C++ Support
227227
- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665)
228228
- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293)
229229
- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
230+
- Fixed a mismatched lambda scope bug when propagating up ``consteval`` within nested lambdas. (#GH145776)
230231
- Fix an assertion failure when expression in assumption attribute
231232
(``[[assume(expr)]]``) creates temporary objects.
232233
- 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
@@ -16224,10 +16224,6 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
1622416224
return Decl;
1622516225
}
1622616226

16227-
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
16228-
return ActOnFinishFunctionBody(D, BodyArg, /*IsInstantiation=*/false);
16229-
}
16230-
1623116227
/// RAII object that pops an ExpressionEvaluationContext when exiting a function
1623216228
/// body.
1623316229
class ExitFunctionBodyRAII {
@@ -16298,8 +16294,8 @@ void Sema::CheckCoroutineWrapper(FunctionDecl *FD) {
1629816294
Diag(FD->getLocation(), diag::err_coroutine_return_type) << RD;
1629916295
}
1630016296

16301-
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
16302-
bool IsInstantiation) {
16297+
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
16298+
bool RetainFunctionScopeInfo) {
1630316299
FunctionScopeInfo *FSI = getCurFunction();
1630416300
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
1630516301

@@ -16756,7 +16752,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1675616752
if (!IsInstantiation)
1675716753
PopDeclContext();
1675816754

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

clang/lib/Sema/SemaLambda.cpp

Lines changed: 131 additions & 137 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,156 +2133,149 @@ 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;
21402142
SourceLocation CaptureDefaultLoc = LSI->CaptureDefaultLoc;
21412143
LambdaCaptureDefault CaptureDefault =
21422144
mapImplicitCaptureStyle(LSI->ImpCaptureStyle);
2143-
CXXRecordDecl *Class;
2144-
CXXMethodDecl *CallOperator;
2145-
SourceRange IntroducerRange;
2146-
bool ExplicitParams;
2147-
bool ExplicitResultType;
2148-
CleanupInfo LambdaCleanup;
2149-
bool ContainsUnexpandedParameterPack;
2150-
bool IsGenericLambda;
2151-
{
2152-
CallOperator = LSI->CallOperator;
2153-
Class = LSI->Lambda;
2154-
IntroducerRange = LSI->IntroducerRange;
2155-
ExplicitParams = LSI->ExplicitParams;
2156-
ExplicitResultType = !LSI->HasImplicitReturnType;
2157-
LambdaCleanup = LSI->Cleanup;
2158-
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
2159-
IsGenericLambda = Class->isGenericLambda();
2160-
2161-
CallOperator->setLexicalDeclContext(Class);
2162-
Decl *TemplateOrNonTemplateCallOperatorDecl =
2163-
CallOperator->getDescribedFunctionTemplate()
2164-
? CallOperator->getDescribedFunctionTemplate()
2165-
: cast<Decl>(CallOperator);
2166-
2167-
// FIXME: Is this really the best choice? Keeping the lexical decl context
2168-
// set as CurContext seems more faithful to the source.
2169-
TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
2170-
2171-
PopExpressionEvaluationContext();
2172-
2173-
// True if the current capture has a used capture or default before it.
2174-
bool CurHasPreviousCapture = CaptureDefault != LCD_None;
2175-
SourceLocation PrevCaptureLoc = CurHasPreviousCapture ?
2176-
CaptureDefaultLoc : IntroducerRange.getBegin();
2177-
2178-
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
2179-
const Capture &From = LSI->Captures[I];
2180-
2181-
if (From.isInvalid())
2182-
return ExprError();
2183-
2184-
assert(!From.isBlockCapture() && "Cannot capture __block variables");
2185-
bool IsImplicit = I >= LSI->NumExplicitCaptures;
2186-
SourceLocation ImplicitCaptureLoc =
2187-
IsImplicit ? CaptureDefaultLoc : SourceLocation();
2188-
2189-
// Use source ranges of explicit captures for fixits where available.
2190-
SourceRange CaptureRange = LSI->ExplicitCaptureRanges[I];
2191-
2192-
// Warn about unused explicit captures.
2193-
bool IsCaptureUsed = true;
2194-
if (!CurContext->isDependentContext() && !IsImplicit &&
2195-
!From.isODRUsed()) {
2196-
// Initialized captures that are non-ODR used may not be eliminated.
2197-
// FIXME: Where did the IsGenericLambda here come from?
2198-
bool NonODRUsedInitCapture =
2199-
IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
2200-
if (!NonODRUsedInitCapture) {
2201-
bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
2202-
SourceRange FixItRange = ConstructFixItRangeForUnusedCapture(
2203-
*this, CaptureRange, PrevCaptureLoc, CurHasPreviousCapture,
2204-
IsLast);
2205-
IsCaptureUsed =
2206-
!DiagnoseUnusedLambdaCapture(CaptureRange, FixItRange, From);
2207-
}
2208-
}
2145+
CXXRecordDecl *Class = LSI->Lambda;
2146+
CXXMethodDecl *CallOperator = LSI->CallOperator;
2147+
SourceRange IntroducerRange = LSI->IntroducerRange;
2148+
bool ExplicitParams = LSI->ExplicitParams;
2149+
bool ExplicitResultType = !LSI->HasImplicitReturnType;
2150+
CleanupInfo LambdaCleanup = LSI->Cleanup;
2151+
bool ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
2152+
bool IsGenericLambda = Class->isGenericLambda();
2153+
2154+
CallOperator->setLexicalDeclContext(Class);
2155+
Decl *TemplateOrNonTemplateCallOperatorDecl =
2156+
CallOperator->getDescribedFunctionTemplate()
2157+
? CallOperator->getDescribedFunctionTemplate()
2158+
: cast<Decl>(CallOperator);
2159+
2160+
// FIXME: Is this really the best choice? Keeping the lexical decl context
2161+
// set as CurContext seems more faithful to the source.
2162+
TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
22092163

2210-
if (CaptureRange.isValid()) {
2211-
CurHasPreviousCapture |= IsCaptureUsed;
2212-
PrevCaptureLoc = CaptureRange.getEnd();
2164+
PopExpressionEvaluationContext();
2165+
2166+
sema::AnalysisBasedWarnings::Policy WP =
2167+
AnalysisWarnings.getPolicyInEffectAt(EndLoc);
2168+
// We cannot release LSI until we finish computing captures, which
2169+
// requires the scope to be popped.
2170+
Sema::PoppedFunctionScopePtr _ = PopFunctionScopeInfo(&WP, LSI->CallOperator);
2171+
2172+
// True if the current capture has a used capture or default before it.
2173+
bool CurHasPreviousCapture = CaptureDefault != LCD_None;
2174+
SourceLocation PrevCaptureLoc =
2175+
CurHasPreviousCapture ? CaptureDefaultLoc : IntroducerRange.getBegin();
2176+
2177+
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
2178+
const Capture &From = LSI->Captures[I];
2179+
2180+
if (From.isInvalid())
2181+
return ExprError();
2182+
2183+
assert(!From.isBlockCapture() && "Cannot capture __block variables");
2184+
bool IsImplicit = I >= LSI->NumExplicitCaptures;
2185+
SourceLocation ImplicitCaptureLoc =
2186+
IsImplicit ? CaptureDefaultLoc : SourceLocation();
2187+
2188+
// Use source ranges of explicit captures for fixits where available.
2189+
SourceRange CaptureRange = LSI->ExplicitCaptureRanges[I];
2190+
2191+
// Warn about unused explicit captures.
2192+
bool IsCaptureUsed = true;
2193+
if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
2194+
// Initialized captures that are non-ODR used may not be eliminated.
2195+
// FIXME: Where did the IsGenericLambda here come from?
2196+
bool NonODRUsedInitCapture =
2197+
IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
2198+
if (!NonODRUsedInitCapture) {
2199+
bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
2200+
SourceRange FixItRange = ConstructFixItRangeForUnusedCapture(
2201+
*this, CaptureRange, PrevCaptureLoc, CurHasPreviousCapture, IsLast);
2202+
IsCaptureUsed =
2203+
!DiagnoseUnusedLambdaCapture(CaptureRange, FixItRange, From);
22132204
}
2205+
}
22142206

2215-
// Map the capture to our AST representation.
2216-
LambdaCapture Capture = [&] {
2217-
if (From.isThisCapture()) {
2218-
// Capturing 'this' implicitly with a default of '[=]' is deprecated,
2219-
// because it results in a reference capture. Don't warn prior to
2220-
// C++2a; there's nothing that can be done about it before then.
2221-
if (getLangOpts().CPlusPlus20 && IsImplicit &&
2222-
CaptureDefault == LCD_ByCopy) {
2223-
Diag(From.getLocation(), diag::warn_deprecated_this_capture);
2224-
Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture)
2225-
<< FixItHint::CreateInsertion(
2226-
getLocForEndOfToken(CaptureDefaultLoc), ", this");
2227-
}
2228-
return LambdaCapture(From.getLocation(), IsImplicit,
2229-
From.isCopyCapture() ? LCK_StarThis : LCK_This);
2230-
} else if (From.isVLATypeCapture()) {
2231-
return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
2232-
} else {
2233-
assert(From.isVariableCapture() && "unknown kind of capture");
2234-
ValueDecl *Var = From.getVariable();
2235-
LambdaCaptureKind Kind =
2236-
From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
2237-
return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
2238-
From.getEllipsisLoc());
2239-
}
2240-
}();
2207+
if (CaptureRange.isValid()) {
2208+
CurHasPreviousCapture |= IsCaptureUsed;
2209+
PrevCaptureLoc = CaptureRange.getEnd();
2210+
}
22412211

2242-
// Form the initializer for the capture field.
2243-
ExprResult Init = BuildCaptureInit(From, ImplicitCaptureLoc);
2212+
// Map the capture to our AST representation.
2213+
LambdaCapture Capture = [&] {
2214+
if (From.isThisCapture()) {
2215+
// Capturing 'this' implicitly with a default of '[=]' is deprecated,
2216+
// because it results in a reference capture. Don't warn prior to
2217+
// C++2a; there's nothing that can be done about it before then.
2218+
if (getLangOpts().CPlusPlus20 && IsImplicit &&
2219+
CaptureDefault == LCD_ByCopy) {
2220+
Diag(From.getLocation(), diag::warn_deprecated_this_capture);
2221+
Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture)
2222+
<< FixItHint::CreateInsertion(
2223+
getLocForEndOfToken(CaptureDefaultLoc), ", this");
2224+
}
2225+
return LambdaCapture(From.getLocation(), IsImplicit,
2226+
From.isCopyCapture() ? LCK_StarThis : LCK_This);
2227+
} else if (From.isVLATypeCapture()) {
2228+
return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
2229+
} else {
2230+
assert(From.isVariableCapture() && "unknown kind of capture");
2231+
ValueDecl *Var = From.getVariable();
2232+
LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
2233+
return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
2234+
From.getEllipsisLoc());
2235+
}
2236+
}();
22442237

2245-
// FIXME: Skip this capture if the capture is not used, the initializer
2246-
// has no side-effects, the type of the capture is trivial, and the
2247-
// lambda is not externally visible.
2238+
// Form the initializer for the capture field.
2239+
ExprResult Init = BuildCaptureInit(From, ImplicitCaptureLoc);
22482240

2249-
// Add a FieldDecl for the capture and form its initializer.
2250-
BuildCaptureField(Class, From);
2251-
Captures.push_back(Capture);
2252-
CaptureInits.push_back(Init.get());
2241+
// FIXME: Skip this capture if the capture is not used, the initializer
2242+
// has no side-effects, the type of the capture is trivial, and the
2243+
// lambda is not externally visible.
22532244

2254-
if (LangOpts.CUDA)
2255-
CUDA().CheckLambdaCapture(CallOperator, From);
2256-
}
2245+
// Add a FieldDecl for the capture and form its initializer.
2246+
BuildCaptureField(Class, From);
2247+
Captures.push_back(Capture);
2248+
CaptureInits.push_back(Init.get());
22572249

2258-
Class->setCaptures(Context, Captures);
2259-
2260-
// C++11 [expr.prim.lambda]p6:
2261-
// The closure type for a lambda-expression with no lambda-capture
2262-
// has a public non-virtual non-explicit const conversion function
2263-
// to pointer to function having the same parameter and return
2264-
// types as the closure type's function call operator.
2265-
if (Captures.empty() && CaptureDefault == LCD_None)
2266-
addFunctionPointerConversions(*this, IntroducerRange, Class,
2267-
CallOperator);
2268-
2269-
// Objective-C++:
2270-
// The closure type for a lambda-expression has a public non-virtual
2271-
// non-explicit const conversion function to a block pointer having the
2272-
// same parameter and return types as the closure type's function call
2273-
// operator.
2274-
// FIXME: Fix generic lambda to block conversions.
2275-
if (getLangOpts().Blocks && getLangOpts().ObjC && !IsGenericLambda)
2276-
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
2277-
2278-
// Finalize the lambda class.
2279-
SmallVector<Decl*, 4> Fields(Class->fields());
2280-
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
2281-
SourceLocation(), ParsedAttributesView());
2282-
CheckCompletedCXXClass(nullptr, Class);
2250+
if (LangOpts.CUDA)
2251+
CUDA().CheckLambdaCapture(CallOperator, From);
22832252
}
22842253

2254+
Class->setCaptures(Context, Captures);
2255+
2256+
// C++11 [expr.prim.lambda]p6:
2257+
// The closure type for a lambda-expression with no lambda-capture
2258+
// has a public non-virtual non-explicit const conversion function
2259+
// to pointer to function having the same parameter and return
2260+
// types as the closure type's function call operator.
2261+
if (Captures.empty() && CaptureDefault == LCD_None)
2262+
addFunctionPointerConversions(*this, IntroducerRange, Class, CallOperator);
2263+
2264+
// Objective-C++:
2265+
// The closure type for a lambda-expression has a public non-virtual
2266+
// non-explicit const conversion function to a block pointer having the
2267+
// same parameter and return types as the closure type's function call
2268+
// operator.
2269+
// FIXME: Fix generic lambda to block conversions.
2270+
if (getLangOpts().Blocks && getLangOpts().ObjC && !IsGenericLambda)
2271+
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
2272+
2273+
// Finalize the lambda class.
2274+
SmallVector<Decl *, 4> Fields(Class->fields());
2275+
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
2276+
SourceLocation(), ParsedAttributesView());
2277+
CheckCompletedCXXClass(nullptr, Class);
2278+
22852279
Cleanup.mergeFrom(LambdaCleanup);
22862280

22872281
LambdaExpr *Lambda =

0 commit comments

Comments
 (0)