From: Richard Smith Date: Fri, 4 Nov 2011 18:32:57 +0000 (+0000) Subject: Clean up C++11 constant expression testing. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=545d1bbf91c01e3d72e6e5074311ace6b3f86b26;p=clang Clean up C++11 constant expression testing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143720 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 645093b01d..782b6a1d5b 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1,5 +1,21 @@ // RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 %s +// This version of static_assert just requires a foldable value as the +// expression, not an ICE. +// FIXME: Once we implement the C++11 ICE rules, most uses of this here should +// be converted to static_assert. +#define static_assert_fold(expr, str) \ + static_assert(__builtin_constant_p(expr), "not an integral constant expression"); \ + static_assert(__builtin_constant_p(expr) ? expr : true, str) + +namespace StaticAssertFoldTest { + +int x; +static_assert_fold(++x, "test"); // expected-error {{not an integral constant expression}} +static_assert_fold(false, "test"); // expected-error {{test}} + +} + // FIXME: support const T& parameters here. //template constexpr T id(const T &t) { return t; } template constexpr T id(T t) { return t; } @@ -46,17 +62,13 @@ namespace MemberEnum { struct WithMemberEnum { enum E { A = 42 }; } wme; - // FIXME: b's initializer is not treated as a constant expression yet, but we - // can at least fold it. - constexpr bool b = wme.A == 42; - int n[b]; + + static_assert_fold(wme.A == 42, ""); } namespace Recursion { constexpr int fib(int n) { return n > 1 ? fib(n-1) + fib(n-2) : n; } - // FIXME: this isn't an ICE yet. - using check_fib = int[fib(11)]; - using check_fib = int[89]; + static_assert_fold(fib(11) == 89, ""); constexpr int gcd_inner(int a, int b) { return b == 0 ? a : gcd_inner(b, a % b); @@ -65,9 +77,7 @@ namespace Recursion { return gcd_inner(max(a, b), min(a, b)); } - // FIXME: this isn't an ICE yet. - using check_gcd = int[gcd(1749237, 5628959)]; - using check_gcd = int[7]; + static_assert_fold(gcd(1749237, 5628959) == 7, ""); } namespace FunctionCast { @@ -85,11 +95,11 @@ namespace StaticMemberFunction { static constexpr int k = 42; static constexpr int f(int n) { return n * k + 2; } } s; - // FIXME: this isn't an ICE yet. - using check_static_call = int[S::f(19)]; + constexpr int n = s.f(19); - using check_static_call = int[s.f(19)]; - using check_static_call = int[800]; + static_assert_fold(S::f(19) == 800, ""); + static_assert_fold(s.f(19) == 800, ""); + static_assert_fold(n == 800, ""); } namespace ParameterScopes { @@ -99,16 +109,16 @@ namespace ParameterScopes { constexpr const int &MaybeReturnJunk(bool b, const int a) { return ObscureTheTruth(b ? a : k); } - constexpr int n1 = MaybeReturnJunk(false, 0); // ok - constexpr int n2 = MaybeReturnJunk(true, 0); // expected-error {{must be initialized by a constant expression}} + static_assert_fold(MaybeReturnJunk(false, 0) == 42, ""); // ok + constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} constexpr const int MaybeReturnNonstaticRef(bool b, const int a) { // If ObscureTheTruth returns a reference to 'a', the result is not a // constant expression even though 'a' is still in scope. return ObscureTheTruth(b ? a : k); } - constexpr int n1a = MaybeReturnNonstaticRef(false, 0); // ok - constexpr int n2a = MaybeReturnNonstaticRef(true, 0); // expected-error {{must be initialized by a constant expression}} + static_assert_fold(MaybeReturnNonstaticRef(false, 0) == 42, ""); // ok + constexpr int b = MaybeReturnNonstaticRef(true, 0); // expected-error {{constant expression}} constexpr int InternalReturnJunk(int n) { // FIXME: We should reject this: it never produces a constant expression. @@ -120,11 +130,8 @@ namespace ParameterScopes { constexpr int GrabCallersArgument(bool which, int a, int b) { return LToR(which ? b : a); } - constexpr int n4 = GrabCallersArgument(false, 1, 2); - constexpr int n5 = GrabCallersArgument(true, 4, 8); - // FIXME: this isn't an ICE yet. - using check_value = int[n4 + n5]; - using check_value = int[9]; + static_assert_fold(GrabCallersArgument(false, 1, 2) == 1, ""); + static_assert_fold(GrabCallersArgument(true, 4, 8) == 8, ""); } @@ -136,16 +143,12 @@ namespace Pointers { } const int x = 1, y = 10, z = 100; - constexpr int n1 = f(23, &x, &y, &z); - // FIXME: this isn't an ICE yet. - using check_value_1 = int[n1]; - using check_value_1 = int[788]; + static_assert_fold(f(23, &x, &y, &z) == 788, ""); constexpr int g(int n, int a, int b, int c) { return f(n, &a, &b, &c); } - constexpr int n2 = g(23, x, y, z); - using check_value_1 = int[n2]; + static_assert_fold(g(23, x, y, z) == 788, ""); } @@ -160,8 +163,7 @@ namespace FunctionPointers { } constexpr int Apply(int (*F)(int), int n) { return F(n); } - using check_value = int[1 + Apply(Select(4), 5) + Apply(Select(3), 7)]; - using check_value = int[42]; + static_assert_fold(1 + Apply(Select(4), 5) + Apply(Select(3), 7) == 42, ""); constexpr int Invalid = Apply(Select(0), 0); // xpected-error {{must be initialized by a constant expression}} @@ -171,6 +173,8 @@ namespace FunctionPointers { namespace PointerComparison { int x, y; +static_assert_fold(&x == &y, "false"); // expected-error {{false}} +static_assert_fold(&x != &y, ""); constexpr bool g1 = &x == &y; constexpr bool g2 = &x != &y; constexpr bool g3 = &x <= &y; // expected-error {{must be initialized by a constant expression}} @@ -179,46 +183,47 @@ constexpr bool g5 = &x < &y; // expected-error {{must be initialized by a consta constexpr bool g6 = &x > &y; // expected-error {{must be initialized by a constant expression}} struct S { int x, y; } s; -constexpr bool m1 = &s.x == &s.y; -constexpr bool m2 = &s.x != &s.y; -constexpr bool m3 = &s.x <= &s.y; -constexpr bool m4 = &s.x >= &s.y; -constexpr bool m5 = &s.x < &s.y; -constexpr bool m6 = &s.x > &s.y; - -constexpr bool n1 = 0 == &y; -constexpr bool n2 = 0 != &y; +static_assert_fold(&s.x == &s.y, "false"); // expected-error {{false}} +static_assert_fold(&s.x != &s.y, ""); +static_assert_fold(&s.x <= &s.y, ""); +static_assert_fold(&s.x >= &s.y, "false"); // expected-error {{false}} +static_assert_fold(&s.x < &s.y, ""); +static_assert_fold(&s.x > &s.y, "false"); // expected-error {{false}} + +static_assert_fold(0 == &y, "false"); // expected-error {{false}} +static_assert_fold(0 != &y, ""); constexpr bool n3 = 0 <= &y; // expected-error {{must be initialized by a constant expression}} constexpr bool n4 = 0 >= &y; // expected-error {{must be initialized by a constant expression}} constexpr bool n5 = 0 < &y; // expected-error {{must be initialized by a constant expression}} constexpr bool n6 = 0 > &y; // expected-error {{must be initialized by a constant expression}} -constexpr bool n7 = &x == 0; -constexpr bool n8 = &x != 0; +static_assert_fold(&x == 0, "false"); // expected-error {{false}} +static_assert_fold(&x != 0, ""); constexpr bool n9 = &x <= 0; // expected-error {{must be initialized by a constant expression}} constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a constant expression}} constexpr bool n11 = &x < 0; // expected-error {{must be initialized by a constant expression}} constexpr bool n12 = &x > 0; // expected-error {{must be initialized by a constant expression}} -constexpr bool s1 = &x == &x; -constexpr bool s2 = &x != &x; -constexpr bool s3 = &x <= &x; -constexpr bool s4 = &x >= &x; -constexpr bool s5 = &x < &x; -constexpr bool s6 = &x > &x; +static_assert_fold(&x == &x, ""); +static_assert_fold(&x != &x, "false"); // expected-error {{false}} +static_assert_fold(&x <= &x, ""); +static_assert_fold(&x >= &x, ""); +static_assert_fold(&x < &x, "false"); // expected-error {{false}} +static_assert_fold(&x > &x, "false"); // expected-error {{false}} #if 0 constexpr S* sptr = &s; +// FIXME: This is not a constant expression; check we reject this and move this +// test elsewhere. constexpr bool dyncast = sptr == dynamic_cast(sptr); #endif extern char externalvar[]; +// FIXME: This is not a constant expression; check we reject this and move this +// test elsewhere. constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} - -using check = int[m1 + (m2<<1) + (m3<<2) + (m4<<3) + (m5<<4) + (m6<<5) + - (n1<<6) + (n2<<7) + (n7<<8) + (n8<<9) + (g1<<10) + (g2<<11) + - (s1<<12) + (s2<<13) + (s3<<14) + (s4<<15) + (s5<<16) + (s6<<17)]; -using check = int[2+4+16+128+512+2048+4096+16384+32768]; +constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}} +static_assert_fold(0 != "foo", ""); } @@ -230,11 +235,10 @@ constexpr int n = f(1); constexpr bool same(const int &a, const int &b) { return &a == &b; } constexpr bool sameTemporary(const int &n) { return same(n, n); } -using check_value = int[1]; -using check_value = int[n]; -using check_value = int[!same(4, 4)]; -using check_value = int[same(n, n)]; -using check_value = int[sameTemporary(9)]; +static_assert_fold(n, ""); +static_assert_fold(!same(4, 4), ""); +static_assert_fold(same(n, n), ""); +static_assert_fold(sameTemporary(9), ""); } @@ -251,10 +255,9 @@ constexpr int MangleChars(const char32_t *p) { return *p + 3 * (*p ? MangleChars(p+1) : 0); } -using check_value = int[1768383]; -using check_value = int[MangleChars("constexpr!")]; -using check_value = int[MangleChars(u"constexpr!")]; -using check_value = int[MangleChars(U"constexpr!")]; +static_assert_fold(MangleChars("constexpr!") == 1768383, ""); +static_assert_fold(MangleChars(u"constexpr!") == 1768383, ""); +static_assert_fold(MangleChars(U"constexpr!") == 1768383, ""); constexpr char c0 = "nought index"[0]; constexpr char c1 = "nice index"[10];