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@+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>(); 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@+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 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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits