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 @@ -1487,6 +1487,8 @@ // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; +def err_constexpr_if_condition_expression_is_not_constant : Error< + "constexpr if condition is not a constant expression convertible to bool">; def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; def err_static_assert_requirement_failed : Error< "static_assert failed due to requirement '%0'%select{ %2|}1">; 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 @@ -3920,11 +3920,21 @@ // expression, implicitly converted to bool. // // FIXME: Return this value to the caller so they don't need to recompute it. - llvm::APSInt Value(/*BitWidth*/1); - return (IsConstexpr && !CondExpr->isValueDependent()) - ? CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value, - CCEK_ConstexprIf) - : PerformContextuallyConvertToBool(CondExpr); + + if ((IsConstexpr && !LangOpts.CPlusPlus2b) && !CondExpr->isValueDependent()) { + llvm::APSInt Value(/*BitWidth*/ 1); + return CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value, + CCEK_ConstexprIf); + } + ExprResult E = PerformContextuallyConvertToBool(CondExpr); + if (!IsConstexpr || CondExpr->isValueDependent()) + return E; + + llvm::APSInt Cond; + E = VerifyIntegerConstantExpression( + E.get(), &Cond, + diag::err_constexpr_if_condition_expression_is_not_constant); + return E; } /// Helper function to determine whether this is the (deprecated) C++ diff --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp --- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=c++1z -verify %s // RUN: %clang_cc1 -std=c++1z -verify %s -DUNDEFINED +// RUN: %clang_cc1 -std=c++2b -verify %s +// RUN: %clang_cc1 -std=c++2b -verify %s -DUNDEFINED #ifdef UNDEFINED // "used but not defined" errors don't get produced if we have more interesting @@ -40,17 +42,41 @@ namespace ccce { void f() { if (5) {} - if constexpr (5) {} // expected-error {{cannot be narrowed}} + if constexpr (5) { + } } template void g() { - if constexpr (N) {} // expected-error {{cannot be narrowed}} + if constexpr (N) { + } } - template void g<5>(); // expected-note {{instantiation of}} + template void g<5>(); void h() { - if constexpr (4.3) {} // expected-error{{conversion from 'double' to 'bool' is not allowed in a converted constant expression}} + if constexpr (4.3) { + } constexpr void *p = nullptr; - if constexpr (p) {} // expected-error{{conversion from 'void *const' to 'bool' is not allowed in a converted constant expression}} + if constexpr (p) { + } } + + void not_constant(int b) { + if constexpr (bool(b)) { + } // expected-error {{constexpr if condition is not a constant expression}} + if constexpr (b) { + } // expected-error {{constexpr if condition is not a constant expression}} + } + +#if __cplusplus <= 202002 + // expected-error@45 {{cannot be narrowed}} + // expected-error@48 {{cannot be narrowed}} + // expected-note@50 {{instantiation of}} + // expected-error@52 {{conversion from 'double' to 'bool' is not allowed in a converted constant expression}} + // expected-error@54 {{conversion from 'void *const' to 'bool' is not allowed in a converted constant expression}} +#else + // expected-warning@52 {{implicit conversion from 'double' to 'bool' changes value}} +#endif + // expected-note@58 {{cannot be used in a constant expression}} + // expected-note@59 {{cannot be used in a constant expression}} + // expected-note@57 2{{declared here}} } namespace generic_lambda { diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1296,7 +1296,7 @@ Narrowing contextual conversions to bool P1401R5 - No + Clang 13 Trimming whitespaces before line splicing