Skip to content

Commit b06305e

Browse files
[Diagnostics] Warn for std::is_constant_evaluated in constexpr mode
Summary: constexpr int fn1() { if constexpr (std::is_constant_evaluated()) // condition is always true! return 0; else return 1; } constexpr int fn2() { if (std::is_constant_evaluated()) return 0; else return 1; } Solves PR42977 Reviewers: rsmith, aaron.ballman Reviewed By: rsmith Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D69518
1 parent c950495 commit b06305e

File tree

4 files changed

+78
-2
lines changed

4 files changed

+78
-2
lines changed

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ def warn_integer_constant_overflow : Warning<
329329
def note_unimplemented_constexpr_lambda_feature_ast : Note<
330330
"unimplemented constexpr lambda feature: %0 (coming soon!)">;
331331

332+
def warn_is_constant_evaluated_always_true_constexpr : Warning<
333+
"'%0' will always evaluate to 'true' in a manifestly constant-evaluated expression">,
334+
InGroup<DiagGroup<"constant-evaluated">>;
335+
332336
// inline asm related.
333337
let CategoryName = "Inline Assembly Issue" in {
334338
def err_asm_invalid_escape : Error<

clang/lib/AST/ExprConstant.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10593,8 +10593,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1059310593
return false;
1059410594
}
1059510595

10596-
case Builtin::BI__builtin_is_constant_evaluated:
10596+
case Builtin::BI__builtin_is_constant_evaluated: {
10597+
const auto *Callee = Info.CurrentCall->getCallee();
10598+
if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression &&
10599+
(Info.CallStackDepth == 1 ||
10600+
(Info.CallStackDepth == 2 && Callee->isInStdNamespace() &&
10601+
Callee->getIdentifier() &&
10602+
Callee->getIdentifier()->isStr("is_constant_evaluated")))) {
10603+
// FIXME: Find a better way to avoid duplicated diagnostics.
10604+
if (Info.EvalStatus.Diag)
10605+
Info.report((Info.CallStackDepth == 1) ? E->getExprLoc()
10606+
: Info.CurrentCall->CallLoc,
10607+
diag::warn_is_constant_evaluated_always_true_constexpr)
10608+
<< (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated"
10609+
: "std::is_constant_evaluated");
10610+
}
10611+
1059710612
return Success(Info.InConstantContext, E);
10613+
}
1059810614

1059910615
case Builtin::BI__builtin_ctz:
1060010616
case Builtin::BI__builtin_ctzl:

clang/test/SemaCXX/builtin-is-constant-evaluated.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
1+
// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -Wno-constant-evaluated -triple=x86_64-linux-gnu
22

33
using size_t = decltype(sizeof(int));
44

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s
2+
3+
namespace std {
4+
constexpr bool is_constant_evaluated() noexcept {
5+
return __builtin_is_constant_evaluated();
6+
}
7+
} // namespace std
8+
9+
constexpr int fn1() {
10+
if constexpr (std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
11+
return 0;
12+
else
13+
return 1;
14+
}
15+
16+
constexpr int fn2() {
17+
if constexpr (!std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
18+
return 0;
19+
else
20+
return 1;
21+
}
22+
23+
constexpr int fn3() {
24+
if constexpr (std::is_constant_evaluated() == false) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
25+
return 0;
26+
else
27+
return 1;
28+
}
29+
30+
constexpr int fn4() {
31+
if constexpr (__builtin_is_constant_evaluated() == true) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
32+
return 0;
33+
else
34+
return 1;
35+
}
36+
37+
constexpr int fn5() {
38+
if constexpr (__builtin_is_constant_evaluated()) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
39+
return 0;
40+
else
41+
return 1;
42+
}
43+
44+
constexpr int nowarn1() {
45+
if (std::is_constant_evaluated())
46+
return 0;
47+
else
48+
return 1;
49+
}
50+
51+
constexpr int nowarn2() {
52+
if (!__builtin_is_constant_evaluated())
53+
return 0;
54+
else
55+
return 1;
56+
}

0 commit comments

Comments
 (0)