side-effect, so that we don't allow speculative evaluation of such expressions during code generation. This caused a diagnostic quality regression, so fix constant expression diagnostics to prefer either the first "can't be constant folded" diagnostic or the first "not a constant expression" diagnostic depending on the kind of evaluation we're doing. This was always the intent, but didn't quite work correctly before. This results in certain initializers that used to be constant initializers to no longer be; in particular, things like: float f = 1e100; are no longer accepted in C. This seems appropriate, as such constructs would lead to code being executed if sanitizers are enabled. llvm-svn: 254574
105 lines
4.6 KiB
C++
105 lines
4.6 KiB
C++
// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -triple x86_64-linux-gnu
|
|
|
|
struct S;
|
|
constexpr int extract(const S &s);
|
|
|
|
struct S {
|
|
constexpr S() : n(extract(*this)), m(0) {} // expected-note {{in call to 'extract(s1)'}}
|
|
constexpr S(int k) : n(k), m(extract(*this)) {}
|
|
int n, m;
|
|
};
|
|
|
|
constexpr int extract(const S &s) { return s.n; } // expected-note {{read of object outside its lifetime is not allowed in a constant expression}}
|
|
|
|
constexpr S s1; // ok
|
|
void f() {
|
|
constexpr S s1; // expected-error {{constant expression}} expected-note {{in call to 'S()'}}
|
|
constexpr S s2(10);
|
|
}
|
|
|
|
typedef __attribute__((vector_size(16))) int vector_int;
|
|
|
|
struct T {
|
|
constexpr T() : arr() {}
|
|
int arr[4];
|
|
};
|
|
struct U : T {
|
|
constexpr U(const int *p) : T(), another(), p(p) {}
|
|
constexpr U(const U &u) : T(), another(), p(u.p) {}
|
|
T another;
|
|
const int *p;
|
|
};
|
|
constexpr U u1(&u1.arr[2]);
|
|
|
|
constexpr int test_printing(int a, float b, _Complex int c, _Complex float d,
|
|
int *e, int &f, vector_int g, U h) {
|
|
return *e; // expected-note {{read of non-constexpr variable 'u2'}}
|
|
}
|
|
U u2(0); // expected-note {{here}}
|
|
static_assert(test_printing(12, 39.762, 3 + 4i, 12.9 + 3.6i, &u2.arr[4], u2.another.arr[2], (vector_int){5, 1, 2, 3}, u1) == 0, ""); // \
|
|
expected-error {{constant expression}} \
|
|
expected-note {{in call to 'test_printing(12, 3.976200e+01, 3+4i, 1.290000e+01+3.600000e+00i, &u2.T::arr[4], u2.another.arr[2], {5, 1, 2, 3}, {{{}}, {{}}, &u1.T::arr[2]})'}}
|
|
|
|
struct V {
|
|
// FIXME: when we can generate these as constexpr constructors, remove the
|
|
// explicit definitions.
|
|
constexpr V() : arr{[255] = 42} {}
|
|
constexpr V(const V &v) : arr{[255] = 42} {}
|
|
int arr[256];
|
|
};
|
|
constexpr V v;
|
|
constexpr int get(const int *p) { return *p; } // expected-note {{read of dereferenced one-past-the-end pointer}}
|
|
constexpr int passLargeArray(V v) { return get(v.arr+256); } // expected-note {{in call to 'get(&v.arr[256])'}}
|
|
static_assert(passLargeArray(v) == 0, ""); // expected-error {{constant expression}} expected-note {{in call to 'passLargeArray({{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...}})'}}
|
|
|
|
union Union {
|
|
constexpr Union(int n) : b(n) {}
|
|
constexpr Union(const Union &u) : b(u.b) {}
|
|
int a, b;
|
|
};
|
|
constexpr Union myUnion = 76;
|
|
|
|
constexpr int badness(Union u) { return u.a + u.b; } // expected-note {{read of member 'a' of union with active member 'b'}}
|
|
static_assert(badness(myUnion), ""); // expected-error {{constant expression}} \
|
|
expected-note {{in call to 'badness({.b = 76})'}}
|
|
|
|
struct MemPtrTest {
|
|
int n;
|
|
void f();
|
|
};
|
|
MemPtrTest mpt; // expected-note {{here}}
|
|
constexpr int MemPtr(int (MemPtrTest::*a), void (MemPtrTest::*b)(), int &c) {
|
|
return c; // expected-note {{read of non-constexpr variable 'mpt'}}
|
|
}
|
|
static_assert(MemPtr(&MemPtrTest::n, &MemPtrTest::f, mpt.*&MemPtrTest::n), ""); // expected-error {{constant expression}} \
|
|
expected-note {{in call to 'MemPtr(&MemPtrTest::n, &MemPtrTest::f, mpt.n)'}}
|
|
|
|
template<typename CharT>
|
|
constexpr CharT get(const CharT *p) { return p[-1]; } // expected-note 5{{}}
|
|
|
|
constexpr char c = get("test\0\\\"\t\a\b\234"); // \
|
|
expected-error {{}} expected-note {{"test\000\\\"\t\a\b\234"}}
|
|
constexpr char c8 = get(u8"test\0\\\"\t\a\b\234"); // \
|
|
expected-error {{}} expected-note {{u8"test\000\\\"\t\a\b\234"}}
|
|
constexpr char16_t c16 = get(u"test\0\\\"\t\a\b\234\u1234"); // \
|
|
expected-error {{}} expected-note {{u"test\000\\\"\t\a\b\234\u1234"}}
|
|
constexpr char32_t c32 = get(U"test\0\\\"\t\a\b\234\u1234\U0010ffff"); // \
|
|
expected-error {{}} expected-note {{U"test\000\\\"\t\a\b\234\u1234\U0010FFFF"}}
|
|
constexpr wchar_t wc = get(L"test\0\\\"\t\a\b\234\u1234\xffffffff"); // \
|
|
expected-error {{}} expected-note {{L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF"}}
|
|
|
|
constexpr char32_t c32_err = get(U"\U00110000"); // expected-error {{invalid universal character}}
|
|
|
|
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
|
|
|
|
typedef decltype(sizeof(int)) LabelDiffTy;
|
|
constexpr LabelDiffTy mulBy3(LabelDiffTy x) { return x * 3; } // expected-note {{subexpression}}
|
|
void LabelDiffTest() {
|
|
static_assert(mulBy3(fold((LabelDiffTy)&&a-(LabelDiffTy)&&b)) == 3, ""); // expected-error {{constant expression}} expected-note {{call to 'mulBy3(&&a - &&b)'}}
|
|
a:b:return;
|
|
}
|
|
|
|
constexpr bool test_bool_printing(bool b) { return 1 / !(2*b | !(2*b)); } // expected-note 2{{division by zero}}
|
|
constexpr bool test_bool_0 = test_bool_printing(false); // expected-error {{constant expr}} expected-note {{in call to 'test_bool_printing(false)'}}
|
|
constexpr bool test_bool_1 = test_bool_printing(true); // expected-error {{constant expr}} expected-note {{in call to 'test_bool_printing(true)'}}
|