// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -Wno-vla -fms-extensions -std=c++11 -verify=expected,both %s // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -Wno-vla -fms-extensions -std=c++20 -verify=expected,both %s // RUN: %clang_cc1 -std=c++11 -fms-extensions -Wno-vla -verify=ref,both %s // RUN: %clang_cc1 -std=c++20 -fms-extensions -Wno-vla -verify=ref,both %s #define INT_MIN (~__INT_MAX__) #define INT_MAX __INT_MAX__ typedef __INTPTR_TYPE__ intptr_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; static_assert(true, ""); static_assert(false, ""); // both-error{{failed}} static_assert(nullptr == nullptr, ""); static_assert(__null == __null, ""); static_assert(1 == 1, ""); static_assert(1 == 3, ""); // both-error{{failed}} constexpr void* v = nullptr; static_assert(__null == v, ""); constexpr int number = 10; static_assert(number == 10, ""); static_assert(number != 10, ""); // both-error{{failed}} \ // both-note{{evaluates to}} static_assert(__objc_yes, ""); static_assert(!__objc_no, ""); constexpr bool b = number; static_assert(b, ""); constexpr int one = true; static_assert(one == 1, ""); constexpr bool b2 = bool(); static_assert(!b2, ""); constexpr int Failed1 = 1 / 0; // both-error {{must be initialized by a constant expression}} \ // both-note {{division by zero}} \ // both-note {{declared here}} constexpr int Failed2 = Failed1 + 1; // both-error {{must be initialized by a constant expression}} \ // both-note {{declared here}} \ // both-note {{initializer of 'Failed1' is not a constant expression}} static_assert(Failed2 == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{initializer of 'Failed2' is not a constant expression}} const int x = *(volatile int*)0x1234; static_assert((void{}, true), ""); namespace ScalarTypes { constexpr int ScalarInitInt = int(); static_assert(ScalarInitInt == 0, ""); constexpr float ScalarInitFloat = float(); static_assert(ScalarInitFloat == 0.0f, ""); static_assert(decltype(nullptr)() == nullptr, ""); template constexpr T getScalar() { return T(); } static_assert(getScalar() == 0, ""); static_assert(getScalar() == 0.0, ""); static_assert(getScalar() == nullptr, ""); static_assert(getScalar() == nullptr, ""); enum E { First = 0, }; static_assert(getScalar() == First, ""); struct S { int v; }; constexpr int S::* MemberPtr = &S::v; static_assert(getScalar() == nullptr, ""); #if __cplusplus >= 201402L constexpr void Void(int n) { void(n + 1); void(); } constexpr int void_test = (Void(0), 1); static_assert(void_test == 1, ""); #endif } namespace IntegralCasts { constexpr int i = 12; constexpr unsigned int ui = i; static_assert(ui == 12, ""); constexpr unsigned int ub = !false; static_assert(ub == 1, ""); constexpr int si = ui; static_assert(si == 12, ""); constexpr int sb = true; static_assert(sb == 1, ""); constexpr int zero = 0; constexpr unsigned int uzero = 0; constexpr bool bs = i; static_assert(bs, ""); constexpr bool bu = ui; static_assert(bu, ""); constexpr bool ns = zero; static_assert(!ns, ""); constexpr bool nu = uzero; static_assert(!nu, ""); }; constexpr int UninitI; // both-error {{must be initialized by a constant expression}} constexpr int *UninitPtr; // both-error {{must be initialized by a constant expression}} constexpr bool getTrue() { return true; } constexpr bool getFalse() { return false; } constexpr void* getNull() { return nullptr; } constexpr int neg(int m) { return -m; } constexpr bool inv(bool b) { return !b; } static_assert(12, ""); static_assert(12 == -(-(12)), ""); static_assert(!false, ""); static_assert(!!true, ""); static_assert(!!true == !false, ""); static_assert(true == 1, ""); static_assert(false == 0, ""); static_assert(!5 == false, ""); static_assert(!0, ""); static_assert(-true, ""); static_assert(-false, ""); //both-error{{failed}} static_assert(~0 == -1, ""); static_assert(~1 == -2, ""); static_assert(~-1 == 0, ""); static_assert(~255 == -256, ""); static_assert(~INT_MIN == INT_MAX, ""); static_assert(~INT_MAX == INT_MIN, ""); static_assert(-(1 << 31), ""); // both-error {{not an integral constant expression}} \ // both-note {{outside the range of representable values}} namespace PrimitiveEmptyInitList { constexpr int a = {}; static_assert(a == 0, ""); constexpr bool b = {}; static_assert(!b, ""); constexpr double d = {}; static_assert(d == 0.0, ""); } enum E {}; constexpr E e = static_cast(0); static_assert(~e == -1, ""); constexpr int m = 10; constexpr const int *p = &m; static_assert(p != nullptr, ""); static_assert(*p == 10, ""); constexpr const int* getIntPointer() { return &m; } static_assert(getIntPointer() == &m, ""); static_assert(*getIntPointer() == 10, ""); constexpr int gimme(int k) { return k; } static_assert(gimme(5) == 5, ""); namespace PointerToBool { constexpr void *N = nullptr; constexpr bool B = N; static_assert(!B, ""); static_assert(!N, ""); constexpr float F = 1.0; constexpr const float *FP = &F; static_assert(FP, ""); static_assert(!!FP, ""); } namespace PointerComparison { struct S { int a, b; } s; constexpr void *null = 0; constexpr void *pv = (void*)&s.a; constexpr void *qv = (void*)&s.b; constexpr bool v1 = null < (int*)0; constexpr bool v2 = null < pv; // both-error {{must be initialized by a constant expression}} \ // both-note {{comparison between 'nullptr' and '&s.a' has unspecified value}} constexpr bool v3 = null == pv; // ok constexpr bool v4 = qv == pv; // ok constexpr bool v5 = qv >= pv; constexpr bool v8 = qv > (void*)&s.a; constexpr bool v6 = qv > null; // both-error {{must be initialized by a constant expression}} \ // both-note {{comparison between '&s.b' and 'nullptr' has unspecified value}} constexpr bool v7 = qv <= (void*)&s.b; // ok constexpr ptrdiff_t m = &m - &m; static_assert(m == 0, ""); constexpr ptrdiff_t m2 = (&m2 + 1) - (&m2 + 1); static_assert(m2 == 0, ""); constexpr long m3 = (&m3 + 1) - (&m3); static_assert(m3 == 1, ""); constexpr long m4 = &m4 + 2 - &m4; // both-error {{must be initialized by a constant expression}} \ // both-note {{cannot refer to element 2 of non-array object}} } namespace SizeOf { static_assert(alignof(char&) == 1, ""); constexpr int soint = sizeof(int); constexpr int souint = sizeof(unsigned int); static_assert(soint == souint, ""); static_assert(sizeof(&soint) == sizeof(void*), ""); static_assert(sizeof(&soint) == sizeof(nullptr), ""); static_assert(sizeof(long) == sizeof(unsigned long), ""); static_assert(sizeof(char) == sizeof(unsigned char), ""); constexpr int N = 4; constexpr int arr[N] = {1,2,3,4}; static_assert(sizeof(arr) == N * sizeof(int), ""); static_assert(sizeof(arr) == N * sizeof(arr[0]), ""); constexpr bool arrB[N] = {true, true, true, true}; static_assert(sizeof(arrB) == N * sizeof(bool), ""); static_assert(sizeof(bool) == 1, ""); static_assert(sizeof(char) == 1, ""); constexpr int F = sizeof(void); // both-error{{incomplete type 'void'}} constexpr int F2 = sizeof(gimme); // both-error{{to a function type}} struct S { void func(); }; constexpr void (S::*Func)() = &S::func; static_assert(sizeof(Func) == sizeof(&S::func), ""); void func() { int n = 12; constexpr int oofda = sizeof(int[n++]); // both-error {{must be initialized by a constant expression}} } #if __cplusplus >= 201402L constexpr int IgnoredRejected() { // ref-error {{never produces a constant expression}} int n = 0; sizeof(int[n++]); // both-warning {{expression result unused}} \ // ref-note 2{{subexpression not valid in a constant expression}} return n; } /// FIXME: This is rejected because the parameter so sizeof() is not constant. /// produce a proper diagnostic. static_assert(IgnoredRejected() == 0, ""); // both-error {{not an integral constant expression}} \ // ref-note {{in call to 'IgnoredRejected()'}} #endif #if __cplusplus >= 202002L /// FIXME: The following code should be accepted. consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}} return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}} } constinit int var = foo(5); // ref-error {{not a constant expression}} \ // ref-note 2{{in call to}} \ // ref-error {{does not have a constant initializer}} \ // ref-note {{required by 'constinit' specifier}} \ // expected-error {{is not a constant expression}} \ // expected-error {{does not have a constant initializer}} \ // expected-note {{required by 'constinit' specifier}} \ #endif }; namespace rem { static_assert(2 % 2 == 0, ""); static_assert(2 % 1 == 0, ""); static_assert(-3 % 4 == -3, ""); static_assert(4 % -2 == 0, ""); static_assert(-3 % -4 == -3, ""); constexpr int zero() { return 0; } static_assert(10 % zero() == 20, ""); // both-error {{not an integral constant expression}} \ // both-note {{division by zero}} static_assert(true % true == 0, ""); static_assert(false % true == 0, ""); static_assert(true % false == 10, ""); // both-error {{not an integral constant expression}} \ // both-note {{division by zero}} constexpr int x = INT_MIN % - 1; // both-error {{must be initialized by a constant expression}} \ // both-note {{value 2147483648 is outside the range}} }; namespace div { constexpr int zero() { return 0; } static_assert(12 / 3 == 4, ""); static_assert(12 / zero() == 12, ""); // both-error {{not an integral constant expression}} \ // both-note {{division by zero}} static_assert(12 / -3 == -4, ""); static_assert(-12 / 3 == -4, ""); constexpr int LHS = 12; constexpr long unsigned RHS = 3; static_assert(LHS / RHS == 4, ""); constexpr int x = INT_MIN / - 1; // both-error {{must be initialized by a constant expression}} \ // both-note {{value 2147483648 is outside the range}} }; namespace cond { constexpr bool isEven(int n) { return n % 2 == 0 ? true : false; } static_assert(isEven(2), ""); static_assert(!isEven(3), ""); static_assert(isEven(100), ""); constexpr int M = 5 ? 10 : 20; static_assert(M == 10, ""); static_assert(5 ? 13 : 16 == 13, ""); static_assert(0 ? 13 : 16 == 16, ""); static_assert(number ?: -15 == number, ""); static_assert(0 ?: 100 == 100 , ""); #if __cplusplus >= 201402L constexpr int N = 20; constexpr int foo() { int m = N > 0 ? 5 : 10; return m == 5 ? isEven(m) : true; } static_assert(foo() == false, ""); constexpr int dontCallMe(unsigned m) { if (m == 0) return 0; return dontCallMe(m - 2); } // Can't call this because it will run into infinite recursion. constexpr int assertNotReached() { return dontCallMe(3); } constexpr int testCond() { return true ? 5 : assertNotReached(); } constexpr int testCond2() { return false ? assertNotReached() : 10; } static_assert(testCond() == 5, ""); static_assert(testCond2() == 10, ""); #endif }; namespace band { static_assert((10 & 1) == 0, ""); static_assert((10 & 10) == 10, ""); static_assert((1337 & -1) == 1337, ""); static_assert((0 & gimme(12)) == 0, ""); }; namespace bitOr { static_assert((10 | 1) == 11, ""); static_assert((10 | 10) == 10, ""); static_assert((1337 | -1) == -1, ""); static_assert((0 | gimme(12)) == 12, ""); static_assert((12 | true) == 13, ""); }; namespace bitXor { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wxor-used-as-pow" static_assert((10 ^ 1) == 11, ""); static_assert((10 ^ 10) == 0, ""); enum { ONE = 1, }; static_assert((1337 ^ -1) == -1338, ""); static_assert((0 | gimme(12)) == 12, ""); static_assert((12 ^ true) == 13, ""); static_assert((12 ^ ONE) == 13, ""); #pragma clang diagnostic pop }; #if __cplusplus >= 201402L constexpr bool IgnoredUnary() { bool bo = true; !bo; // both-warning {{expression result unused}} return bo; } static_assert(IgnoredUnary(), ""); #endif namespace strings { constexpr const char *S = "abc"; static_assert(S[0] == 97, ""); static_assert(S[1] == 98, ""); static_assert(S[2] == 99, ""); static_assert(S[3] == 0, ""); static_assert("foobar"[2] == 'o', ""); static_assert(2["foobar"] == 'o', ""); constexpr const wchar_t *wide = L"bar"; static_assert(wide[0] == L'b', ""); constexpr const char32_t *u32 = U"abc"; static_assert(u32[1] == U'b', ""); constexpr char32_t c = U'\U0001F60E'; static_assert(c == 0x0001F60EL, ""); constexpr char k = -1; static_assert(k == -1, ""); static_assert('\N{LATIN CAPITAL LETTER E}' == 'E', ""); static_assert('\t' == 9, ""); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmultichar" constexpr int mc = 'abc'; static_assert(mc == 'abc', ""); __WCHAR_TYPE__ wm = L'abc'; // both-error{{wide character literals may not contain multiple characters}} __WCHAR_TYPE__ wu = u'abc'; // both-error{{Unicode character literals may not contain multiple characters}} __WCHAR_TYPE__ wU = U'abc'; // both-error{{Unicode character literals may not contain multiple characters}} #if __cplusplus > 201103L __WCHAR_TYPE__ wu8 = u8'abc'; // both-error{{Unicode character literals may not contain multiple characters}} #endif #pragma clang diagnostic pop constexpr char foo[12] = "abc"; static_assert(foo[0] == 'a', ""); static_assert(foo[1] == 'b', ""); static_assert(foo[2] == 'c', ""); static_assert(foo[3] == 0, ""); static_assert(foo[11] == 0, ""); constexpr char foo2[] = "abc\0def"; static_assert(foo2[0] == 'a', ""); static_assert(foo2[3] == '\0', ""); static_assert(foo2[6] == 'f', ""); static_assert(foo2[7] == '\0', ""); static_assert(foo2[8] == '\0', ""); // both-error {{not an integral constant expression}} \ // both-note {{read of dereferenced one-past-the-end pointer}} constexpr char foo3[4] = "abc"; static_assert(foo3[3] == '\0', ""); static_assert(foo3[4] == '\0', ""); // both-error {{not an integral constant expression}} \ // both-note {{read of dereferenced one-past-the-end pointer}} constexpr char foo4[2] = "abcd"; // both-error {{initializer-string for char array is too long}} static_assert(foo4[0] == 'a', ""); static_assert(foo4[1] == 'b', ""); static_assert(foo4[2] == '\0', ""); // both-error {{not an integral constant expression}} \ // both-note {{read of dereferenced one-past-the-end pointer}} constexpr char foo5[12] = "abc\xff"; #if defined(__CHAR_UNSIGNED__) || __CHAR_BIT__ > 8 static_assert(foo5[3] == 255, ""); #else static_assert(foo5[3] == -1, ""); #endif }; #if __cplusplus > 201402L namespace IncDec { constexpr int zero() { int a = 0; a++; ++a; a--; --a; return a; } static_assert(zero() == 0, ""); constexpr int preInc() { int a = 0; return ++a; } static_assert(preInc() == 1, ""); constexpr int postInc() { int a = 0; return a++; } static_assert(postInc() == 0, ""); constexpr int preDec() { int a = 0; return --a; } static_assert(preDec() == -1, ""); constexpr int postDec() { int a = 0; return a--; } static_assert(postDec() == 0, ""); constexpr int three() { int a = 0; return ++a + ++a; // both-warning {{multiple unsequenced modifications to 'a'}} } static_assert(three() == 3, ""); constexpr bool incBool() { bool b = false; return ++b; // both-error {{ISO C++17 does not allow incrementing expression of type bool}} } static_assert(incBool(), ""); /// FIXME: The diagnostics for pre-inc/dec of pointers doesn't match the /// current interpreter. But they are stil OK. template constexpr int uninit() { T a; if constexpr (Inc) { if (Pre) ++a; // ref-note 3{{increment of uninitialized}} \ // expected-note 2{{increment of uninitialized}} \ // expected-note {{read of uninitialized}} else a++; // ref-note 2{{increment of uninitialized}} \ // expected-note 2{{increment of uninitialized}} } else { if (Pre) --a; // ref-note 3{{decrement of uninitialized}} \ // expected-note 2{{decrement of uninitialized}} \ // expected-note {{read of uninitialized}} else a--; // ref-note 2{{decrement of uninitialized}} \ // expected-note 2{{decrement of uninitialized}} } return 1; } static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'uninit()'}} constexpr int OverFlow() { // both-error {{never produces a constant expression}} int a = INT_MAX; ++a; // both-note 2{{is outside the range}} return -1; } static_assert(OverFlow() == -1, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'OverFlow()'}} constexpr int UnderFlow() { // both-error {{never produces a constant expression}} int a = INT_MIN; --a; // both-note 2{{is outside the range}} return -1; } static_assert(UnderFlow() == -1, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'UnderFlow()'}} constexpr int getTwo() { int i = 1; return (i += 1); } static_assert(getTwo() == 2, ""); constexpr int sub(int a) { return (a -= 2); } static_assert(sub(7) == 5, ""); constexpr int add(int a, int b) { a += b; // both-note {{is outside the range of representable values}} return a; } static_assert(add(1, 2) == 3, ""); static_assert(add(INT_MAX, 1) == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'add}} constexpr int sub(int a, int b) { a -= b; // both-note {{is outside the range of representable values}} return a; } static_assert(sub(10, 20) == -10, ""); static_assert(sub(INT_MIN, 1) == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'sub}} constexpr int subAll(int a) { return (a -= a); } static_assert(subAll(213) == 0, ""); constexpr bool BoolOr(bool b1, bool b2) { bool a; a = b1; a |= b2; return a; } static_assert(BoolOr(true, true), ""); static_assert(BoolOr(true, false), ""); static_assert(BoolOr(false, true), ""); static_assert(!BoolOr(false, false), ""); constexpr int IntOr(unsigned a, unsigned b) { unsigned r; r = a; r |= b; return r; } static_assert(IntOr(10, 1) == 11, ""); static_assert(IntOr(1337, -1) == -1, ""); static_assert(IntOr(0, 12) == 12, ""); constexpr bool BoolAnd(bool b1, bool b2) { bool a; a = b1; a &= b2; return a; } static_assert(BoolAnd(true, true), ""); static_assert(!BoolAnd(true, false), ""); static_assert(!BoolAnd(false, true), ""); static_assert(!BoolAnd(false, false), ""); constexpr int IntAnd(unsigned a, unsigned b) { unsigned r; r = a; r &= b; return r; } static_assert(IntAnd(10, 1) == 0, ""); static_assert(IntAnd(1337, -1) == 1337, ""); static_assert(IntAnd(0, 12) == 0, ""); constexpr bool BoolXor(bool b1, bool b2) { bool a; a = b1; a ^= b2; return a; } static_assert(!BoolXor(true, true), ""); static_assert(BoolXor(true, false), ""); static_assert(BoolXor(false, true), ""); static_assert(!BoolXor(false, false), ""); constexpr int IntXor(unsigned a, unsigned b) { unsigned r; r = a; r ^= b; return r; } static_assert(IntXor(10, 1) == 11, ""); static_assert(IntXor(10, 10) == 0, ""); static_assert(IntXor(12, true) == 13, ""); constexpr bool BoolRem(bool b1, bool b2) { bool a; a = b1; a %= b2; return a; } static_assert(!BoolRem(true, true), ""); static_assert(!BoolRem(false, true), ""); constexpr int IntRem(int a, int b) { int r; r = a; r %= b; // both-note {{division by zero}} \ // both-note {{outside the range of representable values}} return r; } static_assert(IntRem(2, 2) == 0, ""); static_assert(IntRem(2, 1) == 0, ""); static_assert(IntRem(9, 7) == 2, ""); static_assert(IntRem(5, 0) == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'IntRem(5, 0)'}} static_assert(IntRem(INT_MIN, -1) == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'IntRem}} constexpr bool BoolDiv(bool b1, bool b2) { bool a; a = b1; a /= b2; return a; } static_assert(BoolDiv(true, true), ""); static_assert(!BoolDiv(false, true), ""); constexpr int IntDiv(int a, int b) { int r; r = a; r /= b; // both-note {{division by zero}} \ // both-note {{outside the range of representable values}} return r; } static_assert(IntDiv(2, 2) == 1, ""); static_assert(IntDiv(12, 20) == 0, ""); static_assert(IntDiv(2, 1) == 2, ""); static_assert(IntDiv(9, 7) == 1, ""); static_assert(IntDiv(5, 0) == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'IntDiv(5, 0)'}} static_assert(IntDiv(INT_MIN, -1) == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'IntDiv}} constexpr bool BoolMul(bool b1, bool b2) { bool a; a = b1; a *= b2; return a; } static_assert(BoolMul(true, true), ""); static_assert(!BoolMul(true, false), ""); static_assert(!BoolMul(false, true), ""); static_assert(!BoolMul(false, false), ""); constexpr int IntMul(int a, int b) { int r; r = a; r *= b; // both-note {{is outside the range of representable values of type 'int'}} return r; } static_assert(IntMul(2, 2) == 4, ""); static_assert(IntMul(12, 20) == 240, ""); static_assert(IntMul(2, 1) == 2, ""); static_assert(IntMul(9, 7) == 63, ""); static_assert(IntMul(INT_MAX, 2) == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'IntMul}} constexpr int arr[] = {1,2,3}; constexpr int ptrInc1() { const int *p = arr; p += 2; return *p; } static_assert(ptrInc1() == 3, ""); constexpr int ptrInc2() { const int *p = arr; return *(p += 1); } static_assert(ptrInc2() == 2, ""); constexpr int ptrInc3() { // both-error {{never produces a constant expression}} const int *p = arr; p += 12; // both-note {{cannot refer to element 12 of array of 3 elements}} return *p; } constexpr int ptrIncDec1() { const int *p = arr; p += 2; p -= 1; return *p; } static_assert(ptrIncDec1() == 2, ""); constexpr int ptrDec1() { // both-error {{never produces a constant expression}} const int *p = arr; p -= 1; // both-note {{cannot refer to element -1 of array of 3 elements}} return *p; } /// This used to leave a 0 on the stack instead of the previous /// value of a. constexpr int bug1Inc() { int a = 3; int b = a++; return b; } static_assert(bug1Inc() == 3); constexpr int bug1Dec() { int a = 3; int b = a--; return b; } static_assert(bug1Dec() == 3); constexpr int f() { int a[] = {1,2}; int i = 0; // RHS should be evaluated before LHS, so this should // write to a[1]; a[i++] += ++i; return a[1]; } static_assert(f() == 3, ""); int nonconst(int a) { // both-note 4{{declared here}} static_assert(a++, ""); // both-error {{not an integral constant expression}} \ // both-note {{function parameter 'a' with unknown value cannot be used in a constant expression}} static_assert(a--, ""); // both-error {{not an integral constant expression}} \ // both-note {{function parameter 'a' with unknown value cannot be used in a constant expression}} static_assert(++a, ""); // both-error {{not an integral constant expression}} \ // both-note {{function parameter 'a' with unknown value cannot be used in a constant expression}} static_assert(--a, ""); // both-error {{not an integral constant expression}} \ // both-note {{function parameter 'a' with unknown value cannot be used in a constant expression}} } }; #endif namespace CompoundLiterals { constexpr int get5() { return (int[]){1,2,3,4,5}[4]; } static_assert(get5() == 5, ""); constexpr int get6(int f = (int[]){1,2,6}[2]) { // ref-note {{subexpression not valid in a constant expression}} \ // ref-note {{declared here}} return f; } static_assert(get6(6) == 6, ""); // FIXME: Who's right here? static_assert(get6() == 6, ""); // ref-error {{not an integral constant expression}} constexpr int x = (int){3}; static_assert(x == 3, ""); #if __cplusplus >= 201402L constexpr int getX() { int x = (int){3}; x = (int){5}; return x; } static_assert(getX() == 5, ""); #endif #if __cplusplus >= 202002L constexpr int get3() { int m; m = (int){3}; return m; } static_assert(get3() == 3, ""); #endif }; namespace TypeTraits { static_assert(__is_trivial(int), ""); static_assert(__is_trivial(float), ""); static_assert(__is_trivial(E), ""); struct S{}; static_assert(__is_trivial(S), ""); struct S2 { S2() {} }; static_assert(!__is_trivial(S2), ""); template struct S3 { constexpr bool foo() const { return __is_trivial(T); } }; struct T { ~T() {} }; struct U {}; static_assert(S3{}.foo(), ""); static_assert(!S3{}.foo(), ""); typedef int Int; typedef Int IntAr[10]; typedef const IntAr ConstIntAr; typedef ConstIntAr ConstIntArAr[4]; static_assert(__array_rank(IntAr) == 1, ""); static_assert(__array_rank(ConstIntArAr) == 2, ""); static_assert(__array_extent(IntAr, 0) == 10, ""); static_assert(__array_extent(ConstIntArAr, 0) == 4, ""); static_assert(__array_extent(ConstIntArAr, 1) == 10, ""); } #if __cplusplus >= 201402L constexpr int ignoredDecls() { static_assert(true, ""); struct F { int a; }; enum E { b }; using A = int; typedef int Z; return F{12}.a; } static_assert(ignoredDecls() == 12, ""); namespace DiscardExprs { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-value" typedef struct _GUID { __UINT32_TYPE__ Data1; __UINT16_TYPE__ Data2; __UINT16_TYPE__ Data3; __UINT8_TYPE__ Data4[8]; } GUID; class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) GuidType; struct A{ int a; }; constexpr int ignoredExprs() { (void)(1 / 2); A a{12}; a; (void)a; (a); /// Ignored MaterializeTemporaryExpr. struct B{ const int &a; }; (void)B{12}; (void)5, (void)6; 1 ? 0 : 1; __is_trivial(int); (int){1}; (int[]){1,2,3}; int arr[] = {1,2,3}; arr[0]; "a"; 'b'; sizeof(int); alignof(int); (short)5; (bool)1; __null; __builtin_offsetof(A, a); 1,2; (int)1.0; (float)1; (double)1.0f; (signed)4u; __uuidof(GuidType); __uuidof(number); // both-error {{cannot call operator __uuidof on a type with no GUID}} requires{false;}; return 0; } static_assert(ignoredExprs() == 0, ""); constexpr int oh_my(int x) { (int){ x++ }; return x; } static_assert(oh_my(0) == 1, ""); constexpr int oh_my2(int x) { int y{x++}; return x; } static_assert(oh_my2(0) == 1, ""); /// Ignored comma expressions still have their /// expressions evaluated. constexpr int Comma(int start) { int i = start; (void)i++; (void)i++,(void)i++; return i; } constexpr int Value = Comma(5); static_assert(Value == 8, ""); /// Ignored MemberExprs need to still evaluate the Base /// expr. constexpr A callme(int &i) { ++i; return A{}; } constexpr int ignoredMemberExpr() { int i = 0; callme(i).a; return i; } static_assert(ignoredMemberExpr() == 1, ""); template constexpr int foo() { I; return I; } static_assert(foo<3>() == 3, ""); struct ATemp { consteval ATemp ret_a() const { return ATemp{}; } }; void test() { int k = (ATemp().ret_a(), 0); } #pragma clang diagnostic pop } #endif namespace PredefinedExprs { #if __cplusplus >= 201402L template constexpr bool strings_match(const CharT *str1, const CharT *str2) { while (*str1 && *str2) { if (*str1++ != *str2++) return false; }; return *str1 == *str2; } void foo() { static_assert(strings_match(__FUNCSIG__, "void __cdecl PredefinedExprs::foo(void)"), ""); static_assert(strings_match(L__FUNCSIG__, L"void __cdecl PredefinedExprs::foo(void)"), ""); static_assert(strings_match(L__FUNCTION__, L"foo"), ""); static_assert(strings_match(__FUNCTION__, "foo"), ""); static_assert(strings_match(__func__, "foo"), ""); static_assert(strings_match(__PRETTY_FUNCTION__, "void PredefinedExprs::foo()"), ""); } constexpr char heh(unsigned index) { __FUNCTION__; // both-warning {{result unused}} __extension__ __FUNCTION__; // both-warning {{result unused}} return __FUNCTION__[index]; } static_assert(heh(0) == 'h', ""); static_assert(heh(1) == 'e', ""); static_assert(heh(2) == 'h', ""); #endif } namespace NE { constexpr int foo() noexcept { return 1; } static_assert(noexcept(foo()), ""); constexpr int foo2() { return 1; } static_assert(!noexcept(foo2()), ""); #if __cplusplus > 201402L constexpr int a() { int b = 0; (void)noexcept(++b); // both-warning {{expression with side effects has no effect in an unevaluated context}} return b; } static_assert(a() == 0, ""); #endif } namespace PointerCasts { constexpr int M = 10; constexpr const int *P = &M; constexpr intptr_t A = (intptr_t)P; // both-error {{must be initialized by a constant expression}} \ // both-note {{cast that performs the conversions of a reinterpret_cast}} int array[(intptr_t)(char*)0]; // both-warning {{variable length array folded to constant array}} } namespace InvalidDeclRefs { bool b00; // both-note {{declared here}} static_assert(b00, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of non-const variable}} float b01; // both-note {{declared here}} static_assert(b01, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of non-constexpr variable}} extern const int b02; // both-note {{declared here}} static_assert(b02, ""); // both-error {{not an integral constant expression}} \ // both-note {{initializer of 'b02' is unknown}} int b03 = 3; // both-note {{declared here}} static_assert(b03, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of non-const variable}} extern int var; constexpr int *varp = &var; // Ok. } namespace NonConstReads { void *p = nullptr; // both-note {{declared here}} static_assert(!p, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of non-constexpr variable 'p'}} int arr[!p]; // both-error {{variable length array}} int z; // both-note {{declared here}} static_assert(z == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of non-const variable 'z'}} } /// This test passes a MaterializedTemporaryExpr to evaluateAsRValue. /// That needs to return a null pointer after the lvalue-to-rvalue conversion. /// We used to fail to do that. namespace rdar8769025 { __attribute__((nonnull)) void f1(int * const &p); void test_f1() { f1(0); // both-warning{{null passed to a callee that requires a non-null argument}} } } namespace nullptrsub { void a() { char *f = (char *)0; f = (char *)((char *)0 - (char *)0); } } namespace incdecbool { #if __cplusplus >= 201402L constexpr bool incb(bool c) { if (!c) ++c; else {++c; c++; } #if __cplusplus >= 202002L // both-error@-3 {{ISO C++17 does not allow incrementing expression of type bool}} // both-error@-3 2{{ISO C++17 does not allow incrementing expression of type bool}} #else // both-warning@-6 {{incrementing expression of type bool is deprecated and incompatible with C++17}} #endif return c; } static_assert(incb(false), ""); static_assert(incb(true), ""); static_assert(incb(true) == 1, ""); #endif #if __cplusplus == 201103L constexpr bool foo() { // both-error {{never produces a constant expression}} bool b = true; // both-warning {{variable declaration in a constexpr function is a C++14 extension}} b++; // both-warning {{incrementing expression of type bool is deprecated and incompatible with C++17}} \ // both-warning {{use of this statement in a constexpr function is a C++14 extension}} \ // both-note 2{{subexpression not valid in a constant expression}} return b; } static_assert(foo() == 1, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} #endif } #if __cplusplus >= 201402L constexpr int externvar1() { // both-error {{never produces a constant expression}} extern char arr[]; // both-note {{declared here}} return arr[0]; // both-note {{read of non-constexpr variable 'arr'}} } namespace externarr { extern int arr[]; constexpr int *externarrindex = &arr[0]; /// No diagnostic. } namespace StmtExprs { constexpr int foo() { ({ int i; for (i = 0; i < 76; i++) {} i; // both-warning {{expression result unused}} }); return 76; } static_assert(foo() == 76, ""); namespace CrossFuncLabelDiff { constexpr long a(bool x) { return x ? 0 : (intptr_t)&&lbl + (0 && ({lbl: 0;})); } } } #endif namespace Extern { constexpr extern char Oops = 1; static_assert(Oops == 1, ""); #if __cplusplus >= 201402L struct NonLiteral { NonLiteral() {} }; NonLiteral nl; constexpr NonLiteral &ExternNonLiteralVarDecl() { extern NonLiteral nl; return nl; } static_assert(&ExternNonLiteralVarDecl() == &nl, ""); #endif struct A { int b; }; extern constexpr A a{12}; static_assert(a.b == 12, ""); } #if __cplusplus >= 201402L constexpr int StmtExprEval() { if (({ while (0); true; })) { return 2; } return 1; } static_assert(StmtExprEval() == 2, ""); constexpr int ReturnInStmtExpr() { // both-error {{never produces a constant expression}} return ({ return 1; // both-note 2{{this use of statement expressions is not supported in a constant expression}} 2; }); } static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} #endif namespace ComparisonAgainstOnePastEnd { int a, b; static_assert(&a + 1 == &b, ""); // both-error {{not an integral constant expression}} \ // both-note {{comparison against pointer '&a + 1' that points past the end of a complete object has unspecified value}} static_assert(&a == &b + 1, ""); // both-error {{not an integral constant expression}} \ // both-note {{comparison against pointer '&b + 1' that points past the end of a complete object has unspecified value}} static_assert(&a + 1 == &b + 1, ""); // both-error {{static assertion failed}} }; namespace NTTP { template constexpr unsigned size(const _Tp (&)[_Nm]) noexcept { return _Nm; } template static int write_padding() { static const char Chars[] = {C}; return size(Chars); } } #if __cplusplus >= 201402L namespace UnaryOpError { constexpr int foo() { int f = 0; ++g; // both-error {{use of undeclared identifier 'g'}} return f; } } #endif namespace VolatileReads { const volatile int b = 1; static_assert(b, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of volatile-qualified type 'const volatile int' is not allowed in a constant expression}} } #if __cplusplus >= 201703L namespace { struct C { int x; }; template void f() { const auto &[c] = *p; &c; // both-warning {{expression result unused}} } } #endif