diff options
Diffstat (limited to 'test/SemaCXX/constant-expression-cxx1y.cpp')
-rw-r--r-- | test/SemaCXX/constant-expression-cxx1y.cpp | 468 |
1 files changed, 461 insertions, 7 deletions
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp index 60ec820..521526d 100644 --- a/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/test/SemaCXX/constant-expression-cxx1y.cpp @@ -128,10 +128,10 @@ constexpr int namespace_alias() { namespace assign { constexpr int a = 0; const int b = 0; - int c = 0; // expected-note 2{{here}} + int c = 0; // expected-note {{here}} constexpr void set(const int &a, int b) { - const_cast<int&>(a) = b; // expected-note 2{{constant expression cannot modify an object that is visible outside that expression}} + const_cast<int&>(a) = b; // expected-note 3{{constant expression cannot modify an object that is visible outside that expression}} } constexpr int wrap(int a, int b) { set(a, b); @@ -140,7 +140,7 @@ namespace assign { static_assert((set(a, 1), a) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(a, 1)'}} static_assert((set(b, 1), b) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(b, 1)'}} - static_assert((set(c, 1), c) == 1, ""); // expected-error {{constant expression}} expected-note {{read of non-const variable 'c'}} + static_assert((set(c, 1), c) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(c, 1)'}} static_assert(wrap(a, 1) == 1, ""); static_assert(wrap(b, 1) == 1, ""); @@ -250,11 +250,12 @@ namespace lifetime { } namespace const_modify { - constexpr int modify(int &n) { return n = 1; } // expected-note {{modification of object of const-qualified type 'const int'}} + constexpr int modify(int &n) { return n = 1; } // expected-note 2 {{modification of object of const-qualified type 'const int'}} constexpr int test1() { int k = 0; return modify(k); } - constexpr int test2() { const int k = 0; return modify(const_cast<int&>(k)); } // expected-note {{in call}} + constexpr int test2() { const int k = 0; return modify(const_cast<int&>(k)); } // expected-note 2 {{in call}} static_assert(test1() == 1, ""); static_assert(test2() == 1, ""); // expected-error {{constant expression}} expected-note {{in call}} + constexpr int i = test2(); // expected-error {{constant expression}} expected-note {{in call}} } namespace null { @@ -334,6 +335,99 @@ namespace incdec { static_assert(incr(0) == 101, ""); } +namespace compound_assign { + constexpr bool test_int() { + int a = 3; + a += 6; + if (a != 9) return false; + a -= 2; + if (a != 7) return false; + a *= 3; + if (a != 21) return false; + if (&(a /= 10) != &a) return false; + if (a != 2) return false; + a <<= 3; + if (a != 16) return false; + a %= 6; + if (a != 4) return false; + a >>= 1; + if (a != 2) return false; + a ^= 10; + if (a != 8) return false; + a |= 5; + if (a != 13) return false; + a &= 14; + if (a != 12) return false; + return true; + } + static_assert(test_int(), ""); + + constexpr bool test_float() { + float f = 123.; + f *= 2; + if (f != 246.) return false; + if ((f -= 0.5) != 245.5) return false; + if (f != 245.5) return false; + f /= 0.5; + if (f != 491.) return false; + f += -40; + if (f != 451.) return false; + return true; + } + static_assert(test_float(), ""); + + constexpr bool test_ptr() { + int arr[123] = {}; + int *p = arr; + if ((p += 4) != &arr[4]) return false; + if (p != &arr[4]) return false; + p += -1; + if (p != &arr[3]) return false; + if ((p -= -10) != &arr[13]) return false; + if (p != &arr[13]) return false; + p -= 11; + if (p != &arr[2]) return false; + return true; + } + static_assert(test_ptr(), ""); + + template<typename T> + constexpr bool test_overflow() { + T a = 1; + while (a != a / 2) + a *= 2; // expected-note {{value 2147483648 is outside the range}} expected-note {{ 9223372036854775808 }} expected-note {{floating point arithmetic produces an infinity}} + return true; + } + + static_assert(test_overflow<int>(), ""); // expected-error {{constant}} expected-note {{call}} + static_assert(test_overflow<unsigned>(), ""); // ok, unsigned overflow is defined + static_assert(test_overflow<short>(), ""); // ok, short is promoted to int before multiplication + static_assert(test_overflow<unsigned short>(), ""); // ok + static_assert(test_overflow<unsigned long long>(), ""); // ok + static_assert(test_overflow<long long>(), ""); // expected-error {{constant}} expected-note {{call}} + static_assert(test_overflow<float>(), ""); // expected-error {{constant}} expected-note {{call}} + + constexpr short test_promotion(short k) { + short s = k; + s *= s; + return s; + } + static_assert(test_promotion(100) == 10000, ""); + static_assert(test_promotion(200) == -25536, ""); + static_assert(test_promotion(256) == 0, ""); + + constexpr const char *test_bounds(const char *p, int o) { + return p += o; // expected-note {{element 5 of}} expected-note {{element -1 of}} expected-note {{element 1000 of}} + } + static_assert(test_bounds("foo", 0)[0] == 'f', ""); + static_assert(test_bounds("foo", 3)[0] == 0, ""); + static_assert(test_bounds("foo", 4)[-3] == 'o', ""); + static_assert(test_bounds("foo" + 4, -4)[0] == 'f', ""); + static_assert(test_bounds("foo", 5) != 0, ""); // expected-error {{constant}} expected-note {{call}} + static_assert(test_bounds("foo", -1) != 0, ""); // expected-error {{constant}} expected-note {{call}} + static_assert(test_bounds("foo", 1000) != 0, ""); // expected-error {{constant}} expected-note {{call}} +} + namespace loops { constexpr int fib_loop(int a) { int f_k = 0, f_k_plus_one = 1; @@ -407,7 +501,7 @@ namespace loops { int arr[] = { 1, 2, 3, 4, 5 }; int sum = 0; for (int x : arr) - sum = sum + x; + sum += x; return sum; } static_assert(range_for() == 15, ""); @@ -450,10 +544,370 @@ namespace loops { array<int, 5> arr { 1, 2, 3, 4, 5 }; int sum = 0; for (int k : arr) { - sum = sum + k; + sum += k; if (sum > 8) break; } return sum; } static_assert(range_for_2() == 10, ""); } + +namespace assignment_op { + struct A { + constexpr A() : n(5) {} + int n; + struct B { + int k = 1; + union U { + constexpr U() : y(4) {} + int x; + int y; + } u; + } b; + }; + constexpr bool testA() { + A a, b; + a.n = 7; + a.b.u.y = 5; + b = a; + return b.n == 7 && b.b.u.y == 5 && b.b.k == 1; + } + static_assert(testA(), ""); + + struct B { + bool assigned = false; + constexpr B &operator=(const B&) { + assigned = true; + return *this; + } + }; + struct C : B { + B b; + int n = 5; + }; + constexpr bool testC() { + C c, d; + c.n = 7; + d = c; + c.n = 3; + return d.n == 7 && d.assigned && d.b.assigned; + } + static_assert(testC(), ""); +} + +namespace switch_stmt { + constexpr int f(char k) { + bool b = false; + int z = 6; + switch (k) { + return -1; + case 0: + if (false) { + case 1: + z = 1; + for (; b;) { + return 5; + while (0) + case 2: return 2; + case 7: z = 7; + do case 6: { + return z; + if (false) + case 3: return 3; + case 4: z = 4; + } while (1); + case 5: b = true; + case 9: z = 9; + } + return z; + } else if (false) case 8: z = 8; + else if (false) { + case 10: + z = -10; + break; + } + else z = 0; + return z; + default: + return -1; + } + return -z; + } + static_assert(f(0) == 0, ""); + static_assert(f(1) == 1, ""); + static_assert(f(2) == 2, ""); + static_assert(f(3) == 3, ""); + static_assert(f(4) == 4, ""); + static_assert(f(5) == 5, ""); + static_assert(f(6) == 6, ""); + static_assert(f(7) == 7, ""); + static_assert(f(8) == 8, ""); + static_assert(f(9) == 9, ""); + static_assert(f(10) == 10, ""); + + // Check that we can continue an outer loop from within a switch. + constexpr bool contin() { + for (int n = 0; n != 10; ++n) { + switch (n) { + case 0: + ++n; + continue; + case 1: + return false; + case 2: + return true; + } + } + return false; + } + static_assert(contin(), ""); + + constexpr bool switch_into_for() { + int n = 0; + switch (n) { + for (; n == 1; ++n) { + return n == 1; + case 0: ; + } + } + return false; + } + static_assert(switch_into_for(), ""); + + constexpr void duff_copy(char *a, const char *b, int n) { + switch ((n - 1) % 8 + 1) { + for ( ; n; n = (n - 1) & ~7) { + case 8: a[n-8] = b[n-8]; + case 7: a[n-7] = b[n-7]; + case 6: a[n-6] = b[n-6]; + case 5: a[n-5] = b[n-5]; + case 4: a[n-4] = b[n-4]; + case 3: a[n-3] = b[n-3]; + case 2: a[n-2] = b[n-2]; + case 1: a[n-1] = b[n-1]; + } + case 0: ; + } + } + + constexpr bool test_copy(const char *str, int n) { + char buffer[16] = {}; + duff_copy(buffer, str, n); + for (int i = 0; i != sizeof(buffer); ++i) + if (buffer[i] != (i < n ? str[i] : 0)) + return false; + return true; + } + static_assert(test_copy("foo", 0), ""); + static_assert(test_copy("foo", 1), ""); + static_assert(test_copy("foo", 2), ""); + static_assert(test_copy("hello world", 0), ""); + static_assert(test_copy("hello world", 7), ""); + static_assert(test_copy("hello world", 8), ""); + static_assert(test_copy("hello world", 9), ""); + static_assert(test_copy("hello world", 10), ""); + static_assert(test_copy("hello world", 10), ""); +} + +namespace deduced_return_type { + constexpr auto f() { return 0; } + template<typename T> constexpr auto g(T t) { return t; } + static_assert(f() == 0, ""); + static_assert(g(true), ""); +} + +namespace modify_temporary_during_construction { + struct A { int &&temporary; int x; int y; }; + constexpr int f(int &r) { r *= 9; return r - 12; } + // FIXME: The 'uninitialized' warning here is bogus. + constexpr A a = { 6, f(a.temporary), a.temporary }; // expected-warning {{uninitialized}} expected-note {{temporary created here}} + static_assert(a.x == 42, ""); + static_assert(a.y == 54, ""); + constexpr int k = a.temporary++; // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}} +} + +namespace std { + typedef decltype(sizeof(int)) size_t; + + template <class _E> + class initializer_list + { + const _E* __begin_; + size_t __size_; + + constexpr initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + constexpr initializer_list() : __begin_(nullptr), __size_(0) {} + + constexpr size_t size() const {return __size_;} + constexpr const _E* begin() const {return __begin_;} + constexpr const _E* end() const {return __begin_ + __size_;} + }; +} + +namespace InitializerList { + constexpr int sum(std::initializer_list<int> ints) { + int total = 0; + for (int n : ints) total += n; + return total; + } + static_assert(sum({1, 2, 3, 4, 5}) == 15, ""); +} + +namespace StmtExpr { + constexpr int f(int k) { + switch (k) { + case 0: + return 0; + + ({ + case 1: // expected-note {{not supported}} + return 1; + }); + } + } + static_assert(f(1) == 1, ""); // expected-error {{constant expression}} expected-note {{in call}} + + constexpr int g() { // expected-error {{never produces a constant}} + return ({ int n; n; }); // expected-note {{object of type 'int' is not initialized}} + } + + // FIXME: We should handle the void statement expression case. + constexpr int h() { // expected-error {{never produces a constant}} + ({ if (true) {} }); // expected-note {{not supported}} + return 0; + } +} + +namespace VirtualFromBase { + struct S1 { + virtual int f() const; + }; + struct S2 { + virtual int f(); + }; + template <typename T> struct X : T { + constexpr X() {} + double d = 0.0; + constexpr int f() { return sizeof(T); } + }; + + // Non-virtual f(), OK. + constexpr X<X<S1>> xxs1; + constexpr X<S1> *p = const_cast<X<X<S1>>*>(&xxs1); + static_assert(p->f() == sizeof(S1), ""); + + // Virtual f(), not OK. + constexpr X<X<S2>> xxs2; + constexpr X<S2> *q = const_cast<X<X<S2>>*>(&xxs2); + static_assert(q->f() == sizeof(X<S2>), ""); // expected-error {{constant expression}} expected-note {{virtual function call}} +} + +namespace Lifetime { + constexpr int &get(int &&r) { return r; } + constexpr int f() { + int &r = get(123); + return r; // expected-note {{read of object outside its lifetime}} + } + static_assert(f() == 123, ""); // expected-error {{constant expression}} expected-note {{in call}} + + constexpr int g() { + int *p = 0; + { + int n = 0; + p = &n; + n = 42; + } + *p = 123; // expected-note {{assignment to object outside its lifetime}} + return *p; + } + static_assert(g() == 42, ""); // expected-error {{constant expression}} expected-note {{in call}} + + constexpr int h(int n) { + int *p[4] = {}; + int &&r = 1; + p[0] = &r; + while (int a = 1) { + p[1] = &a; + for (int b = 1; int c = 1; ) { + p[2] = &b, p[3] = &c; + break; + } + break; + } + *p[n] = 0; // expected-note 3{{assignment to object outside its lifetime}} + return *p[n]; + } + static_assert(h(0) == 0, ""); // ok, lifetime-extended + static_assert(h(1) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}} + static_assert(h(2) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}} + static_assert(h(3) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}} + + // FIXME: This function should be treated as non-constant. + constexpr void lifetime_versus_loops() { + int *p = 0; + for (int i = 0; i != 2; ++i) { + int *q = p; + int n = 0; + p = &n; + if (i) + // This modifies the 'n' from the previous iteration of the loop outside + // its lifetime. + ++*q; + } + } + static_assert((lifetime_versus_loops(), true), ""); +} + +namespace Bitfields { + struct A { + bool b : 3; + int n : 4; + unsigned u : 5; + }; + constexpr bool test() { + A a {}; + a.b += 2; + --a.n; + --a.u; + a.n = -a.n * 3; + return a.b == false && a.n == 3 && a.u == 31; + } + static_assert(test(), ""); +} + +namespace PR17615 { + struct A { + int &&r; + constexpr A(int &&r) : r(static_cast<int &&>(r)) {} + constexpr A() : A(0) { + (void)+r; // expected-note {{outside its lifetime}} + } + }; + constexpr int k = A().r; // expected-error {{constant expression}} expected-note {{in call to}} +} + +namespace PR17331 { + template<typename T, unsigned int N> + constexpr T sum(const T (&arr)[N]) { + T result = 0; + for (T i : arr) + result += i; + return result; + } + + constexpr int ARR[] = { 1, 2, 3, 4, 5 }; + static_assert(sum(ARR) == 15, ""); +} |