Skip to content

Commit 00e2098

Browse files
committed
[Clang] Implement CWG2518 - static_assert(false)
This allows `static_assert(false)` to not be ill-formed in template definitions. This change is applied as a DR in all C++ modes. Of notes, a couple of tests were relying of the eager nature of static_assert * test/SemaTemplate/instantiation-dependence.cpp * test/SemaTemplate/instantiate-var-template.cpp I don't know if the changes to `static_assert` still allow that sort of tests to be expressed. Reviewed By: #clang-language-wg, erichkeane, aaron.ballman Differential Revision: https://reviews.llvm.org/D144285
1 parent 7344f8a commit 00e2098

File tree

9 files changed

+76
-14
lines changed

9 files changed

+76
-14
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ C++ Language Changes
7373
- Improved ``-O0`` code generation for calls to ``std::forward_like``. Similarly to
7474
``std::move, std::forward`` et al. it is now treated as a compiler builtin and implemented
7575
directly rather than instantiating the definition from the standard library.
76+
- Implemented `CWG2518 <https://wg21.link/CWG2518>`_ which allows ``static_assert(false)``
77+
to not be ill-formed when its condition is evaluated in the context of a template definition.
7678

7779
C++20 Feature Support
7880
^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16784,7 +16784,14 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
1678416784
FoldKind).isInvalid())
1678516785
Failed = true;
1678616786

16787-
if (!Failed && !Cond) {
16787+
// CWG2518
16788+
// [dcl.pre]/p10 If [...] the expression is evaluated in the context of a
16789+
// template definition, the declaration has no effect.
16790+
bool InTemplateDefinition =
16791+
getLangOpts().CPlusPlus && CurContext->isDependentContext();
16792+
16793+
if (!Failed && !Cond && !InTemplateDefinition) {
16794+
1678816795
SmallString<256> MsgBuffer;
1678916796
llvm::raw_svector_ostream Msg(MsgBuffer);
1679016797
if (AssertMessage) {
@@ -16815,7 +16822,8 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
1681516822
DiagnoseStaticAssertDetails(InnerCond);
1681616823
} else {
1681716824
Diag(StaticAssertLoc, diag::err_static_assert_failed)
16818-
<< !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
16825+
<< !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
16826+
PrintContextStack();
1681916827
}
1682016828
Failed = true;
1682116829
}

clang/test/CXX/drs/dr25xx.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
11
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify
22

3+
namespace dr2518 { // dr2518: 17 review
4+
5+
template <class T>
6+
void f(T t) {
7+
if constexpr (sizeof(T) != sizeof(int)) {
8+
static_assert(false, "must be int-sized"); // expected-error {{must be int-size}}
9+
}
10+
}
11+
12+
void g(char c) {
13+
f(0);
14+
f(c); // expected-note {{requested here}}
15+
}
16+
17+
template <typename Ty>
18+
struct S {
19+
static_assert(false); // expected-error {{static assertion failed}}
20+
};
21+
22+
template <>
23+
struct S<int> {};
24+
25+
template <>
26+
struct S<float> {};
27+
28+
int test_specialization() {
29+
S<int> s1;
30+
S<float> s2;
31+
S<double> s3; // expected-note {{in instantiation of template class 'dr2518::S<double>' requested here}}
32+
}
33+
34+
}
35+
36+
337
namespace dr2565 { // dr2565: 16 open
438
template<typename T>
539
concept C = requires (typename T::type x) {

clang/test/SemaCXX/access-base-class.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,14 @@ struct flag {
9696
};
9797

9898
template <class T>
99-
struct trait : flag<sizeof(T)> {};
99+
struct trait : flag<sizeof(T)> {}; // expected-note 2{{here}}
100100

101-
template <class T, bool Inferred = trait<T>::value>
101+
template <class T, bool Inferred = trait<T>::value> // expected-note {{here}}
102102
struct a {};
103103

104104
template <class T>
105105
class b {
106-
a<T> x;
106+
a<T> x; // expected-note {{here}}
107107
using U = a<T>;
108108
};
109109

@@ -113,5 +113,5 @@ struct Impossible {
113113
};
114114

115115
// verify "no member named 'value'" bogus diagnostic is not emitted.
116-
trait<b<Impossible<0>>>::value;
116+
trait<b<Impossible<0>>>::value; // expected-note {{here}}
117117
} // namespace T8

clang/test/SemaCXX/coroutines.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1309,7 +1309,7 @@ struct DepTestType {
13091309
}
13101310
};
13111311

1312-
template struct DepTestType<int>; // expected-note {{requested here}}
1312+
template struct DepTestType<int>; // expected-note 2{{requested here}}
13131313
template CoroMemberTag DepTestType<int>::test_member_template(long, const char *) const &&;
13141314

13151315
template CoroMemberTag DepTestType<int>::test_static_template<void>(const char *volatile &, unsigned);

clang/test/SemaCXX/static-assert.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ static_assert(false, "🏳️‍🌈 🏴󠁧󠁢󠁥󠁮󠁧󠁿 🇪🇺"); //
5252

5353
template<typename T> struct AlwaysFails {
5454
// Only give one error here.
55-
static_assert(false, ""); // expected-error {{static assertion failed}}
55+
static_assert(false, ""); // expected-error 2{{static assertion failed}}
5656
};
57-
AlwaysFails<int> alwaysFails;
57+
AlwaysFails<int> alwaysFails; // expected-note {{instantiation}}
58+
AlwaysFails<double> alwaysFails2; // expected-note {{instantiation}}
59+
5860

5961
template<typename T> struct StaticAssertProtected {
6062
static_assert(__is_literal(T), ""); // expected-error {{static assertion failed}}
@@ -217,6 +219,23 @@ static_assert(constexprNotBool, "message"); // expected-error {{value of type 'c
217219

218220
static_assert(1 , "") // expected-error {{expected ';' after 'static_assert'}}
219221

222+
namespace DependentAlwaysFalse {
223+
template <typename Ty>
224+
struct S {
225+
static_assert(false); // expected-error{{static assertion failed}} \
226+
// expected-warning {{C++17 extension}}
227+
};
228+
229+
template <typename Ty>
230+
struct T {
231+
static_assert(false, "test"); // expected-error{{static assertion failed: test}}
232+
};
233+
234+
int f() {
235+
S<double> s; //expected-note {{in instantiation of template class 'DependentAlwaysFalse::S<double>' requested here}}
236+
T<double> t; //expected-note {{in instantiation of template class 'DependentAlwaysFalse::T<double>' requested here}}
237+
}
238+
}
220239

221240
namespace Diagnostics {
222241
/// No notes for literals.

clang/test/SemaTemplate/instantiate-var-template.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ namespace InstantiationDependent {
3131
static_assert(b<char> == 1, ""); // expected-note {{in instantiation of}}
3232

3333
template<typename T> void f() {
34-
static_assert(a<sizeof(sizeof(f(T())))> == 0, ""); // expected-error {{static assertion failed due to requirement 'a<sizeof (sizeof (f(type-parameter-0-0())))> == 0'}} \
35-
// expected-note {{evaluates to '1 == 0'}}
34+
int check[a<sizeof(sizeof(f(T())))> == 0 ? 1 : -1]; // expected-error {{array with a negative size}}
3635
}
3736
}
3837

clang/test/SemaTemplate/instantiation-dependence.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ namespace PR33655 {
3737
template<class ...Args> using indirect_void_t = typename indirect_void_t_imp<Args...>::type;
3838

3939
template<class T> void foo() {
40-
static_assert(!__is_void(indirect_void_t<T>)); // "ok", dependent
41-
static_assert(!__is_void(void_t<T>)); // expected-error {{failed}}
40+
int check1[__is_void(indirect_void_t<T>) == 0 ? 1 : -1]; // "ok", dependent
41+
int check2[__is_void(void_t<T>) == 0 ? 1 : -1]; // expected-error {{array with a negative size}}
4242
}
4343
}
4444

clang/www/cxx_dr_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14915,7 +14915,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
1491514915
<td><a href="https://wg21.link/cwg2518">2518</a></td>
1491614916
<td>review</td>
1491714917
<td>Conformance requirements and <TT>#error</TT>/<TT>#warning</TT></td>
14918-
<td align="center">Not resolved</td>
14918+
<td class="unreleased" align="center">Clang 17</td>
1491914919
</tr>
1492014920
<tr class="open" id="2519">
1492114921
<td><a href="https://wg21.link/cwg2519">2519</a></td>

0 commit comments

Comments
 (0)