Skip to content

Commit 7676b24

Browse files
committed
Refactor PushExpressionEvaluationContext to avoid duplication
PushExpressionEvaluationContextForFunction sets a correct evaluation context for function, correctly dealing with discarded statements and immediate escalation.
1 parent 65f6611 commit 7676b24

File tree

6 files changed

+72
-49
lines changed

6 files changed

+72
-49
lines changed

clang/include/clang/Sema/EnterExpressionEvaluationContext.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ class EnterExpressionEvaluationContext {
6464
}
6565
};
6666

67+
/// RAII object that enters a new function expression evaluation context.
68+
class EnterExpressionEvaluationContextForFunction {
69+
Sema &Actions;
70+
71+
public:
72+
EnterExpressionEvaluationContextForFunction(
73+
Sema &Actions, Sema::ExpressionEvaluationContext NewContext,
74+
FunctionDecl *FD = nullptr)
75+
: Actions(Actions) {
76+
Actions.PushExpressionEvaluationContextForFunction(NewContext, FD);
77+
}
78+
~EnterExpressionEvaluationContextForFunction() {
79+
Actions.PopExpressionEvaluationContext();
80+
}
81+
};
82+
6783
} // namespace clang
6884

6985
#endif

clang/include/clang/Sema/Sema.h

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6916,6 +6916,10 @@ class Sema final : public SemaBase {
69166916
ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr,
69176917
ExpressionEvaluationContextRecord::ExpressionKind Type =
69186918
ExpressionEvaluationContextRecord::EK_Other);
6919+
6920+
void PushExpressionEvaluationContextForFunction(
6921+
ExpressionEvaluationContext NewContext, FunctionDecl *FD);
6922+
69196923
enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl };
69206924
void PushExpressionEvaluationContext(
69216925
ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t,
@@ -13372,23 +13376,11 @@ class Sema final : public SemaBase {
1337213376
: S(S), SavedContext(S, DC) {
1337313377
auto *FD = dyn_cast<FunctionDecl>(DC);
1337413378
S.PushFunctionScope();
13375-
S.PushExpressionEvaluationContext(
13376-
(FD && FD->isImmediateFunction())
13377-
? ExpressionEvaluationContext::ImmediateFunctionContext
13378-
: ExpressionEvaluationContext::PotentiallyEvaluated);
13379-
if (FD) {
13380-
auto &Current = S.currentEvaluationContext();
13381-
const auto &Parent = S.parentEvaluationContext();
13382-
13379+
S.PushExpressionEvaluationContextForFunction(
13380+
ExpressionEvaluationContext::PotentiallyEvaluated, FD);
13381+
if (FD)
1338313382
FD->setWillHaveBody(true);
13384-
Current.InImmediateFunctionContext =
13385-
FD->isImmediateFunction() ||
13386-
(isLambdaMethod(FD) && (Parent.isConstantEvaluated() ||
13387-
Parent.isImmediateFunctionContext()));
13388-
13389-
Current.InImmediateEscalatingFunctionContext =
13390-
S.getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
13391-
} else
13383+
else
1339213384
assert(isa<ObjCMethodDecl>(DC));
1339313385
}
1339413386

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -697,10 +697,9 @@ static void checkReturnStmtInCoroutine(Sema &S, FunctionScopeInfo *FSI) {
697697
bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
698698
StringRef Keyword) {
699699
// Ignore previous expr evaluation contexts.
700-
EnterExpressionEvaluationContext PotentiallyEvaluated(
701-
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
702-
703-
ExprEvalContexts.back().InDiscardedStatement = false;
700+
EnterExpressionEvaluationContextForFunction PotentiallyEvaluated(
701+
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
702+
dyn_cast_or_null<FunctionDecl>(CurContext));
704703

705704
if (!checkCoroutineContext(*this, KWLoc, Keyword))
706705
return false;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15866,27 +15866,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
1586615866
// Do not push if it is a lambda because one is already pushed when building
1586715867
// the lambda in ActOnStartOfLambdaDefinition().
1586815868
if (!isLambdaCallOperator(FD))
15869-
// [expr.const]/p14.1
15870-
// An expression or conversion is in an immediate function context if it is
15871-
// potentially evaluated and either: its innermost enclosing non-block scope
15872-
// is a function parameter scope of an immediate function.
15873-
PushExpressionEvaluationContext(
15874-
FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext
15875-
: ExprEvalContexts.back().Context);
15876-
15877-
// Each ExpressionEvaluationContextRecord also keeps track of whether the
15878-
// context is nested in an immediate function context, so smaller contexts
15879-
// that appear inside immediate functions (like variable initializers) are
15880-
// considered to be inside an immediate function context even though by
15881-
// themselves they are not immediate function contexts. But when a new
15882-
// function is entered, we need to reset this tracking, since the entered
15883-
// function might be not an immediate function.
15884-
ExprEvalContexts.back().InImmediateFunctionContext = FD->isConsteval();
15885-
ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
15886-
getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
15887-
15888-
// A function that is not a lambda is never in a discarded statement
15889-
ExprEvalContexts.back().InDiscardedStatement = false;
15869+
PushExpressionEvaluationContextForFunction(ExprEvalContexts.back().Context,
15870+
FD);
1589015871

1589115872
// Check for defining attributes before the check for redefinition.
1589215873
if (const auto *Attr = FD->getAttr<AliasAttr>()) {

clang/lib/Sema/SemaExpr.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17749,6 +17749,47 @@ Sema::PushExpressionEvaluationContext(
1774917749
PushExpressionEvaluationContext(NewContext, ClosureContextDecl, ExprContext);
1775017750
}
1775117751

17752+
void Sema::PushExpressionEvaluationContextForFunction(
17753+
ExpressionEvaluationContext NewContext, FunctionDecl *FD) {
17754+
// [expr.const]/p14.1
17755+
// An expression or conversion is in an immediate function context if it is
17756+
// potentially evaluated and either: its innermost enclosing non-block scope
17757+
// is a function parameter scope of an immediate function.
17758+
PushExpressionEvaluationContext(
17759+
FD && FD->isConsteval()
17760+
? ExpressionEvaluationContext::ImmediateFunctionContext
17761+
: NewContext);
17762+
const Sema::ExpressionEvaluationContextRecord &Parent =
17763+
parentEvaluationContext();
17764+
Sema::ExpressionEvaluationContextRecord &Current = currentEvaluationContext();
17765+
17766+
Current.InDiscardedStatement = false;
17767+
17768+
if (FD) {
17769+
17770+
// Each ExpressionEvaluationContextRecord also keeps track of whether the
17771+
// context is nested in an immediate function context, so smaller contexts
17772+
// that appear inside immediate functions (like variable initializers) are
17773+
// considered to be inside an immediate function context even though by
17774+
// themselves they are not immediate function contexts. But when a new
17775+
// function is entered, we need to reset this tracking, since the entered
17776+
// function might be not an immediate function.
17777+
17778+
Current.InImmediateEscalatingFunctionContext =
17779+
getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
17780+
17781+
if (isLambdaMethod(FD)) {
17782+
Current.InDiscardedStatement = Parent.isDiscardedStatementContext();
17783+
Current.InImmediateFunctionContext =
17784+
FD->isConsteval() ||
17785+
(isLambdaMethod(FD) && (Parent.isConstantEvaluated() ||
17786+
Parent.isImmediateFunctionContext()));
17787+
} else {
17788+
Current.InImmediateFunctionContext = FD->isConsteval();
17789+
}
17790+
}
17791+
}
17792+
1775217793
namespace {
1775317794

1775417795
const DeclRefExpr *CheckPossibleDeref(Sema &S, const Expr *PossibleDeref) {

clang/lib/Sema/SemaLambda.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,14 +1574,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
15741574

15751575
// Enter a new evaluation context to insulate the lambda from any
15761576
// cleanups from the enclosing full-expression.
1577-
PushExpressionEvaluationContext(
1578-
LSI->CallOperator->isConsteval()
1579-
? ExpressionEvaluationContext::ImmediateFunctionContext
1580-
: ExpressionEvaluationContext::PotentiallyEvaluated);
1581-
ExprEvalContexts.back().InImmediateFunctionContext =
1582-
LSI->CallOperator->isConsteval();
1583-
ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
1584-
getLangOpts().CPlusPlus20 && LSI->CallOperator->isImmediateEscalating();
1577+
PushExpressionEvaluationContextForFunction(
1578+
ExpressionEvaluationContext::PotentiallyEvaluated, LSI->CallOperator);
15851579
}
15861580

15871581
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,

0 commit comments

Comments
 (0)