[clang] 8747234 - Partially implement P1401R5 (Narrowing contextual conversions to bool)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 12 05:06:36 PDT 2021


Author: Corentin Jabot
Date: 2021-07-12T08:06:27-04:00
New Revision: 8747234032c9c6270a6198ab3cca14ce2bd18721

URL: https://github.com/llvm/llvm-project/commit/8747234032c9c6270a6198ab3cca14ce2bd18721
DIFF: https://github.com/llvm/llvm-project/commit/8747234032c9c6270a6198ab3cca14ce2bd18721.diff

LOG: Partially implement P1401R5 (Narrowing contextual conversions to bool)

Support Narrowing conversions to bool in if constexpr condition
under C++23 language mode.

Only if constexpr is implemented as the behavior of static_assert
is already conforming. Still need to work on explicit(bool) to
complete support.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/SemaExprCXX.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
    clang/test/SemaCXX/static-assert.cpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c8d848b41d353..21b9ce2d9ff2a 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -82,11 +82,11 @@ def err_typecheck_converted_constant_expression_indirect : Error<
   "bind reference to a temporary">;
 def err_expr_not_cce : Error<
   "%select{case value|enumerator value|non-type template argument|"
-  "array size|constexpr if condition|explicit specifier argument}0 "
+  "array size|explicit specifier argument}0 "
   "is not a constant expression">;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
-  "array size|constexpr if condition|explicit specifier argument}0 "
+  "array size|explicit specifier argument}0 "
   "%select{cannot be narrowed from type %2 to %3|"
   "evaluates to %2, which cannot be narrowed to type %3}1">,
   InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
@@ -1487,6 +1487,8 @@ def err_messaging_class_with_direct_method : Error<
 // 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">;
 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/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ad987dffac03a..e1dac7db1b4ce 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3503,7 +3503,6 @@ class Sema final {
     CCEK_Enumerator,  ///< Enumerator value with fixed underlying type.
     CCEK_TemplateArg, ///< Value of a non-type template parameter.
     CCEK_ArrayBound,  ///< Array bound in array declarator or new-expression.
-    CCEK_ConstexprIf, ///< Condition in a constexpr if statement.
     CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier.
   };
   ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index e6bf5c6a7ad86..bf0b8b71d9315 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3911,7 +3911,7 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
 
 /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
 ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) {
-  // C++ 6.4p4:
+  // C++11 6.4p4:
   // The value of a condition that is an initialized declaration in a statement
   // other than a switch statement is the value of the declared variable
   // implicitly converted to type bool. If that conversion is ill-formed, the
@@ -3919,12 +3919,22 @@ ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) {
   // The value of a condition that is an expression is the value of the
   // expression, implicitly converted to bool.
   //
+  // C++2b 8.5.2p2
+  // If the if statement is of the form if constexpr, the value of the condition
+  // is contextually converted to bool and the converted expression shall be
+  // a constant expression.
+  //
+
+  ExprResult E = PerformContextuallyConvertToBool(CondExpr);
+  if (!IsConstexpr || E.isInvalid() || E.get()->isValueDependent())
+    return E;
+
   // 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);
+  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/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 8092f0be6ccec..0758fbb841074 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5634,12 +5634,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
   //  implicitly converted to type T, where the converted
   //  expression is a constant expression and the implicit conversion
   //  sequence contains only [... list of conversions ...].
-  // C++1z [stmt.if]p2:
-  //  If the if statement is of the form if constexpr, the value of the
-  //  condition shall be a contextually converted constant expression of type
-  //  bool.
   ImplicitConversionSequence ICS =
-      CCE == Sema::CCEK_ConstexprIf || CCE == Sema::CCEK_ExplicitBool
+      CCE == Sema::CCEK_ExplicitBool
           ? TryContextuallyConvertToBool(S, From)
           : TryCopyInitialization(S, From, T,
                                   /*SuppressUserConversions=*/false,

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
index c33bf0eba231b..ed61119dc252a 100644
--- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
@@ -38,18 +38,38 @@ namespace odr_use_in_selected_arm {
 }
 #else
 namespace ccce {
+
+  struct S {
+  };
   void f() {
     if (5) {}
-    if constexpr (5) {} // expected-error {{cannot be narrowed}}
+    if constexpr (5) {
+    }
   }
   template<int N> 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) { //expected-warning {{implicit conversion from 'double' to 'bool' changes value}}
+    }
     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, S s) { //  expected-note 2{{declared here}}
+    if constexpr (bool(b)) {      // expected-error {{constexpr if condition is not a constant expression}} expected-note {{cannot be used in a constant expression}}
+    }
+    if constexpr (b) { // expected-error {{constexpr if condition is not a constant expression}} expected-note {{cannot be used in a constant expression}}
+    }
+    if constexpr (s) { // expected-error {{value of type 'ccce::S' is not contextually convertible to 'bool'}}
+    }
+
+    constexpr S constexprS;
+    if constexpr (constexprS) { // expected-error {{value of type 'const ccce::S' is not contextually convertible to 'bool'}}
+    }
   }
 }
 

diff  --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp
index dfc06331e51f3..affc0c32a7a89 100644
--- a/clang/test/SemaCXX/static-assert.cpp
+++ b/clang/test/SemaCXX/static-assert.cpp
@@ -188,3 +188,14 @@ void foo4(T t) {
 }
 void callFoo4() { foo4(42); }
 // expected-note at -1{{in instantiation of function template specialization 'foo4<int>' requested here}}
+
+static_assert(42, "message");
+static_assert(42.0, "message"); // expected-warning {{implicit conversion from 'double' to 'bool' changes value from 42 to true}}
+constexpr int *p = 0;
+static_assert(p, "message"); // expected-error {{static_assert failed}}
+
+struct NotBool {
+} notBool;
+constexpr NotBool constexprNotBool;
+static_assert(notBool, "message");          // expected-error {{value of type 'struct NotBool' is not contextually convertible to 'bool'}}
+static_assert(constexprNotBool, "message"); // expected-error {{value of type 'const NotBool' is not contextually convertible to 'bool'}}

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 8de688189e297..2ad2047f68d00 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1296,7 +1296,7 @@ <h2 id="cxx23">C++2b implementation status</h2>
     <tr>
       <td>Narrowing contextual conversions to bool</td>
       <td><a href="https://wg21.link/P1401R5">P1401R5</a></td>
-      <td class="none" align="center">No</td>
+      <td class="partial" align="center">Clang 13</td>
     </tr>
     <tr>
       <td>Trimming whitespaces before line splicing</td>


        


More information about the cfe-commits mailing list