434 lines · cpp
1// RUN: %clang_cc1 -std=c++23 -verify=expected,nointerpreter -Winvalid-constexpr %s2// RUN: %clang_cc1 -std=c++23 -verify=expected,interpreter %s -fexperimental-new-constant-interpreter -Winvalid-constexpr3 4using size_t = decltype(sizeof(0));5 6namespace std {7struct type_info {8 const char* name() const noexcept(true);9};10}11 12template <typename T, size_t N>13constexpr size_t array_size(T (&)[N]) {14 return N;15}16 17void use_array(int const (&gold_medal_mel)[2]) {18 constexpr auto gold = array_size(gold_medal_mel); // ok19}20 21constexpr auto olympic_mile() {22 const int ledecky = 1500;23 return []{ return ledecky; };24}25static_assert(olympic_mile()() == 1500); // ok26 27struct Swim {28 constexpr int phelps() { return 28; }29 virtual constexpr int lochte() { return 12; }30 int coughlin = 12;31};32 33constexpr int how_many(Swim& swam) {34 Swim* p = &swam;35 return (p + 1 - 1)->phelps();36}37 38void splash(Swim& swam) { // nointerpreter-note {{declared here}}39 static_assert(swam.phelps() == 28); // ok40 static_assert((&swam)->phelps() == 28); // ok41 Swim* pswam = &swam; // expected-note {{declared here}}42 static_assert(pswam->phelps() == 28); // expected-error {{static assertion expression is not an integral constant expression}} \43 // expected-note {{read of non-constexpr variable 'pswam' is not allowed in a constant expression}}44 static_assert(how_many(swam) == 28); // ok45 static_assert(Swim().lochte() == 12); // ok46 static_assert(swam.lochte() == 12); // expected-error {{static assertion expression is not an integral constant expression}} \47 // expected-note {{virtual function called on object 'swam' whose dynamic type is not constant}}48 static_assert(swam.coughlin == 12); // expected-error {{static assertion expression is not an integral constant expression}} \49 // nointerpreter-note {{read of variable 'swam' whose value is not known}}50}51 52extern Swim dc;53extern Swim& trident; // interpreter-note {{declared here}}54 55constexpr auto& sandeno = typeid(dc); // ok: can only be typeid(Swim)56constexpr auto& gallagher = typeid(trident); // expected-error {{constexpr variable 'gallagher' must be initialized by a constant expression}} \57 // nointerpreter-note {{typeid applied to object 'trident' whose dynamic type is not constant}} \58 // interpreter-note {{initializer of 'trident' is unknown}}59 60namespace explicitThis {61struct C {62 constexpr int b() { return 0; };63 64 constexpr int f(this C &c) {65 return c.b(); // ok66 }67 68 constexpr int g() {69 return f(); // ok70 }71};72 73void g() {74 C c;75 constexpr int x = c.f();76 constexpr int y = c.g();77}78}79 80namespace GH64376 {81template<int V>82struct Test {83 static constexpr int value = V;84};85 86int main() {87 Test<124> test;88 auto& test2 = test;89 90 if constexpr(test2.value > 3) {91 return 1;92 }93 94 return 0;95}96}97 98namespace GH30060 {99template<int V>100struct A {101 static constexpr int value = V;102};103 104template<class T>105static void test1(T &f) {106 A<f.value> bar;107}108 109void g() {110 A<42> f;111 112 test1(f);113}114}115 116namespace GH26067 {117struct A {118 constexpr operator int() const { return 42; }119};120 121template <int>122void f() {}123 124void test(const A& value) {125 f<value>();126}127 128int main() {129 A a{};130 test(a);131}132}133 134namespace GH34365 {135void g() {136 auto f = []() { return 42; };137 constexpr int x = f();138 [](auto f) { constexpr int x = f(); }(f);139 [](auto &f) { constexpr int x = f(); }(f);140 (void)[&]() { constexpr int x = f(); };141}142}143 144namespace GH118063 {145template <unsigned int N>146struct array {147 constexpr auto size() const -> unsigned int {148 return N;149 }150};151 152constexpr auto f(array<5> const& arr) {153 return array<arr.size()>{}.size();154}155 156int g() {157 array<5> arr {};158 static_assert(f(arr) == 5);159}160}161 162namespace GH128409 {163 int &ff();164 int &x = ff(); // expected-note {{declared here}}165 constinit int &z = x; // expected-error {{variable does not have a constant initializer}} \166 // expected-note {{required by 'constinit' specifier here}} \167 // expected-note {{initializer of 'x' is not a constant expression}}168}169 170namespace GH129845 {171 int &ff();172 int &x = ff(); // expected-note {{declared here}}173 struct A { int& x; };174 constexpr A g = {x}; // expected-error {{constexpr variable 'g' must be initialized by a constant expression}} \175 // expected-note {{initializer of 'x' is not a constant expression}}176 const A* gg = &g;177}178 179namespace extern_reference_used_as_unknown {180 extern int &x;181 int y;182 constinit int& g = (x,y); // expected-warning {{left operand of comma operator has no effect}}183}184 185namespace GH139452 {186struct Dummy {187 explicit operator bool() const noexcept { return true; }188};189 190struct Base { int error; };191struct Derived : virtual Base { };192 193template <class R>194constexpr R get_value() {195 const auto& derived_val = Derived{};196 if (derived_val.error != 0)197 /* nothing */;198 return R{};199}200 201int f() {202 return !get_value<Dummy>(); // contextually convert the function call result to bool203}204}205 206namespace uninit_reference_used {207 int y;208 constexpr int &r = r; // expected-error {{must be initialized by a constant expression}} \209 // expected-note {{initializer of 'r' is not a constant expression}} \210 // expected-note {{declared here}}211 constexpr int &rr = (rr, y);212 constexpr int &g() {213 int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \214 // nointerpreter-note {{use of reference outside its lifetime is not allowed in a constant expression}} \215 // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}216 return x;217 }218 constexpr int &gg = g(); // expected-error {{must be initialized by a constant expression}} \219 // expected-note {{in call to 'g()'}}220 constexpr int g2() {221 int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \222 // nointerpreter-note {{use of reference outside its lifetime is not allowed in a constant expression}} \223 // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}224 return x;225 }226 constexpr int gg2 = g2(); // expected-error {{must be initialized by a constant expression}} \227 // expected-note {{in call to 'g2()'}}228 constexpr int &g3() {229 int &x = (x,y); // expected-warning{{left operand of comma operator has no effect}} \230 // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \231 // nointerpreter-note {{use of reference outside its lifetime is not allowed in a constant expression}}232 return x;233 }234 constexpr int &gg3 = g3(); // nointerpreter-error {{must be initialized by a constant expression}} \235 // nointerpreter-note {{in call to 'g3()'}}236 typedef decltype(sizeof(1)) uintptr_t;237 constexpr uintptr_t g4() {238 uintptr_t * &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \239 // nointerpreter-note {{use of reference outside its lifetime is not allowed in a constant expression}} \240 // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}241 *(uintptr_t*)x = 10;242 return 3;243 }244 constexpr uintptr_t gg4 = g4(); // expected-error {{must be initialized by a constant expression}} \245 // expected-note {{in call to 'g4()'}}246 constexpr int g5() {247 int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \248 // nointerpreter-note {{use of reference outside its lifetime is not allowed in a constant expression}} \249 // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}250 return 3;251 }252 constexpr uintptr_t gg5 = g5(); // expected-error {{must be initialized by a constant expression}} \253 // expected-note {{in call to 'g5()'}}254 255}256 257namespace param_reference {258 constexpr int arbitrary = -12345;259 constexpr void f(const int &x = arbitrary) { // nointerpreter-note 3 {{declared here}} interpreter-note {{declared here}}260 constexpr const int &v1 = x; // expected-error {{must be initialized by a constant expression}} \261 // expected-note {{reference to 'x' is not a constant expression}}262 constexpr const int &v2 = (x, arbitrary); // expected-warning {{left operand of comma operator has no effect}}263 constexpr int v3 = x; // expected-error {{must be initialized by a constant expression}} \264 // nointerpreter-note {{read of variable 'x' whose value is not known}}265 static_assert(x==arbitrary); // expected-error {{static assertion expression is not an integral constant expression}} \266 // nointerpreter-note {{read of variable 'x' whose value is not known}}267 static_assert(&x - &x == 0);268 }269}270 271namespace dropped_note {272 extern int &x; // expected-note {{declared here}}273 constexpr int f() { return x; } // nointerpreter-note {{read of non-constexpr variable 'x'}} \274 // interpreter-note {{initializer of 'x' is unknown}}275 constexpr int y = f(); // expected-error {{constexpr variable 'y' must be initialized by a constant expression}} expected-note {{in call to 'f()'}}276}277 278namespace dynamic {279 struct A {virtual ~A();};280 struct B : A {};281 void f(A& a) { // interpreter-note 2{{declared here}}282 constexpr B* b = dynamic_cast<B*>(&a); // expected-error {{must be initialized by a constant expression}} \283 // nointerpreter-note {{dynamic_cast applied to object 'a' whose dynamic type is not constant}} \284 // interpreter-note {{pointer to 'a' is not a constant expression}}285 constexpr void* b2 = dynamic_cast<void*>(&a); // expected-error {{must be initialized by a constant expression}} \286 // nointerpreter-note {{dynamic_cast applied to object 'a' whose dynamic type is not constant}} \287 // interpreter-note {{pointer to 'a' is not a constant expression}}288 }289}290 291namespace unsized_array {292 void f(int (&a)[], int (&b)[], int (&c)[4]) {293 constexpr int t1 = a - a;294 constexpr int t2 = a - b; // expected-error {{constexpr variable 't2' must be initialized by a constant expression}} \295 // nointerpreter-note {{arithmetic involving unrelated objects '&a[0]' and '&b[0]' has unspecified value}} \296 // interpreter-note {{arithmetic involving unrelated objects 'a' and 'b' has unspecified value}}297 constexpr int t3 = a - &c[2]; // expected-error {{constexpr variable 't3' must be initialized by a constant expression}} \298 // nointerpreter-note {{arithmetic involving unrelated objects '&a[0]' and '&c[2]' has unspecified value}} \299 // interpreter-note {{arithmetic involving unrelated objects 'a' and '*((char*)&c + 8)' has unspecified value}}300 }301}302 303namespace casting {304 struct A {};305 struct B : A {};306 struct C : A {};307 extern A &a; // interpreter-note {{declared here}}308 extern B &b; // expected-note {{declared here}} interpreter-note 2 {{declared here}}309 constexpr B &t1 = (B&)a; // expected-error {{must be initialized by a constant expression}} \310 // nointerpreter-note {{cannot cast object of dynamic type 'A' to type 'B'}} \311 // interpreter-note {{initializer of 'a' is unknown}}312 constexpr B &t2 = (B&)(A&)b; // expected-error {{must be initialized by a constant expression}} \313 // nointerpreter-note {{initializer of 'b' is not a constant expression}} \314 // interpreter-note {{initializer of 'b' is unknown}}315 // FIXME: interpreter incorrectly rejects.316 constexpr bool t3 = &b + 1 == &(B&)(A&)b; // interpreter-error {{must be initialized by a constant expression}} \317 // interpreter-note {{initializer of 'b' is unknown}}318 constexpr C &t4 = (C&)(A&)b; // expected-error {{must be initialized by a constant expression}} \319 // nointerpreter-note {{cannot cast object of dynamic type 'B' to type 'C'}} \320 // interpreter-note {{initializer of 'b' is unknown}}321}322 323namespace pointer_comparisons {324 extern int &extern_n; // interpreter-note 4 {{declared here}}325 extern int &extern_n2;326 constexpr int f1(bool b, int& n) {327 if (b) {328 return &extern_n == &n;329 }330 return f1(true, n);331 }332 // FIXME: interpreter incorrectly rejects; both sides are the same constexpr-unknown value.333 static_assert(f1(false, extern_n)); // interpreter-error {{static assertion expression is not an integral constant expression}} \334 // interpreter-note {{initializer of 'extern_n' is unknown}}335 static_assert(&extern_n != &extern_n2); // expected-error {{static assertion expression is not an integral constant expression}} \336 // nointerpreter-note {{comparison between pointers to unrelated objects '&extern_n' and '&extern_n2' has unspecified value}} \337 // interpreter-note {{initializer of 'extern_n' is unknown}}338 void f2(const int &n) {339 constexpr int x = &x == &n; // nointerpreter-error {{must be initialized by a constant expression}} \340 // nointerpreter-note {{comparison between pointers to unrelated objects '&x' and '&n' has unspecified value}}341 // Distinct variables are not equal, even if they're local variables.342 constexpr int y = &x == &y;343 static_assert(!y);344 }345 constexpr int f3() {346 int x;347 return &x == &extern_n; // nointerpreter-note {{comparison between pointers to unrelated objects '&x' and '&extern_n' has unspecified value}} \348 // interpreter-note {{initializer of 'extern_n' is unknown}}349 }350 static_assert(!f3()); // expected-error {{static assertion expression is not an integral constant expression}} \351 // expected-note {{in call to 'f3()'}}352 constexpr int f4() {353 int *p = new int;354 bool b = p == &extern_n; // nointerpreter-note {{comparison between pointers to unrelated objects '&{*new int#0}' and '&extern_n' has unspecified value}} \355 // interpreter-note {{initializer of 'extern_n' is unknown}}356 delete p;357 return b;358 }359 static_assert(!f4()); // expected-error {{static assertion expression is not an integral constant expression}} \360 // expected-note {{in call to 'f4()'}}361}362 363namespace GH149188 {364namespace enable_if_1 {365 template <__SIZE_TYPE__ N>366 constexpr void foo(const char (&Str)[N])367 __attribute((enable_if(__builtin_strlen(Str), ""))) {}368 369 void x() {370 foo("1234");371 }372}373 374namespace enable_if_2 {375 constexpr const char (&f())[];376 extern const char (&Str)[];377 constexpr int foo()378 __attribute((enable_if(__builtin_strlen(Str), "")))379 {return __builtin_strlen(Str);}380 381 constexpr const char (&f())[] {return "a";}382 constexpr const char (&Str)[] = f();383 void x() {384 constexpr int x = foo();385 }386}387}388 389namespace GH150015 {390 extern int (& c)[8]; // interpreter-note {{declared here}}391 constexpr int x = c <= c+8; // interpreter-error {{constexpr variable 'x' must be initialized by a constant expression}} \392 // interpreter-note {{initializer of 'c' is unknown}}393 394 struct X {};395 struct Y {};396 struct Z : X, Y {};397 extern Z &z; // interpreter-note{{declared here}}398 constexpr int bases = (void*)(X*)&z <= (Y*)&z; // expected-error {{constexpr variable 'bases' must be initialized by a constant expression}} \399 // nointerpreter-note {{comparison of addresses of subobjects of different base classes has unspecified value}} \400 // interpreter-note {{initializer of 'z' is unknown}}401}402 403namespace InvalidConstexprFn {404 // Make sure we don't trigger -Winvalid-constexpr incorrectly.405 constexpr bool same_address(const int &a, const int &b) { return &a == &b; }406 constexpr int next_element(const int &p) { return (&p)[2]; }407 408 struct Base {};409 struct Derived : Base { int n; };410 constexpr int get_derived_member(const Base& b) { return static_cast<const Derived&>(b).n; }411 412 struct PolyBase {413 constexpr virtual int get() const { return 0; }414 };415 struct PolyDerived : PolyBase {416 constexpr int get() const override { return 1; }417 };418 constexpr int virtual_call(const PolyBase& b) { return b.get(); }419 constexpr auto* type(const PolyBase& b) { return &typeid(b); }420 constexpr const void* dyncast(const PolyBase& b) { return dynamic_cast<const void*>(&b); }421 constexpr int sub(const int (&a)[], const int (&b)[]) { return a-b; }422 constexpr const int* add(const int &a) { return &a+3; }423 424 constexpr int arr[3]{0, 1, 2};425 static_assert(same_address(arr[1], arr[1]));426 static_assert(next_element(arr[0]) == 2);427 static_assert(get_derived_member(Derived{}) == 0);428 static_assert(virtual_call(PolyDerived{}) == 1);429 static_assert(type(PolyDerived{}) != nullptr);430 static_assert(dyncast(PolyDerived{}) != nullptr);431 static_assert(sub(arr, arr) == 0);432 static_assert(add(arr[0]) == &arr[3]);433}434