Skip to content

Commit

Permalink
[clang] Migrate DR tests to static_assert (#88611)
Browse files Browse the repository at this point in the history
This patch touches a number of tests that run in C++98 mode that have
been using array size as a context that requires a constant expression,
replacing it with a `static_assert` backported via a macro. This reduces
noise in expected directives that comes from diagnostics around VLAs.

This patch also showcases that DR tests would benefit from folding in
constant expressions in C++98 mode, but I'm not sure it's even on the
table. If it is, I'd be happy to prepare a PR for that, and rebase this
PR on top of it.

CC @AaronBallman
  • Loading branch information
Endilll authored Apr 16, 2024
1 parent 4082a75 commit aefff77
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 95 deletions.
14 changes: 9 additions & 5 deletions clang/test/CXX/drs/dr0xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
// cxx98-error@-1 {{variadic macros are a C99 feature}}
#endif

namespace cwg1 { // cwg1: no
namespace X { extern "C" void cwg1_f(int a = 1); }
namespace Y { extern "C" void cwg1_f(int a = 1); }
Expand Down Expand Up @@ -897,7 +902,7 @@ namespace cwg54 { // cwg54: 2.8

namespace cwg55 { // cwg55: yes
enum E { e = 5 };
int test[(e + 1 == 6) ? 1 : -1];
static_assert(e + 1 == 6, "");
}

namespace cwg56 { // cwg56: yes
Expand Down Expand Up @@ -1163,10 +1168,9 @@ namespace cwg75 { // cwg75: yes

namespace cwg76 { // cwg76: yes
const volatile int n = 1;
int arr[n]; // #cwg76-vla
// expected-error@#cwg76-vla {{variable length arrays in C++ are a Clang extension}}
// expected-note@#cwg76-vla {{read of volatile-qualified type 'const volatile int' is not allowed in a constant expression}}
// expected-error@#cwg76-vla {{variable length array declaration not allowed at file scope}}
static_assert(n, "");
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
// expected-note@-2 {{read of volatile-qualified type 'const volatile int' is not allowed in a constant expression}}
}

namespace cwg77 { // cwg77: yes
Expand Down
5 changes: 2 additions & 3 deletions clang/test/CXX/drs/dr16xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,9 @@ namespace cwg1645 { // cwg1645: 3.9

namespace cwg1652 { // cwg1652: 3.6
int a, b;
int arr[&a + 1 == &b ? 1 : 2];
// expected-error@-1 {{variable length arrays in C++ are a Clang extension}}
static_assert(&a + 1 == &b, "");
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
// expected-note@-2 {{comparison against pointer '&a + 1' that points past the end of a complete object has unspecified value}}
// expected-error@-3 {{variable length array declaration not allowed at file scope}}
}

namespace cwg1653 { // cwg1653: 4 c++17
Expand Down
61 changes: 33 additions & 28 deletions clang/test/CXX/drs/dr1xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
// cxx98-error@-1 {{variadic macros are a C99 feature}}
#endif

#if __cplusplus == 199711L
#define __enable_constant_folding(x) (__builtin_constant_p(x) ? (x) : (x))
#else
#define __enable_constant_folding
#endif

namespace cwg100 { // cwg100: yes
template<const char (*)[4]> struct A {}; // #cwg100-A
template<const char (&)[4]> struct B {}; // #cwg100-B
Expand Down Expand Up @@ -736,22 +747,16 @@ namespace cwg147 { // cwg147: yes

namespace cwg148 { // cwg148: yes
struct A { int A::*p; };
int check1[__is_pod(int(A::*)) ? 1 : -1];
int check2[__is_pod(A) ? 1 : -1];
static_assert(__is_pod(int(A::*)), "");
static_assert(__is_pod(A), "");
}

// cwg149: na

namespace cwg151 { // cwg151: 3.1
struct X {};
typedef int X::*p;
#if __cplusplus < 201103L
#define fold(x) (__builtin_constant_p(0) ? (x) : (x))
#else
#define fold
#endif
int check[fold(p() == 0) ? 1 : -1];
#undef fold
static_assert(__enable_constant_folding(p() == 0), "");
}

namespace cwg152 { // cwg152: yes
Expand Down Expand Up @@ -956,42 +961,42 @@ namespace cwg171 {

namespace cwg172 { // cwg172: yes
enum { zero };
int check1[-1 < zero ? 1 : -1];
static_assert(-1 < zero, "");

enum { x = -1, y = (unsigned int)-1 };
int check2[sizeof(x) > sizeof(int) ? 1 : -1];
static_assert(sizeof(x) > sizeof(int), "");

enum { a = (unsigned int)-1 / 2 };
int check3a[sizeof(a) == sizeof(int) ? 1 : -1];
int check3b[-a < 0 ? 1 : -1];
static_assert(sizeof(a) == sizeof(int), "");
static_assert(-a < 0, "");

enum { b = (unsigned int)-1 / 2 + 1 };
int check4a[sizeof(b) == sizeof(unsigned int) ? 1 : -1];
int check4b[-b > 0 ? 1 : -1];
static_assert(sizeof(b) == sizeof(unsigned int), "");
static_assert(-b > 0, "");

enum { c = (unsigned long)-1 / 2 };
int check5a[sizeof(c) == sizeof(long) ? 1 : -1];
int check5b[-c < 0 ? 1 : -1];
static_assert(sizeof(c) == sizeof(long), "");
static_assert(-c < 0, "");

enum { d = (unsigned long)-1 / 2 + 1 };
int check6a[sizeof(d) == sizeof(unsigned long) ? 1 : -1];
int check6b[-d > 0 ? 1 : -1];
static_assert(sizeof(d) == sizeof(unsigned long), "");
static_assert(-d > 0, "");

enum { e = (unsigned long long)-1 / 2 };
// cxx98-error@-1 {{'long long' is a C++11 extension}}
int check7a[sizeof(e) == sizeof(long) ? 1 : -1];
int check7b[-e < 0 ? 1 : -1];
static_assert(sizeof(e) == sizeof(long), "");
static_assert(-e < 0, "");

enum { f = (unsigned long long)-1 / 2 + 1 };
// cxx98-error@-1 {{'long long' is a C++11 extension}}
int check8a[sizeof(f) == sizeof(unsigned long) ? 1 : -1];
int check8b[-f > 0 ? 1 : -1];
static_assert(sizeof(f) == sizeof(unsigned long), "");
static_assert(-f > 0, "");
}

namespace cwg173 { // cwg173: yes
int check[('0' + 1 == '1' && '0' + 2 == '2' && '0' + 3 == '3' &&
'0' + 4 == '4' && '0' + 5 == '5' && '0' + 6 == '6' &&
'0' + 7 == '7' && '0' + 8 == '8' && '0' + 9 == '9') ? 1 : -1];
static_assert('0' + 1 == '1' && '0' + 2 == '2' && '0' + 3 == '3' &&
'0' + 4 == '4' && '0' + 5 == '5' && '0' + 6 == '6' &&
'0' + 7 == '7' && '0' + 8 == '8' && '0' + 9 == '9', "");
}

// cwg174: sup 1012
Expand Down Expand Up @@ -1070,7 +1075,7 @@ namespace cwg177 { // cwg177: yes
}

namespace cwg178 { // cwg178: yes
int check[int() == 0 ? 1 : -1];
static_assert(int() == 0, "");
#if __cplusplus >= 201103L
static_assert(int{} == 0, "");
struct S { int a, b; };
Expand Down Expand Up @@ -1180,7 +1185,7 @@ namespace cwg187 { // cwg187: sup 481

namespace cwg188 { // cwg188: yes
char c[10];
int check[sizeof(0, c) == 10 ? 1 : -1];
static_assert(sizeof(0, c) == 10, "");
}

// cwg190 FIXME: add codegen test for tbaa
Expand Down
15 changes: 10 additions & 5 deletions clang/test/CXX/drs/dr2xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@
typedef __SIZE_TYPE__ size_t;
// cxx98-error@-1 0-1 {{'long long' is a C++11 extension}}

#if __cplusplus < 201103L
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
// cxx98-error@-1 {{variadic macros are a C99 feature}}
#endif

#if __cplusplus == 199711L
#define __enable_constant_folding(x) (__builtin_constant_p(x) ? (x) : (x))
#else
#define fold
#define __enable_constant_folding
#endif

namespace cwg200 { // cwg200: dup 214
Expand All @@ -31,7 +36,7 @@ namespace cwg200 { // cwg200: dup 214
namespace cwg202 { // cwg202: 3.1
template<typename T> T f();
template<int (*g)()> struct X {
int arr[fold(g == &f<int>) ? 1 : -1];
static_assert(__enable_constant_folding(g == &f<int>), "");
};
template struct X<f>;
}
Expand Down Expand Up @@ -1024,7 +1029,7 @@ namespace cwg275 { // cwg275: no
namespace cwg277 { // cwg277: 3.1
typedef int *intp;
int *p = intp();
int a[fold(intp() ? -1 : 1)];
static_assert(__enable_constant_folding(!intp()), "");
}

namespace cwg280 { // cwg280: 2.9
Expand Down
38 changes: 21 additions & 17 deletions clang/test/CXX/drs/dr3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
// RUN: %clang_cc1 -std=c++11 -verify=expected,cxx98-14,cxx98-17,cxx98-20,cxx11-14,since-cxx11 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++98 -verify=expected,cxx98-14,cxx98-17,cxx98-20,cxx98 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
// cxx98-error@-1 {{variadic macros are a C99 feature}}
#endif

#if __cplusplus == 199711L
#define __enable_constant_folding(x) (__builtin_constant_p(x) ? (x) : (x))
#else
#define __enable_constant_folding
#endif

namespace cwg300 { // cwg300: yes
template<typename R, typename A> void f(R (&)(A)) {}
int g(int);
Expand Down Expand Up @@ -396,7 +407,7 @@ namespace cwg324 { // cwg324: 3.6

namespace cwg326 { // cwg326: 3.1
struct S {};
int test[__is_trivially_constructible(S, const S&) ? 1 : -1];
static_assert(__is_trivially_constructible(S, const S&), "");
}

namespace cwg327 { // cwg327: dup 538
Expand Down Expand Up @@ -653,7 +664,7 @@ namespace cwg339 { // cwg339: 2.8

template<typename T> A<sizeof(f(T()))> make_A();

int a[conv_int<char>::value ? 1 : -1];
static_assert(conv_int<char>::value, "");
bool b = conv_int2<char>(A<1>());
A<1> c = make_A<char>();
}
Expand Down Expand Up @@ -1099,21 +1110,14 @@ namespace cwg364 { // cwg364: yes
#endif

namespace cwg367 { // cwg367: yes
// FIXME: These diagnostics are terrible. Don't diagnose an ill-formed global
// array as being a VLA!
int a[true ? throw 0 : 4];
// expected-error@-1 {{variable length arrays in C++ are a Clang extension}}
// expected-error@-2 {{variable length array declaration not allowed at file scope}}
int b[true ? 4 : throw 0];
// cxx98-error@-1 {{variable length arrays in C++ are a Clang extension}}
// cxx98-error@-2 {{variable length array folded to constant array as an extension}}
int c[true ? *new int : 4];
// expected-error@-1 {{variable length arrays in C++ are a Clang extension}}
static_assert(__enable_constant_folding(true ? throw 0 : 4), "");
// expected-error@-1 {{expression is not an integral constant expression}}
static_assert(__enable_constant_folding(true ? 4 : throw 0), "");
static_assert(__enable_constant_folding(true ? *new int : 4), "");
// expected-error@-1 {{expression is not an integral constant expression}}
// expected-note@-2 {{read of uninitialized object is not allowed in a constant expression}}
// expected-error@-3 {{variable length array declaration not allowed at file scope}}
int d[true ? 4 : *new int];
// cxx98-error@-1 {{variable length arrays in C++ are a Clang extension}}
// cxx98-error@-2 {{variable length array folded to constant array as an extension}}
static_assert(__enable_constant_folding(true ? 4 : *new int), "");

}

namespace cwg368 { // cwg368: 3.6
Expand Down Expand Up @@ -1325,7 +1329,7 @@ namespace cwg383 { // cwg383: yes
struct B { ~B(); };
union C { C &operator=(const C&); };
union D { ~D(); };
int check[(__is_pod(A) || __is_pod(B) || __is_pod(C) || __is_pod(D)) ? -1 : 1];
static_assert(!__is_pod(A) && !__is_pod(B) && !__is_pod(C) && !__is_pod(D), "");
}

namespace cwg384 { // cwg384: yes
Expand Down
Loading

0 comments on commit aefff77

Please sign in to comment.