[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
This commit is contained in:
parent
c950495405
commit
b06305e449
|
@ -329,6 +329,10 @@ def warn_integer_constant_overflow : Warning<
|
|||
def note_unimplemented_constexpr_lambda_feature_ast : Note<
|
||||
"unimplemented constexpr lambda feature: %0 (coming soon!)">;
|
||||
|
||||
def warn_is_constant_evaluated_always_true_constexpr : Warning<
|
||||
"'%0' will always evaluate to 'true' in a manifestly constant-evaluated expression">,
|
||||
InGroup<DiagGroup<"constant-evaluated">>;
|
||||
|
||||
// inline asm related.
|
||||
let CategoryName = "Inline Assembly Issue" in {
|
||||
def err_asm_invalid_escape : Error<
|
||||
|
|
|
@ -10593,8 +10593,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
return false;
|
||||
}
|
||||
|
||||
case Builtin::BI__builtin_is_constant_evaluated:
|
||||
case Builtin::BI__builtin_is_constant_evaluated: {
|
||||
const auto *Callee = Info.CurrentCall->getCallee();
|
||||
if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression &&
|
||||
(Info.CallStackDepth == 1 ||
|
||||
(Info.CallStackDepth == 2 && Callee->isInStdNamespace() &&
|
||||
Callee->getIdentifier() &&
|
||||
Callee->getIdentifier()->isStr("is_constant_evaluated")))) {
|
||||
// FIXME: Find a better way to avoid duplicated diagnostics.
|
||||
if (Info.EvalStatus.Diag)
|
||||
Info.report((Info.CallStackDepth == 1) ? E->getExprLoc()
|
||||
: Info.CurrentCall->CallLoc,
|
||||
diag::warn_is_constant_evaluated_always_true_constexpr)
|
||||
<< (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated"
|
||||
: "std::is_constant_evaluated");
|
||||
}
|
||||
|
||||
return Success(Info.InConstantContext, E);
|
||||
}
|
||||
|
||||
case Builtin::BI__builtin_ctz:
|
||||
case Builtin::BI__builtin_ctzl:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -Wno-constant-evaluated -triple=x86_64-linux-gnu
|
||||
|
||||
using size_t = decltype(sizeof(int));
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s
|
||||
|
||||
namespace std {
|
||||
constexpr bool is_constant_evaluated() noexcept {
|
||||
return __builtin_is_constant_evaluated();
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
constexpr int fn1() {
|
||||
if constexpr (std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn2() {
|
||||
if constexpr (!std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn3() {
|
||||
if constexpr (std::is_constant_evaluated() == false) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn4() {
|
||||
if constexpr (__builtin_is_constant_evaluated() == true) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn5() {
|
||||
if constexpr (__builtin_is_constant_evaluated()) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int nowarn1() {
|
||||
if (std::is_constant_evaluated())
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int nowarn2() {
|
||||
if (!__builtin_is_constant_evaluated())
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue