Skip to content

Commit 491b281

Browse files
committed
[clang][SemaCXX] Diagnose tautological uses of consteval if and is_constant_evaluated
This patch makes clang diagnose extensive cases of consteval if and is_constant_evaluated usage that are tautologically true or false. This introduces a new IsRuntimeEvaluated boolean flag to Sema::ExpressionEvaluationContextRecord that means the immediate appearance of if consteval or is_constant_evaluated are tautologically false(e.g. inside if !consteval {} block or non-constexpr-qualified function definition body) This patch also pushes new expression evaluation context when parsing the condition of if constexpr and initializer of constexpr variables so that Sema can be aware that the use of consteval if and is_consteval are tautologically true in if constexpr condition and constexpr variable initializers. BEFORE this patch, the warning for is_constant_evaluated was emitted from constant evaluator. This patch moves the warning logic to Sema in order to diagnose tautological use of is_constant_evaluated in the same way as consteval if. This patch separates initializer evaluation context from InitializerScopeRAII. This fixes a bug that was happening when user takes address of function address in initializers of non-local variables. Fixes #43760 Fixes #51567 Reviewed By: cor3ntin, ldionne Differential Revision: https://reviews.llvm.org/D155064
1 parent 7d495d6 commit 491b281

40 files changed

+638
-163
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,12 @@ Improvements to Clang's diagnostics
206206
- Clang no longer emits irrelevant notes about unsatisfied constraint expressions
207207
on the left-hand side of ``||`` when the right-hand side constraint is satisfied.
208208
(`#54678: <https://github.com/llvm/llvm-project/issues/54678>`_).
209+
- Clang now diagnoses wider cases of tautological use of consteval if or
210+
``std::is_constant_evaluated``. This also suppresses some false positives.
211+
(`#43760: <https://github.com/llvm/llvm-project/issues/43760>`_)
212+
(`#51567: <https://github.com/llvm/llvm-project/issues/51567>`_)
213+
- Clang now diagnoses narrowing implicit conversions on variable initializers in immediate
214+
function context and on constexpr variable template initializers.
209215

210216
Bug Fixes in This Version
211217
-------------------------

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,6 @@ def warn_constexpr_unscoped_enum_out_of_range : Warning<
413413
def note_unimplemented_constexpr_lambda_feature_ast : Note<
414414
"unimplemented constexpr lambda feature: %0 (coming soon!)">;
415415

416-
def warn_is_constant_evaluated_always_true_constexpr : Warning<
417-
"'%0' will always evaluate to 'true' in a manifestly constant-evaluated expression">,
418-
InGroup<DiagGroup<"constant-evaluated">>;
419-
420416
// inline asm related.
421417
let CategoryName = "Inline Assembly Issue" in {
422418
def err_asm_invalid_escape : Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,8 +1591,8 @@ def err_static_assert_message_constexpr : Error<
15911591
"the message in a static assertion must be produced by a "
15921592
"constant expression">;
15931593

1594-
def warn_consteval_if_always_true : Warning<
1595-
"consteval if is always true in an %select{unevaluated|immediate}0 context">,
1594+
def warn_tautological_consteval_if : Warning<
1595+
"consteval if is always %select{true|false}0 in this context">,
15961596
InGroup<DiagGroup<"redundant-consteval-if">>;
15971597

15981598
def ext_inline_variable : ExtWarn<
@@ -8897,6 +8897,9 @@ def warn_side_effects_unevaluated_context : Warning<
88978897
def warn_side_effects_typeid : Warning<
88988898
"expression with side effects will be evaluated despite being used as an "
88998899
"operand to 'typeid'">, InGroup<PotentiallyEvaluatedExpression>;
8900+
def warn_tautological_is_constant_evaluated : Warning<
8901+
"'%select{std::is_constant_evaluated|__builtin_is_constant_evaluated}0' will always evaluate to %select{false|true}1 in this context">,
8902+
InGroup<DiagGroup<"constant-evaluated">>;
89008903
def warn_unused_result : Warning<
89018904
"ignoring return value of function declared with %0 attribute">,
89028905
InGroup<UnusedResult>;

clang/include/clang/Parse/Parser.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,12 +2003,10 @@ class Parser : public CodeCompletionHandler {
20032003
//===--------------------------------------------------------------------===//
20042004
// C++ if/switch/while/for condition expression.
20052005
struct ForRangeInfo;
2006-
Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt,
2007-
SourceLocation Loc,
2008-
Sema::ConditionKind CK,
2009-
bool MissingOK,
2010-
ForRangeInfo *FRI = nullptr,
2011-
bool EnterForConditionScope = false);
2006+
Sema::ConditionResult ParseCXXCondition(
2007+
StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK,
2008+
bool MissingOK, ForRangeInfo *FRI = nullptr,
2009+
bool EnterForConditionScope = false, SourceLocation ConstexprLoc = {});
20122010
DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
20132011
ParsedAttributes &Attrs);
20142012

@@ -2106,7 +2104,8 @@ class Parser : public CodeCompletionHandler {
21062104
Sema::ConditionResult &CondResult,
21072105
SourceLocation Loc, Sema::ConditionKind CK,
21082106
SourceLocation &LParenLoc,
2109-
SourceLocation &RParenLoc);
2107+
SourceLocation &RParenLoc,
2108+
SourceLocation ConstexprLoc = {});
21102109
StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
21112110
StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
21122111
StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);

clang/include/clang/Sema/Sema.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,9 @@ class Sema final {
13581358
bool InDiscardedStatement;
13591359
bool InImmediateFunctionContext;
13601360
bool InImmediateEscalatingFunctionContext;
1361+
// The immediate occurances of consteval if or std::is_constant_evaluated()
1362+
// are tautologically false
1363+
bool IsRuntimeEvaluated;
13611364

13621365
bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false;
13631366

@@ -1387,7 +1390,8 @@ class Sema final {
13871390
NumCleanupObjects(NumCleanupObjects), NumTypos(0),
13881391
ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext),
13891392
InDiscardedStatement(false), InImmediateFunctionContext(false),
1390-
InImmediateEscalatingFunctionContext(false) {}
1393+
InImmediateEscalatingFunctionContext(false),
1394+
IsRuntimeEvaluated(false) {}
13911395

13921396
bool isUnevaluated() const {
13931397
return Context == ExpressionEvaluationContext::Unevaluated ||
@@ -1426,6 +1430,10 @@ class Sema final {
14261430
/// A stack of expression evaluation contexts.
14271431
SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
14281432

1433+
/// Source location of the start of `constexpr` in constexpr-if
1434+
/// used for diagnostics
1435+
SourceLocation ConstexprIfLoc;
1436+
14291437
// Set of failed immediate invocations to avoid double diagnosing.
14301438
llvm::SmallPtrSet<ConstantExpr *, 4> FailedImmediateInvocations;
14311439

clang/lib/AST/ExprConstant.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12178,22 +12178,6 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1217812178
}
1217912179

1218012180
case Builtin::BI__builtin_is_constant_evaluated: {
12181-
const auto *Callee = Info.CurrentCall->getCallee();
12182-
if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression &&
12183-
(Info.CallStackDepth == 1 ||
12184-
(Info.CallStackDepth == 2 && Callee->isInStdNamespace() &&
12185-
Callee->getIdentifier() &&
12186-
Callee->getIdentifier()->isStr("is_constant_evaluated")))) {
12187-
// FIXME: Find a better way to avoid duplicated diagnostics.
12188-
if (Info.EvalStatus.Diag)
12189-
Info.report((Info.CallStackDepth == 1)
12190-
? E->getExprLoc()
12191-
: Info.CurrentCall->getCallRange().getBegin(),
12192-
diag::warn_is_constant_evaluated_always_true_constexpr)
12193-
<< (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated"
12194-
: "std::is_constant_evaluated");
12195-
}
12196-
1219712181
return Success(Info.InConstantContext, E);
1219812182
}
1219912183

clang/lib/Parse/ParseDecl.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2461,6 +2461,15 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
24612461
return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
24622462
}
24632463

2464+
/// Determine whether the given declaration is a global variable or
2465+
/// static data member.
2466+
static bool isNonlocalVariable(const Decl *D) {
2467+
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
2468+
return Var->hasGlobalStorage();
2469+
2470+
return false;
2471+
}
2472+
24642473
Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
24652474
Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
24662475
// RAII type used to track whether we're inside an initializer.
@@ -2493,6 +2502,36 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
24932502
ThisDecl = nullptr;
24942503
}
24952504
};
2505+
struct EnterInitializerExpressionEvaluationContext {
2506+
Sema &S;
2507+
bool Entered;
2508+
2509+
EnterInitializerExpressionEvaluationContext(Sema &S, Declarator &D,
2510+
Decl *ThisDecl)
2511+
: S(S), Entered(false) {
2512+
if (ThisDecl && S.getLangOpts().CPlusPlus && !ThisDecl->isInvalidDecl()) {
2513+
Entered = true;
2514+
bool RuntimeEvaluated = S.ExprEvalContexts.back().IsRuntimeEvaluated;
2515+
Sema::ExpressionEvaluationContext NewEEC =
2516+
S.ExprEvalContexts.back().Context;
2517+
if ((D.getDeclSpec().getTypeQualifiers() == DeclSpec::TQ_const ||
2518+
isNonlocalVariable(ThisDecl)) &&
2519+
S.ExprEvalContexts.back().IsRuntimeEvaluated) {
2520+
RuntimeEvaluated = false;
2521+
}
2522+
if (D.getDeclSpec().hasConstexprSpecifier()) {
2523+
NewEEC = Sema::ExpressionEvaluationContext::ConstantEvaluated;
2524+
RuntimeEvaluated = false;
2525+
}
2526+
S.PushExpressionEvaluationContext(NewEEC, ThisDecl);
2527+
S.ExprEvalContexts.back().IsRuntimeEvaluated = RuntimeEvaluated;
2528+
}
2529+
}
2530+
~EnterInitializerExpressionEvaluationContext() {
2531+
if (Entered)
2532+
S.PopExpressionEvaluationContext();
2533+
}
2534+
};
24962535

24972536
enum class InitKind { Uninitialized, Equal, CXXDirect, CXXBraced };
24982537
InitKind TheInitKind;
@@ -2592,6 +2631,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
25922631
<< getLangOpts().CPlusPlus20;
25932632
} else {
25942633
InitializerScopeRAII InitScope(*this, D, ThisDecl);
2634+
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
25952635

25962636
if (Tok.is(tok::code_completion)) {
25972637
cutOffParsing();
@@ -2639,6 +2679,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
26392679
ExprVector Exprs;
26402680

26412681
InitializerScopeRAII InitScope(*this, D, ThisDecl);
2682+
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
26422683

26432684
auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
26442685
auto RunSignatureHelp = [&]() {
@@ -2689,6 +2730,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
26892730
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
26902731

26912732
InitializerScopeRAII InitScope(*this, D, ThisDecl);
2733+
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
26922734

26932735
PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
26942736
ExprResult Init(ParseBraceInitializer());

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3234,9 +3234,14 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
32343234

32353235
bool IsFieldInitialization = isa_and_present<FieldDecl>(D);
32363236

3237+
bool IsConstexpr = false;
3238+
if (const auto *VD = dyn_cast_if_present<VarDecl>(D))
3239+
IsConstexpr = VD->isConstexpr();
3240+
32373241
EnterExpressionEvaluationContext Context(
32383242
Actions,
3239-
IsFieldInitialization
3243+
IsConstexpr ? Sema::ExpressionEvaluationContext::ConstantEvaluated
3244+
: IsFieldInitialization
32403245
? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
32413246
: Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
32423247
D);

clang/lib/Parse/ParseExpr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,6 +2093,13 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
20932093
};
20942094
if (OpKind == tok::l_paren || !LHS.isInvalid()) {
20952095
if (Tok.isNot(tok::r_paren)) {
2096+
// FIXME: arguments in consteval functions are constant expression
2097+
// regardless of the evaluation context of callsite. However, we
2098+
// cannot know whether the called function is constevasl before the
2099+
// declaration is resolved.
2100+
bool IsRuntimeEvaluated =
2101+
Actions.ExprEvalContexts.back().IsRuntimeEvaluated;
2102+
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = false;
20962103
if (ParseExpressionList(ArgExprs, [&] {
20972104
PreferredType.enterFunctionArgument(Tok.getLocation(),
20982105
RunSignatureHelp);
@@ -2109,6 +2116,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
21092116
for (auto &E : ArgExprs)
21102117
Actions.CorrectDelayedTyposInExpr(E);
21112118
}
2119+
Actions.ExprEvalContexts.back().IsRuntimeEvaluated =
2120+
IsRuntimeEvaluated;
21122121
}
21132122
}
21142123

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,8 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
20412041
Sema::ConditionResult
20422042
Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
20432043
Sema::ConditionKind CK, bool MissingOK,
2044-
ForRangeInfo *FRI, bool EnterForConditionScope) {
2044+
ForRangeInfo *FRI, bool EnterForConditionScope,
2045+
SourceLocation ConstexprLoc) {
20452046
// Helper to ensure we always enter a continue/break scope if requested.
20462047
struct ForConditionScopeRAII {
20472048
Scope *S;
@@ -2098,9 +2099,28 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
20982099
*InitStmt = Actions.ActOnNullStmt(SemiLoc);
20992100
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
21002101
}
2102+
bool InitStmtIsExprStmt = false;
2103+
if (InitStmt) {
2104+
RevertingTentativeParsingAction PA(*this);
2105+
SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
2106+
InitStmtIsExprStmt = Tok.is(tok::semi);
2107+
}
21012108

2102-
// Parse the expression.
2103-
ExprResult Expr = ParseExpression(); // expression
2109+
ExprResult Expr; // expression
2110+
{
2111+
EnterExpressionEvaluationContext Consteval(
2112+
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
2113+
/*LambdaContextDecl=*/nullptr,
2114+
Sema::ExpressionEvaluationContextRecord::EK_Other,
2115+
/*ShouldEnter=*/CK == Sema::ConditionKind::ConstexprIf &&
2116+
!InitStmtIsExprStmt);
2117+
SourceLocation OuterConstexprIfLoc = Actions.ConstexprIfLoc;
2118+
Actions.ConstexprIfLoc = ConstexprLoc;
2119+
2120+
// Parse the expression.
2121+
Expr = ParseExpression(); // expression
2122+
Actions.ConstexprIfLoc = OuterConstexprIfLoc;
2123+
}
21042124
if (Expr.isInvalid())
21052125
return Sema::ConditionError();
21062126

@@ -2188,6 +2208,21 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
21882208
if (CopyInitialization)
21892209
ConsumeToken();
21902210

2211+
Sema::ExpressionEvaluationContext NewEEC =
2212+
Actions.ExprEvalContexts.back().Context;
2213+
bool RuntimeEvaluated = Actions.ExprEvalContexts.back().IsRuntimeEvaluated;
2214+
if (DS.getTypeQualifiers() == DeclSpec::TQ_const)
2215+
RuntimeEvaluated = false;
2216+
2217+
if (CK == Sema::ConditionKind::ConstexprIf || DS.hasConstexprSpecifier()) {
2218+
RuntimeEvaluated = false;
2219+
NewEEC = Sema::ExpressionEvaluationContext::ConstantEvaluated;
2220+
}
2221+
EnterExpressionEvaluationContext Initializer(Actions, NewEEC, DeclOut);
2222+
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = RuntimeEvaluated;
2223+
SourceLocation OuterConstexprIfLoc = Actions.ConstexprIfLoc;
2224+
Actions.ConstexprIfLoc = ConstexprLoc;
2225+
21912226
ExprResult InitExpr = ExprError();
21922227
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
21932228
Diag(Tok.getLocation(),
@@ -2214,6 +2249,7 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
22142249
Actions.ActOnInitializerError(DeclOut);
22152250

22162251
Actions.FinalizeDeclaration(DeclOut);
2252+
Actions.ConstexprIfLoc = OuterConstexprIfLoc;
22172253
return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
22182254
}
22192255

clang/lib/Parse/ParseStmt.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,18 +1293,17 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
12931293
/// errors in the condition.
12941294
/// Additionally, it will assign the location of the outer-most '(' and ')',
12951295
/// to LParenLoc and RParenLoc, respectively.
1296-
bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
1297-
Sema::ConditionResult &Cond,
1298-
SourceLocation Loc,
1299-
Sema::ConditionKind CK,
1300-
SourceLocation &LParenLoc,
1301-
SourceLocation &RParenLoc) {
1296+
bool Parser::ParseParenExprOrCondition(
1297+
StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc,
1298+
Sema::ConditionKind CK, SourceLocation &LParenLoc,
1299+
SourceLocation &RParenLoc, SourceLocation ConstexprLoc) {
13021300
BalancedDelimiterTracker T(*this, tok::l_paren);
13031301
T.consumeOpen();
13041302
SourceLocation Start = Tok.getLocation();
13051303

13061304
if (getLangOpts().CPlusPlus) {
1307-
Cond = ParseCXXCondition(InitStmt, Loc, CK, false);
1305+
Cond = ParseCXXCondition(InitStmt, Loc, CK, false, nullptr, false,
1306+
ConstexprLoc);
13081307
} else {
13091308
ExprResult CondExpr = ParseExpression();
13101309

@@ -1464,12 +1463,13 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
14641463
bool IsConsteval = false;
14651464
SourceLocation NotLocation;
14661465
SourceLocation ConstevalLoc;
1466+
SourceLocation ConstexprLoc;
14671467

14681468
if (Tok.is(tok::kw_constexpr)) {
14691469
Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if
14701470
: diag::ext_constexpr_if);
14711471
IsConstexpr = true;
1472-
ConsumeToken();
1472+
ConstexprLoc = ConsumeToken();
14731473
} else {
14741474
if (Tok.is(tok::exclaim)) {
14751475
NotLocation = ConsumeToken();
@@ -1515,7 +1515,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
15151515
if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
15161516
IsConstexpr ? Sema::ConditionKind::ConstexprIf
15171517
: Sema::ConditionKind::Boolean,
1518-
LParen, RParen))
1518+
LParen, RParen, ConstexprLoc))
15191519
return StmtError();
15201520

15211521
if (IsConstexpr)
@@ -1558,11 +1558,16 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
15581558
if (NotLocation.isInvalid() && IsConsteval) {
15591559
Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
15601560
ShouldEnter = true;
1561+
} else if (NotLocation.isValid() && IsConsteval) {
1562+
Context = Actions.ExprEvalContexts.back().Context;
1563+
ShouldEnter = true;
15611564
}
15621565

15631566
EnterExpressionEvaluationContext PotentiallyDiscarded(
15641567
Actions, Context, nullptr,
15651568
Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
1569+
if (NotLocation.isValid() && IsConsteval)
1570+
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true;
15661571
ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
15671572
}
15681573

@@ -1603,11 +1608,16 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
16031608
if (NotLocation.isValid() && IsConsteval) {
16041609
Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
16051610
ShouldEnter = true;
1611+
} else if (NotLocation.isInvalid() && IsConsteval) {
1612+
Context = Actions.ExprEvalContexts.back().Context;
1613+
ShouldEnter = true;
16061614
}
16071615

16081616
EnterExpressionEvaluationContext PotentiallyDiscarded(
16091617
Actions, Context, nullptr,
16101618
Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
1619+
if (NotLocation.isInvalid() && IsConsteval)
1620+
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true;
16111621
ElseStmt = ParseStatement();
16121622

16131623
if (ElseStmt.isUsable())

0 commit comments

Comments
 (0)