cor3ntin updated this revision to Diff 360840. cor3ntin added a comment. It turns out that explicit was doing the right thing (as outlined in P1401 <https://reviews.llvm.org/P1401>), but noexcept was not.
I've reworked the handling of noexcept so that noexcept and explicit specifier use the same code paths, as they have the same expected behavior and wording. This also make sure their diagnostics are consistent. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D106216/new/ https://reviews.llvm.org/D106216 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaExceptionSpec.cpp clang/lib/Sema/SemaOverload.cpp clang/test/CXX/except/except.spec/p1.cpp clang/test/SemaCXX/cxx0x-noexcept-expression.cpp clang/test/SemaCXX/cxx2a-explicit-bool.cpp clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp clang/unittests/ASTMatchers/ASTMatchersNodeTest.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="partial" align="center">Clang 13</td> + <td class="unreleased" align="center">Clang 13</td> </tr> <tr> <td>Trimming whitespaces before line splicing</td> Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -876,7 +876,7 @@ 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)); } Index: clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp =================================================================== --- clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -151,7 +151,7 @@ void (*q[])() = { p... }; consume((p(),0)...); } - template<bool ...B> void g(void (*...p)() noexcept (B)) { + template <bool... B> void g(void (*...p)() noexcept(B)) { consume((p(),0)...); check<noexcept(p()) == B ...>(); } Index: clang/test/SemaCXX/cxx2a-explicit-bool.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-explicit-bool.cpp +++ clang/test/SemaCXX/cxx2a-explicit-bool.cpp @@ -727,3 +727,18 @@ 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 Index: clang/test/SemaCXX/cxx0x-noexcept-expression.cpp =================================================================== --- clang/test/SemaCXX/cxx0x-noexcept-expression.cpp +++ clang/test/SemaCXX/cxx0x-noexcept-expression.cpp @@ -77,6 +77,17 @@ } struct pr_44514 { - // expected-error@+1{{value of type 'void' is not contextually convertible to 'bool'}} + // expected-error@+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 Index: clang/test/CXX/except/except.spec/p1.cpp =================================================================== --- clang/test/CXX/except/except.spec/p1.cpp +++ clang/test/CXX/except/except.spec/p1.cpp @@ -54,9 +54,8 @@ 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 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 FuncTmplNoexceptError { int a = 0; - // expected-error@+1{{argument to noexcept specifier must be a constant expression}} + // expected-error@+1{{noexcept specifier argument is not a constant expression}} template <class T> T f() noexcept(a++){ return {};} void g(){ f<int>(); Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -5635,7 +5635,7 @@ // 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, Index: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ clang/lib/Sema/SemaExceptionSpec.cpp @@ -78,14 +78,21 @@ .Default(false); } -ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, - Expr *NoexceptExpr, +ExprResult Sema::ActOnNoexceptSpec(SourceLocation, 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()); @@ -96,12 +103,9 @@ if (Converted.get()->isValueDependent()) { EST = EST_DependentNoexcept; - return Converted; + return NoexceptExpr; } - 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; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -3499,11 +3499,12 @@ /// 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); Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -82,11 +82,11 @@ "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;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits