Skip to content

Commit 880fa7f

Browse files
committed
Revert "[clang][SemaCXX] Diagnose tautological uses of consteval if and is_constant_evaluated"
This reverts commit 491b281. This change broke valid code and generated incorrect diagnostics, see https://reviews.llvm.org/D155064
1 parent 6a34b12 commit 880fa7f

40 files changed

+163
-638
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,6 @@ 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.
215209
- Clang now prints its 'note' diagnostic in cyan instead of black, to be more compatible
216210
with terminals with dark background colors. This is also more consistent with GCC.
217211

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,10 @@ 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+
416420
// inline asm related.
417421
let CategoryName = "Inline Assembly Issue" in {
418422
def err_asm_invalid_escape : Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 5 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_tautological_consteval_if : Warning<
1595-
"consteval if is always %select{true|false}0 in this context">,
1594+
def warn_consteval_if_always_true : Warning<
1595+
"consteval if is always true in an %select{unevaluated|immediate}0 context">,
15961596
InGroup<DiagGroup<"redundant-consteval-if">>;
15971597

15981598
def ext_inline_variable : ExtWarn<
@@ -8897,9 +8897,6 @@ 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">>;
89038900
def warn_unused_result : Warning<
89048901
"ignoring return value of function declared with %0 attribute">,
89058902
InGroup<UnusedResult>;

clang/include/clang/Parse/Parser.h

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

@@ -2104,8 +2106,7 @@ class Parser : public CodeCompletionHandler {
21042106
Sema::ConditionResult &CondResult,
21052107
SourceLocation Loc, Sema::ConditionKind CK,
21062108
SourceLocation &LParenLoc,
2107-
SourceLocation &RParenLoc,
2108-
SourceLocation ConstexprLoc = {});
2109+
SourceLocation &RParenLoc);
21092110
StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
21102111
StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
21112112
StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,9 +1358,6 @@ 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;
13641361

13651362
bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false;
13661363

@@ -1390,8 +1387,7 @@ class Sema final {
13901387
NumCleanupObjects(NumCleanupObjects), NumTypos(0),
13911388
ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext),
13921389
InDiscardedStatement(false), InImmediateFunctionContext(false),
1393-
InImmediateEscalatingFunctionContext(false),
1394-
IsRuntimeEvaluated(false) {}
1390+
InImmediateEscalatingFunctionContext(false) {}
13951391

13961392
bool isUnevaluated() const {
13971393
return Context == ExpressionEvaluationContext::Unevaluated ||
@@ -1430,10 +1426,6 @@ class Sema final {
14301426
/// A stack of expression evaluation contexts.
14311427
SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
14321428

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

clang/lib/AST/ExprConstant.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12178,6 +12178,22 @@ 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+
1218112197
return Success(Info.InConstantContext, E);
1218212198
}
1218312199

clang/lib/Parse/ParseDecl.cpp

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2461,15 +2461,6 @@ 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-
24732464
Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
24742465
Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
24752466
// RAII type used to track whether we're inside an initializer.
@@ -2502,36 +2493,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
25022493
ThisDecl = nullptr;
25032494
}
25042495
};
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-
};
25352496

25362497
enum class InitKind { Uninitialized, Equal, CXXDirect, CXXBraced };
25372498
InitKind TheInitKind;
@@ -2631,7 +2592,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
26312592
<< getLangOpts().CPlusPlus20;
26322593
} else {
26332594
InitializerScopeRAII InitScope(*this, D, ThisDecl);
2634-
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
26352595

26362596
if (Tok.is(tok::code_completion)) {
26372597
cutOffParsing();
@@ -2679,7 +2639,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
26792639
ExprVector Exprs;
26802640

26812641
InitializerScopeRAII InitScope(*this, D, ThisDecl);
2682-
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
26832642

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

27322691
InitializerScopeRAII InitScope(*this, D, ThisDecl);
2733-
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
27342692

27352693
PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
27362694
ExprResult Init(ParseBraceInitializer());

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3234,14 +3234,9 @@ 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-
32413237
EnterExpressionEvaluationContext Context(
32423238
Actions,
3243-
IsConstexpr ? Sema::ExpressionEvaluationContext::ConstantEvaluated
3244-
: IsFieldInitialization
3239+
IsFieldInitialization
32453240
? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
32463241
: Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
32473242
D);

clang/lib/Parse/ParseExpr.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,13 +2093,6 @@ 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;
21032096
if (ParseExpressionList(ArgExprs, [&] {
21042097
PreferredType.enterFunctionArgument(Tok.getLocation(),
21052098
RunSignatureHelp);
@@ -2116,8 +2109,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
21162109
for (auto &E : ArgExprs)
21172110
Actions.CorrectDelayedTyposInExpr(E);
21182111
}
2119-
Actions.ExprEvalContexts.back().IsRuntimeEvaluated =
2120-
IsRuntimeEvaluated;
21212112
}
21222113
}
21232114

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,8 +2041,7 @@ 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,
2045-
SourceLocation ConstexprLoc) {
2044+
ForRangeInfo *FRI, bool EnterForConditionScope) {
20462045
// Helper to ensure we always enter a continue/break scope if requested.
20472046
struct ForConditionScopeRAII {
20482047
Scope *S;
@@ -2099,28 +2098,9 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
20992098
*InitStmt = Actions.ActOnNullStmt(SemiLoc);
21002099
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
21012100
}
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-
}
21082101

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-
}
2102+
// Parse the expression.
2103+
ExprResult Expr = ParseExpression(); // expression
21242104
if (Expr.isInvalid())
21252105
return Sema::ConditionError();
21262106

@@ -2208,21 +2188,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
22082188
if (CopyInitialization)
22092189
ConsumeToken();
22102190

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-
22262191
ExprResult InitExpr = ExprError();
22272192
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
22282193
Diag(Tok.getLocation(),
@@ -2249,7 +2214,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
22492214
Actions.ActOnInitializerError(DeclOut);
22502215

22512216
Actions.FinalizeDeclaration(DeclOut);
2252-
Actions.ConstexprIfLoc = OuterConstexprIfLoc;
22532217
return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
22542218
}
22552219

clang/lib/Parse/ParseStmt.cpp

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,17 +1293,18 @@ 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(
1297-
StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc,
1298-
Sema::ConditionKind CK, SourceLocation &LParenLoc,
1299-
SourceLocation &RParenLoc, SourceLocation ConstexprLoc) {
1296+
bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
1297+
Sema::ConditionResult &Cond,
1298+
SourceLocation Loc,
1299+
Sema::ConditionKind CK,
1300+
SourceLocation &LParenLoc,
1301+
SourceLocation &RParenLoc) {
13001302
BalancedDelimiterTracker T(*this, tok::l_paren);
13011303
T.consumeOpen();
13021304
SourceLocation Start = Tok.getLocation();
13031305

13041306
if (getLangOpts().CPlusPlus) {
1305-
Cond = ParseCXXCondition(InitStmt, Loc, CK, false, nullptr, false,
1306-
ConstexprLoc);
1307+
Cond = ParseCXXCondition(InitStmt, Loc, CK, false);
13071308
} else {
13081309
ExprResult CondExpr = ParseExpression();
13091310

@@ -1463,13 +1464,12 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
14631464
bool IsConsteval = false;
14641465
SourceLocation NotLocation;
14651466
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-
ConstexprLoc = ConsumeToken();
1472+
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, ConstexprLoc))
1518+
LParen, RParen))
15191519
return StmtError();
15201520

15211521
if (IsConstexpr)
@@ -1558,16 +1558,11 @@ 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;
15641561
}
15651562

15661563
EnterExpressionEvaluationContext PotentiallyDiscarded(
15671564
Actions, Context, nullptr,
15681565
Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
1569-
if (NotLocation.isValid() && IsConsteval)
1570-
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true;
15711566
ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
15721567
}
15731568

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

16161608
EnterExpressionEvaluationContext PotentiallyDiscarded(
16171609
Actions, Context, nullptr,
16181610
Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
1619-
if (NotLocation.isInvalid() && IsConsteval)
1620-
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true;
16211611
ElseStmt = ParseStatement();
16221612

16231613
if (ElseStmt.isUsable())

0 commit comments

Comments
 (0)