Completes the support for P1401R5.
"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;
/// 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);
/// 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
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 {
.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());
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;
// 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,
ExceptionSpecificationType EST = ESI.Type;
NoexceptExpr =
- getSema().ActOnNoexceptSpec(Loc, NoexceptExpr.get(), EST);
+ getSema().ActOnNoexceptSpec(NoexceptExpr.get(), EST);
if (NoexceptExpr.isInvalid())
return true;
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 {
}
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() {
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>();
}
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
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
--- /dev/null
+// 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}}
+};
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));
}
<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>