diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1cc9e4efac1fec..d24dab5edad00f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -73,6 +73,8 @@ C++ Language Changes - Improved ``-O0`` code generation for calls to ``std::forward_like``. Similarly to ``std::move, std::forward`` et al. it is now treated as a compiler builtin and implemented directly rather than instantiating the definition from the standard library. +- Implemented `CWG2518 `_ which allows ``static_assert(false)`` + to not be ill-formed when its condition is evaluated in the context of a template definition. C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 6ec0eacf7a37c0..ec85d503ccf8f1 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -16784,7 +16784,14 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, FoldKind).isInvalid()) Failed = true; - if (!Failed && !Cond) { + // CWG2518 + // [dcl.pre]/p10 If [...] the expression is evaluated in the context of a + // template definition, the declaration has no effect. + bool InTemplateDefinition = + getLangOpts().CPlusPlus && CurContext->isDependentContext(); + + if (!Failed && !Cond && !InTemplateDefinition) { + SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); if (AssertMessage) { @@ -16815,7 +16822,8 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, DiagnoseStaticAssertDetails(InnerCond); } else { Diag(StaticAssertLoc, diag::err_static_assert_failed) - << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + PrintContextStack(); } Failed = true; } diff --git a/clang/test/CXX/drs/dr25xx.cpp b/clang/test/CXX/drs/dr25xx.cpp index ee68b4ad45d11e..c4f7d3ebde413e 100644 --- a/clang/test/CXX/drs/dr25xx.cpp +++ b/clang/test/CXX/drs/dr25xx.cpp @@ -1,5 +1,39 @@ // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify +namespace dr2518 { // dr2518: 17 review + +template +void f(T t) { + if constexpr (sizeof(T) != sizeof(int)) { + static_assert(false, "must be int-sized"); // expected-error {{must be int-size}} + } +} + +void g(char c) { + f(0); + f(c); // expected-note {{requested here}} +} + +template +struct S { + static_assert(false); // expected-error {{static assertion failed}} +}; + +template <> +struct S {}; + +template <> +struct S {}; + +int test_specialization() { + S s1; + S s2; + S s3; // expected-note {{in instantiation of template class 'dr2518::S' requested here}} +} + +} + + namespace dr2565 { // dr2565: 16 open template concept C = requires (typename T::type x) { diff --git a/clang/test/SemaCXX/access-base-class.cpp b/clang/test/SemaCXX/access-base-class.cpp index 2b16d3fdda5683..47d0f02ec545c8 100644 --- a/clang/test/SemaCXX/access-base-class.cpp +++ b/clang/test/SemaCXX/access-base-class.cpp @@ -96,14 +96,14 @@ struct flag { }; template -struct trait : flag {}; +struct trait : flag {}; // expected-note 2{{here}} -template ::value> +template ::value> // expected-note {{here}} struct a {}; template class b { - a x; + a x; // expected-note {{here}} using U = a; }; @@ -113,5 +113,5 @@ struct Impossible { }; // verify "no member named 'value'" bogus diagnostic is not emitted. -trait>>::value; +trait>>::value; // expected-note {{here}} } // namespace T8 diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp index 3f779dd913f8fa..e480c0d34593aa 100644 --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/test/SemaCXX/coroutines.cpp @@ -1309,7 +1309,7 @@ struct DepTestType { } }; -template struct DepTestType; // expected-note {{requested here}} +template struct DepTestType; // expected-note 2{{requested here}} template CoroMemberTag DepTestType::test_member_template(long, const char *) const &&; template CoroMemberTag DepTestType::test_static_template(const char *volatile &, unsigned); diff --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp index ed2389f4eb100a..97a3aaec0a08e1 100644 --- a/clang/test/SemaCXX/static-assert.cpp +++ b/clang/test/SemaCXX/static-assert.cpp @@ -52,9 +52,11 @@ static_assert(false, "🏳️‍🌈 🏴󠁧󠁢󠁥󠁮󠁧󠁿 🇪🇺"); // template struct AlwaysFails { // Only give one error here. - static_assert(false, ""); // expected-error {{static assertion failed}} + static_assert(false, ""); // expected-error 2{{static assertion failed}} }; -AlwaysFails alwaysFails; +AlwaysFails alwaysFails; // expected-note {{instantiation}} +AlwaysFails alwaysFails2; // expected-note {{instantiation}} + template struct StaticAssertProtected { static_assert(__is_literal(T), ""); // expected-error {{static assertion failed}} @@ -217,6 +219,23 @@ static_assert(constexprNotBool, "message"); // expected-error {{value of type 'c static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}} +namespace DependentAlwaysFalse { +template +struct S { + static_assert(false); // expected-error{{static assertion failed}} \ + // expected-warning {{C++17 extension}} +}; + +template +struct T { + static_assert(false, "test"); // expected-error{{static assertion failed: test}} +}; + +int f() { + S s; //expected-note {{in instantiation of template class 'DependentAlwaysFalse::S' requested here}} + T t; //expected-note {{in instantiation of template class 'DependentAlwaysFalse::T' requested here}} +} +} namespace Diagnostics { /// No notes for literals. diff --git a/clang/test/SemaTemplate/instantiate-var-template.cpp b/clang/test/SemaTemplate/instantiate-var-template.cpp index 349a80bdd0dc70..60d3bd3b59f533 100644 --- a/clang/test/SemaTemplate/instantiate-var-template.cpp +++ b/clang/test/SemaTemplate/instantiate-var-template.cpp @@ -31,8 +31,7 @@ namespace InstantiationDependent { static_assert(b == 1, ""); // expected-note {{in instantiation of}} template void f() { - static_assert(a == 0, ""); // expected-error {{static assertion failed due to requirement 'a == 0'}} \ - // expected-note {{evaluates to '1 == 0'}} + int check[a == 0 ? 1 : -1]; // expected-error {{array with a negative size}} } } diff --git a/clang/test/SemaTemplate/instantiation-dependence.cpp b/clang/test/SemaTemplate/instantiation-dependence.cpp index 8ef18e8e0559a5..82665b26b12299 100644 --- a/clang/test/SemaTemplate/instantiation-dependence.cpp +++ b/clang/test/SemaTemplate/instantiation-dependence.cpp @@ -37,8 +37,8 @@ namespace PR33655 { template using indirect_void_t = typename indirect_void_t_imp::type; template void foo() { - static_assert(!__is_void(indirect_void_t)); // "ok", dependent - static_assert(!__is_void(void_t)); // expected-error {{failed}} + int check1[__is_void(indirect_void_t) == 0 ? 1 : -1]; // "ok", dependent + int check2[__is_void(void_t) == 0 ? 1 : -1]; // expected-error {{array with a negative size}} } } diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index fdf8e6b4baeb1f..f57aafcdb30906 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -14915,7 +14915,7 @@

C++ defect report implementation status

2518 review Conformance requirements and #error/#warning - Not resolved + Clang 17 2519