[clang] 3c8e94b - Disallow narrowing conversions to bool in noexcept specififers

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 6 07:27:45 PDT 2021


Author: Corentin Jabot
Date: 2021-08-06T10:26:39-04:00
New Revision: 3c8e94bc20e5829ab5167d21d242b6b624dd934e

URL: https://github.com/llvm/llvm-project/commit/3c8e94bc20e5829ab5167d21d242b6b624dd934e
DIFF: https://github.com/llvm/llvm-project/commit/3c8e94bc20e5829ab5167d21d242b6b624dd934e.diff

LOG: Disallow narrowing conversions to bool in noexcept specififers

Completes the support for P1401R5.

Added: 
    clang/test/SemaCXX/ignored-reference-qualifiers-disabled.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Sema/SemaExceptionSpec.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/CXX/except/except.spec/p1.cpp
    clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
    clang/test/SemaCXX/cxx2a-explicit-bool.cpp
    clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4ed561fb57b09..6cfb8b89eb903 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|explicit specifier argument}0 "
+  "array size|explicit specifier argument|noexcept specifier argument}0 "
   "is not a constant expression">;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
-  "array size|explicit specifier argument}0 "
+  "array size|explicit specifier argument|noexcept 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;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 854070aee428b..441c928ac4f20 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3499,11 +3499,12 @@ class Sema final {
 
   /// Contexts in which a converted constant expression is required.
   enum CCEKind {
-    CCEK_CaseValue,   ///< Expression in a case label.
-    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_ExplicitBool ///< Condition in an explicit(bool) specifier.
+    CCEK_CaseValue,    ///< Expression in a case label.
+    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_ExplicitBool, ///< Condition in an explicit(bool) specifier.
+    CCEK_Noexcept      ///< Condition in a noexcept(bool) specifier.
   };
   ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
                                               llvm::APSInt &Value, CCEKind CCE);
@@ -5904,7 +5905,7 @@ class Sema final {
 
   /// Check the given noexcept-specifier, convert its expression, and compute
   /// the appropriate ExceptionSpecificationType.
-  ExprResult ActOnNoexceptSpec(SourceLocation NoexceptLoc, Expr *NoexceptExpr,
+  ExprResult ActOnNoexceptSpec(Expr *NoexceptExpr,
                                ExceptionSpecificationType &EST);
 
   /// Check the given exception-specification and update the

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 760600a3ea3ca..23d22c7b99e9d 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3837,7 +3837,7 @@ Parser::tryParseExceptionSpecification(bool Delayed,
     NoexceptExpr = ParseConstantExpression();
     T.consumeClose();
     if (!NoexceptExpr.isInvalid()) {
-      NoexceptExpr = Actions.ActOnNoexceptSpec(KeywordLoc, NoexceptExpr.get(),
+      NoexceptExpr = Actions.ActOnNoexceptSpec(NoexceptExpr.get(),
                                                NoexceptType);
       NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
     } else {

diff  --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 8816c9c1fea02..0d40b47b24da4 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -78,14 +78,21 @@ bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
       .Default(false);
 }
 
-ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc,
-                                   Expr *NoexceptExpr,
+ExprResult Sema::ActOnNoexceptSpec(Expr *NoexceptExpr,
                                    ExceptionSpecificationType &EST) {
-  // FIXME: This is bogus, a noexcept expression is not a condition.
-  ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr);
+
+  if (NoexceptExpr->isTypeDependent() ||
+      NoexceptExpr->containsUnexpandedParameterPack()) {
+    EST = EST_DependentNoexcept;
+    return NoexceptExpr;
+  }
+
+  llvm::APSInt Result;
+  ExprResult Converted = CheckConvertedConstantExpression(
+      NoexceptExpr, Context.BoolTy, Result, CCEK_Noexcept);
+
   if (Converted.isInvalid()) {
     EST = EST_NoexceptFalse;
-
     // Fill in an expression of 'false' as a fixup.
     auto *BoolExpr = new (Context)
         CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc());
@@ -99,9 +106,6 @@ ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc,
     return Converted;
   }
 
-  llvm::APSInt Result;
-  Converted = VerifyIntegerConstantExpression(
-      Converted.get(), &Result, diag::err_noexcept_needs_constant_expression);
   if (!Converted.isInvalid())
     EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue;
   return Converted;

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0758fbb841074..0bf0818eeccdf 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5635,7 +5635,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
   //  expression is a constant expression and the implicit conversion
   //  sequence contains only [... list of conversions ...].
   ImplicitConversionSequence ICS =
-      CCE == Sema::CCEK_ExplicitBool
+      (CCE == Sema::CCEK_ExplicitBool || CCE == Sema::CCEK_Noexcept)
           ? TryContextuallyConvertToBool(S, From)
           : TryCopyInitialization(S, From, T,
                                   /*SuppressUserConversions=*/false,

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 70ba631dbfc6c..9d20c22ce11b3 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5945,7 +5945,7 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
 
     ExceptionSpecificationType EST = ESI.Type;
     NoexceptExpr =
-        getSema().ActOnNoexceptSpec(Loc, NoexceptExpr.get(), EST);
+        getSema().ActOnNoexceptSpec(NoexceptExpr.get(), EST);
     if (NoexceptExpr.isInvalid())
       return true;
 

diff  --git a/clang/test/CXX/except/except.spec/p1.cpp b/clang/test/CXX/except/except.spec/p1.cpp
index ef7c828bc7f29..e5a8a5de9ef8e 100644
--- a/clang/test/CXX/except/except.spec/p1.cpp
+++ b/clang/test/CXX/except/except.spec/p1.cpp
@@ -54,9 +54,8 @@ namespace noex {
 
   struct A {};
 
-  void g1() noexcept(A()); // expected-error {{not contextually convertible}}
-  void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}} expected-note {{function parameter 'b' with unknown value}} expected-note {{here}}
-
+  void g1() noexcept(A());     // expected-error {{value of type 'noex::A' is not implicitly convertible to 'bool'}}
+  void g2(bool b) noexcept(b); // expected-error {{noexcept specifier argument is not a constant expression}} expected-note {{function parameter 'b' with unknown value}} expected-note {{here}}
 }
 
 namespace noexcept_unevaluated {
@@ -73,12 +72,12 @@ namespace noexcept_unevaluated {
 }
 
 namespace PR11084 {
-  template<int X> struct A { 
-    static int f() noexcept(1/X) { return 10; }  // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}}
-  };
+template <int X> struct A {
+  static int f() noexcept(1 / X) { return 10; } // expected-error{{noexcept specifier argument is not a constant expression}} expected-note{{division by zero}}
+};
 
   template<int X> void f() {
-    int (*p)() noexcept(1/X); // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}}
+    int (*p)() noexcept(1 / X); // expected-error{{noexcept specifier argument is not a constant expression}} expected-note{{division by zero}}
   };
 
   void g() {
@@ -89,7 +88,7 @@ namespace PR11084 {
 
 namespace FuncTmplNoexceptError {
   int a = 0;
-  // expected-error at +1{{argument to noexcept specifier must be a constant expression}}
+  // expected-error at +1{{noexcept specifier argument is not a constant expression}}
   template <class T> T f() noexcept(a++){ return {};}
   void g(){
     f<int>();

diff  --git a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
index f1c6d590bfbb5..6181258ed0c5e 100644
--- a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
+++ b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
@@ -77,6 +77,17 @@ void vla(bool b) {
 }
 
 struct pr_44514 {
-  // expected-error at +1{{value of type 'void' is not contextually convertible to 'bool'}}
+  // expected-error at +1{{value of type 'void' is not implicitly convertible to 'bool'}}
   void foo(void) const &noexcept(f());
 };
+
+namespace P1401 {
+const int *ptr = nullptr;
+void f() noexcept(sizeof(char[2])); // expected-error {{noexcept specifier argument evaluates to 2, which cannot be narrowed to type 'bool'}}
+void g() noexcept(sizeof(char));
+void h() noexcept(ptr);     // expected-error {{conversion from 'const int *' to 'bool' is not allowed in a converted constant expression}}
+void i() noexcept(nullptr); // expected-error {{conversion from 'nullptr_t' to 'bool' is not allowed in a converted constant expression}}
+void j() noexcept(0);
+void k() noexcept(1);
+void l() noexcept(2); // expected-error {{noexcept specifier argument evaluates to 2, which cannot be narrowed to type 'bool'}}
+} // namespace P1401

diff  --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
index 5a9ff0e442dae..7d5fa17ef24af 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -727,3 +727,18 @@ Str a = "short";
 Str b = "not so short";// expected-error {{no viable conversion}}
 
 }
+
+namespace P1401 {
+
+const int *ptr;
+
+struct S {
+  explicit(sizeof(char[2])) S(char); // expected-error {{explicit specifier argument evaluates to 2, which cannot be narrowed to type 'bool'}}
+  explicit(ptr) S(long);             // expected-error {{conversion from 'const int *' to 'bool' is not allowed in a converted constant expression}}
+  explicit(nullptr) S(int);          // expected-error {{conversion from 'nullptr_t' to 'bool' is not allowed in a converted constant expression}}
+  explicit(42L) S(int, int);         // expected-error {{explicit specifier argument evaluates to 42, which cannot be narrowed to type 'bool'}}
+  explicit(sizeof(char)) S();
+  explicit(0) S(char, char);
+  explicit(1L) S(char, char, char);
+};
+} // namespace P1401

diff  --git a/clang/test/SemaCXX/ignored-reference-qualifiers-disabled.cpp b/clang/test/SemaCXX/ignored-reference-qualifiers-disabled.cpp
new file mode 100644
index 0000000000000..8b761320b8e9d
--- /dev/null
+++ b/clang/test/SemaCXX/ignored-reference-qualifiers-disabled.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -std=c++11 -Wignored-qualifiers -Wno-ignored-reference-qualifiers -verify=both
+// RUN: %clang_cc1 %s -std=c++11 -Wignored-qualifiers -verify=both,qual
+
+const int scalar_c(); // both-warning{{'const' type qualifier on return type has no effect}}
+volatile int scalar_v(); // both-warning{{'volatile' type qualifier on return type has no effect}}
+const volatile int scalar_cv(); // both-warning{{'const volatile' type qualifiers on return type have no effect}}
+
+typedef int& IntRef;
+
+const IntRef ref_c(); // qual-warning{{'const' qualifier on reference type 'IntRef' (aka 'int &') has no effect}}
+volatile IntRef ref_v(); // qual-warning{{'volatile' qualifier on reference type 'IntRef' (aka 'int &') has no effect}}
+const volatile IntRef ref_cv(); // qual-warning{{'const' qualifier on reference type 'IntRef' (aka 'int &') has no effect}} \
+                                qual-warning{{'volatile' qualifier on reference type 'IntRef' (aka 'int &') has no effect}}
+
+template<typename T>
+class container {
+	using value_type = T;
+	using reference  = value_type&;
+	reference get();
+	const reference get() const; // qual-warning{{'const' qualifier on reference type 'container::reference' (aka 'T &') has no effect}}
+};

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 99d4b9bc626d8..c24598dfa7024 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -876,7 +876,7 @@ TEST_P(ASTMatchersTest, Matcher_NoexceptExpression) {
   EXPECT_TRUE(
       matches("void foo() noexcept; bool bar = noexcept(foo());", NoExcept));
   EXPECT_TRUE(notMatches("void foo() noexcept;", NoExcept));
-  EXPECT_TRUE(notMatches("void foo() noexcept(1+1);", NoExcept));
+  EXPECT_TRUE(notMatches("void foo() noexcept(0+1);", NoExcept));
   EXPECT_TRUE(matches("void foo() noexcept(noexcept(1+1));", NoExcept));
 }
 

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 92bc95fc51e9d..60ce69db99225 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1298,7 +1298,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="partial" align="center">Clang 13</td>
+      <td class="unreleased" align="center">Clang 14</td>
     </tr>
     <tr>
       <td>Trimming whitespaces before line splicing</td>


        


More information about the cfe-commits mailing list