cor3ntin created this revision.
cor3ntin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105127

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExprCXX.cpp
  clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1296,7 +1296,7 @@
     <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="full" align="center">Clang 13</td>
     </tr>
     <tr>
       <td>Trimming whitespaces before line splicing</td>
Index: clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
===================================================================
--- clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
+++ 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<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) {
+    }
     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 {
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ 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++
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ 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">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to