diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2777,6 +2777,13 @@ FD->getIdentifier() && FD->getIdentifier()->isStr("move"); } + bool isCallToStdIsConstantEvaluated() const { + const FunctionDecl *FD = getDirectCallee(); + return getNumArgs() == 0 && FD && FD->isInStdNamespace() && + FD->getIdentifier() && + FD->getIdentifier()->isStr("is_constant_evaluated"); + } + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCallExprConstant && T->getStmtClass() <= lastCallExprConstant; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8405,6 +8405,9 @@ "%select{self-|array }0comparison always evaluates to " "%select{a constant|true|false|'std::strong_ordering::equal'}1">, InGroup; +def warn_std_is_constant_evaluated_always_true_constexpr : Warning< + "'std::is_constant_evaluated' will always evaluate to " + "'true' in constexpr mode">, InGroup; def warn_comparison_bitwise_always : Warning< "bitwise comparison always evaluates to %select{false|true}0">, InGroup, DefaultIgnore; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3675,6 +3675,10 @@ // expression, implicitly converted to bool. // // FIXME: Return this value to the caller so they don't need to recompute it. + CallExpr *Call = dyn_cast(CondExpr->IgnoreParens()); + if (IsConstexpr && Call && Call->isCallToStdIsConstantEvaluated()) + Diag(Call->getBeginLoc(), + diag::warn_std_is_constant_evaluated_always_true_constexpr); llvm::APSInt Value(/*BitWidth*/1); return (IsConstexpr && !CondExpr->isValueDependent()) ? CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value, diff --git a/clang/test/SemaCXX/warn-std-is-constant-evaluated-constexpr.cpp b/clang/test/SemaCXX/warn-std-is-constant-evaluated-constexpr.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/warn-std-is-constant-evaluated-constexpr.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify -Wtautological-compare %s + +namespace std { +constexpr bool is_constant_evaluated() noexcept { + return __builtin_is_constant_evaluated(); +} +} + +constexpr int fn1() { + if constexpr (std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in constexpr mode}} + return 0; + else + return 1; +} + +constexpr int fn2() { + if (std::is_constant_evaluated()) + return 0; + else + return 1; +}