1214 lines · cpp
1// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=both,expected -fcxx-exceptions %s -DNEW_INTERP -fexperimental-new-constant-interpreter2// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=both,ref -fcxx-exceptions %s3 4void test_alignas_operand() {5 alignas(8) char dummy;6 static_assert(__alignof(dummy) == 8);7}8 9constexpr int getMinus5() {10 int a = 10;11 a = -5;12 int *p = &a;13 return *p;14}15static_assert(getMinus5() == -5, "");16 17constexpr int assign() {18 int m = 10;19 int k = 12;20 21 m = (k = 20);22 23 return m;24}25static_assert(assign() == 20, "");26 27 28constexpr int pointerAssign() {29 int m = 10;30 int *p = &m;31 32 *p = 12; // modifies m33 34 return m;35}36static_assert(pointerAssign() == 12, "");37 38constexpr int pointerDeref() {39 int m = 12;40 int *p = &m;41 42 return *p;43}44static_assert(pointerDeref() == 12, "");45 46constexpr int pointerAssign2() {47 int m = 10;48 int *p = &m;49 int **pp = &p;50 51 **pp = 12;52 53 int v = **pp;54 55 return v;56}57static_assert(pointerAssign2() == 12, "");58 59constexpr int unInitLocal() {60 int a;61 return a; // both-note {{read of uninitialized object}}62}63static_assert(unInitLocal() == 0, ""); // both-error {{not an integral constant expression}} \64 // both-note {{in call to 'unInitLocal()'}}65 66constexpr int initializedLocal() {67 int a;68 a = 20;69 return a;70}71static_assert(initializedLocal() == 20);72 73constexpr int initializedLocal2() {74 int a[2];75 return *a; // both-note {{read of uninitialized object is not allowed in a constant expression}}76}77static_assert(initializedLocal2() == 20); // both-error {{not an integral constant expression}} \78 // both-note {{in call to}}79 80 81struct Int { int a; };82constexpr int initializedLocal3() {83 Int i;84 return i.a; // both-note {{read of uninitialized object is not allowed in a constant expression}}85}86static_assert(initializedLocal3() == 20); // both-error {{not an integral constant expression}} \87 // both-note {{in call to}}88 89 90 91#if 092// FIXME: This code should be rejected because we pass an uninitialized value93// as a function parameter.94constexpr int inc(int a) { return a + 1; }95constexpr int f() {96 int i;97 return inc(i);98}99static_assert(f());100#endif101 102/// Distinct literals have distinct addresses.103/// see https://github.com/llvm/llvm-project/issues/58754104constexpr auto foo(const char *p) { return p; }105constexpr auto p1 = "test1";106constexpr auto p2 = "test2";107 108constexpr bool b1 = foo(p1) == foo(p1);109static_assert(b1);110 111constexpr bool b2 = foo(p1) == foo(p2);112static_assert(!b2);113 114constexpr auto name1() { return "name1"; }115constexpr auto name2() { return "name2"; }116 117constexpr auto b3 = name1() == name1(); // ref-error {{must be initialized by a constant expression}} \118 // ref-note {{comparison of addresses of potentially overlapping literals}}119constexpr auto b4 = name1() == name2();120static_assert(!b4);121 122constexpr auto bar(const char *p) { return p + __builtin_strlen(p); }123constexpr auto b5 = bar(p1) == p1;124static_assert(!b5);125constexpr auto b6 = bar(p1) == ""; // both-error {{must be initialized by a constant expression}} \126 // both-note {{comparison of addresses of potentially overlapping literals}}127constexpr auto b7 = bar(p1) + 1 == ""; // both-error {{must be initialized by a constant expression}} \128 // both-note {{comparison against pointer '&"test1"[6]' that points past the end of a complete object has unspecified value}}129 130namespace UninitializedFields {131 class A {132 public:133 int a; // both-note 4{{subobject declared here}}134 constexpr A() {}135 };136 constexpr A a; // both-error {{must be initialized by a constant expression}} \137 // both-note {{subobject 'a' is not initialized}}138 constexpr A aarr[2]; // both-error {{must be initialized by a constant expression}} \139 // both-note {{subobject 'a' is not initialized}}140 class F {141 public:142 int f; // both-note 3{{subobject declared here}}143 144 constexpr F() {}145 constexpr F(bool b) {146 if (b)147 f = 42;148 }149 };150 151 constexpr F foo[2] = {true}; // both-error {{must be initialized by a constant expression}} \152 // both-note {{subobject 'f' is not initialized}}153 constexpr F foo2[3] = {true, false, true}; // both-error {{must be initialized by a constant expression}} \154 // both-note {{subobject 'f' is not initialized}}155 constexpr F foo3[3] = {true, true, F()}; // both-error {{must be initialized by a constant expression}} \156 // both-note {{subobject 'f' is not initialized}}157 158 159 160 class Base {161 public:162 bool b;163 int a; // both-note {{subobject declared here}}164 constexpr Base() : b(true) {}165 };166 167 class Derived : public Base {168 public:169 constexpr Derived() : Base() {} };170 171 constexpr Derived D; // both-error {{must be initialized by a constant expression}} \172 // both-note {{subobject 'a' is not initialized}}173 174 class C2 {175 public:176 A a;177 constexpr C2() {} };178 constexpr C2 c2; // both-error {{must be initialized by a constant expression}} \179 // both-note {{subobject 'a' is not initialized}}180 181 class C3 {182 public:183 A a[2];184 constexpr C3() {}185 };186 constexpr C3 c3; // both-error {{must be initialized by a constant expression}} \187 // both-note {{subobject 'a' is not initialized}}188 189 class C4 {190 public:191 bool B[2][3]; // both-note {{subobject declared here}}192 constexpr C4(){}193 };194 constexpr C4 c4; // both-error {{must be initialized by a constant expression}} \195 // both-note {{subobject 'B' is not initialized}}196};197 198namespace ConstThis {199 class Foo {200 const int T = 12; // both-note {{declared const here}}201 int a;202 public:203 constexpr Foo() {204 this->a = 10;205 T = 13; // both-error {{cannot assign to non-static data member 'T' with const-qualified type}}206 }207 };208 constexpr Foo F; // both-error {{must be initialized by a constant expression}}209 210 211 class FooDtor {212 int a;213 public:214 constexpr FooDtor() {215 this->a = 10;216 }217 constexpr ~FooDtor() {218 this->a = 12;219 }220 };221 222 constexpr int foo() {223 const FooDtor f;224 return 0;225 }226 static_assert(foo() == 0);227 228 template <bool Good>229 struct ctor_test {230 int a = 0;231 232 constexpr ctor_test() {233 if (Good)234 a = 10;235 int local = 100 / a; // both-note {{division by zero}}236 }237 };238 239 template <bool Good>240 struct dtor_test {241 int a = 0;242 243 constexpr dtor_test() = default;244 constexpr ~dtor_test() {245 if (Good)246 a = 10;247 int local = 100 / a; // both-note {{division by zero}}248 }249 };250 251 constexpr ctor_test<true> good_ctor;252 constexpr dtor_test<true> good_dtor;253 254 constexpr ctor_test<false> bad_ctor; // both-error {{must be initialized by a constant expression}} \255 // both-note {{in call to}}256 constexpr dtor_test<false> bad_dtor; // both-error {{must have constant destruction}} \257 // both-note {{in call to}}258};259 260namespace BaseInit {261 struct Base {262 int a;263 };264 265 struct Intermediate : Base {266 int b;267 };268 269 struct Final : Intermediate {270 int c;271 272 constexpr Final(int a, int b, int c) : c(c) {}273 };274 275 static_assert(Final{1, 2, 3}.c == 3, ""); // OK276 static_assert(Final{1, 2, 3}.a == 0, ""); // both-error {{not an integral constant expression}} \277 // both-note {{read of uninitialized object}}278 279 280 struct Mixin {281 int b;282 283 constexpr Mixin() = default;284 constexpr Mixin(int b) : b(b) {}285 };286 287 struct Final2 : Base, Mixin {288 int c;289 290 constexpr Final2(int a, int b, int c) : Mixin(b), c(c) {}291 constexpr Final2(int a, int b, int c, bool) : c(c) {}292 };293 294 static_assert(Final2{1, 2, 3}.c == 3, ""); // OK295 static_assert(Final2{1, 2, 3}.b == 2, ""); // OK296 static_assert(Final2{1, 2, 3}.a == 0, ""); // both-error {{not an integral constant expression}} \297 // both-note {{read of uninitialized object}}298 299 300 struct Mixin3 {301 int b;302 };303 304 struct Final3 : Base, Mixin3 {305 int c;306 307 constexpr Final3(int a, int b, int c) : c(c) { this->b = b; }308 constexpr Final3(int a, int b, int c, bool) : c(c) {}309 };310 311 static_assert(Final3{1, 2, 3}.c == 3, ""); // OK312 static_assert(Final3{1, 2, 3}.b == 2, ""); // OK313 static_assert(Final3{1, 2, 3}.a == 0, ""); // both-error {{not an integral constant expression}} \314 // both-note {{read of uninitialized object}}315};316 317namespace Destructors {318 319 class Inc final {320 public:321 int &I;322 constexpr Inc(int &I) : I(I) {}323 constexpr ~Inc() {324 I++;325 }326 };327 328 class Dec final {329 public:330 int &I;331 constexpr Dec(int &I) : I(I) {}332 constexpr ~Dec() {333 I--;334 }335 };336 337 338 339 constexpr int m() {340 int i = 0;341 {342 Inc f1(i);343 Inc f2(i);344 Inc f3(i);345 }346 return i;347 }348 static_assert(m() == 3, "");349 350 351 constexpr int C() {352 int i = 0;353 354 while (i < 10) {355 Inc inc(i);356 continue;357 Dec dec(i);358 }359 return i;360 }361 static_assert(C() == 10, "");362 363 364 constexpr int D() {365 int i = 0;366 367 {368 Inc i1(i);369 {370 Inc i2(i);371 return i;372 }373 }374 375 return i;376 }377 static_assert(D() == 0, "");378 379 constexpr int E() {380 int i = 0;381 382 for(;;) {383 Inc i1(i);384 break;385 }386 return i;387 }388 static_assert(E() == 1, "");389 390 391 /// FIXME: This should be rejected, since we call the destructor392 /// twice. However, GCC doesn't care either.393 constexpr int ManualDtor() {394 int i = 0;395 {396 Inc I(i); // ref-note {{destroying object 'I' whose lifetime has already ended}}397 I.~Inc();398 }399 return i;400 }401 static_assert(ManualDtor() == 1, ""); // expected-error {{static assertion failed}} \402 // expected-note {{evaluates to '2 == 1'}} \403 // ref-error {{not an integral constant expression}} \404 // ref-note {{in call to 'ManualDtor()'}}405 406 constexpr void doInc(int &i) {407 Inc I(i);408 return;409 }410 constexpr int testInc() {411 int i = 0;412 doInc(i);413 return i;414 }415 static_assert(testInc() == 1, "");416 constexpr void doInc2(int &i) {417 Inc I(i);418 // No return statement.419 }420 constexpr int testInc2() {421 int i = 0;422 doInc2(i);423 return i;424 }425 static_assert(testInc2() == 1, "");426 427 428 namespace DtorOrder {429 class A {430 public:431 int &I;432 constexpr A(int &I) : I(I) {}433 constexpr ~A() {434 I = 1337;435 }436 };437 438 class B : public A {439 public:440 constexpr B(int &I) : A(I) {}441 constexpr ~B() {442 I = 42;443 }444 };445 446 constexpr int foo() {447 int i = 0;448 {449 B b(i);450 }451 return i;452 }453 454 static_assert(foo() == 1337);455 }456 457 class FieldDtor1 {458 public:459 Inc I1;460 Inc I2;461 constexpr FieldDtor1(int &I) : I1(I), I2(I){}462 };463 464 constexpr int foo2() {465 int i = 0;466 {467 FieldDtor1 FD1(i);468 }469 return i;470 }471 472 static_assert(foo2() == 2);473 474 class FieldDtor2 {475 public:476 Inc Incs[3];477 constexpr FieldDtor2(int &I) : Incs{Inc(I), Inc(I), Inc(I)} {}478 };479 480 constexpr int foo3() {481 int i = 0;482 {483 FieldDtor2 FD2(i);484 }485 return i;486 }487 488 static_assert(foo3() == 3);489 490 struct ArrD {491 int index;492 int *arr;493 int &p;494 constexpr ~ArrD() {495 arr[p] = index;496 ++p;497 }498 };499 constexpr bool ArrayOrder() {500 int order[3] = {0, 0, 0};501 int p = 0;502 {503 ArrD ds[3] = {504 {1, order, p},505 {2, order, p},506 {3, order, p},507 };508 // ds will be destroyed.509 }510 return order[0] == 3 && order[1] == 2 && order[2] == 1;511 }512 static_assert(ArrayOrder());513 514 515 // Static members aren't destroyed.516 class Dec2 {517 public:518 int A = 0;519 constexpr ~Dec2() {520 A++;521 }522 };523 class Foo {524 public:525 static constexpr Dec2 a;526 static Dec2 b;527 };528 static_assert(Foo::a.A == 0);529 constexpr bool f() {530 Foo f;531 return true;532 }533 static_assert(Foo::a.A == 0);534 static_assert(f());535 static_assert(Foo::a.A == 0);536 537 538 struct NotConstexpr {539 NotConstexpr() {}540 ~NotConstexpr() {}541 };542 543 struct Outer {544 constexpr Outer() = default;545 constexpr ~Outer();546 547 constexpr int foo() {548 return 12;549 }550 551 constexpr int bar()const {552 return Outer{}.foo();553 }554 555 static NotConstexpr Val;556 };557 558 constexpr Outer::~Outer() {}559 560 constexpr Outer O;561 static_assert(O.bar() == 12);562}563 564namespace BaseAndFieldInit {565 struct A {566 int a;567 };568 569 struct B : A {570 int b;571 };572 573 struct C : B {574 int c;575 };576 577 constexpr C c = {1,2,3};578 static_assert(c.a == 1 && c.b == 2 && c.c == 3);579}580 581namespace ImplicitFunction {582 struct A {583 int a; // ref-note {{subobject declared here}}584 };585 586 constexpr int callMe() {587 A a;588 A b{12};589 590 /// The operator= call here will fail and the diagnostics should be fine.591 b = a; // ref-note {{subobject 'a' is not initialized}} \592 // expected-note {{read of uninitialized object}} \593 // both-note {{in call to}}594 595 return 1;596 }597 static_assert(callMe() == 1, ""); // both-error {{not an integral constant expression}} \598 // both-note {{in call to 'callMe()'}}599}600 601namespace std {602 class strong_ordering {603 public:604 int n;605 static const strong_ordering less, equal, greater;606 constexpr bool operator==(int n) const noexcept { return this->n == n;}607 constexpr bool operator!=(int n) const noexcept { return this->n != n;}608 };609 constexpr strong_ordering strong_ordering::less = {-1};610 constexpr strong_ordering strong_ordering::equal = {0};611 constexpr strong_ordering strong_ordering::greater = {1};612 613 class partial_ordering {614 public:615 long n;616 static const partial_ordering less, equal, greater, equivalent, unordered;617 constexpr bool operator==(long n) const noexcept { return this->n == n;}618 constexpr bool operator!=(long n) const noexcept { return this->n != n;}619 };620 constexpr partial_ordering partial_ordering::less = {-1};621 constexpr partial_ordering partial_ordering::equal = {0};622 constexpr partial_ordering partial_ordering::greater = {1};623 constexpr partial_ordering partial_ordering::equivalent = {0};624 constexpr partial_ordering partial_ordering::unordered = {-127};625} // namespace std626 627namespace ThreeWayCmp {628 static_assert(1 <=> 2 == -1, "");629 static_assert(1 <=> 1 == 0, "");630 static_assert(2 <=> 1 == 1, "");631 static_assert(1.0 <=> 2.f == -1, "");632 static_assert(1.0 <=> 1.0 == 0, "");633 static_assert(2.0 <=> 1.0 == 1, "");634 constexpr int k = (1 <=> 1, 0); // both-warning {{comparison result unused}}635 static_assert(k== 0, "");636 637 static_assert(__builtin_nanf("") <=> __builtin_nanf("") == -127, "");638 639 /// Pointers.640 constexpr int a[] = {1,2,3};641 constexpr int b[] = {1,2,3};642 constexpr const int *pa1 = &a[1];643 constexpr const int *pa2 = &a[2];644 constexpr const int *pb1 = &b[1];645 static_assert(pa1 <=> pb1 != 0, ""); // both-error {{not an integral constant expression}} \646 // both-note {{has unspecified value}}647 static_assert(pa1 <=> pa1 == 0, "");648 static_assert(pa1 <=> pa2 == -1, "");649 static_assert(pa2 <=> pa1 == 1, "");650}651 652namespace ConstexprArrayInitLoopExprDestructors653{654 struct Highlander {655 int *p = 0;656 constexpr Highlander() {}657 constexpr void set(int *p) { this->p = p; ++*p; if (*p != 1) throw "there can be only one"; }658 constexpr ~Highlander() { --*p; }659 };660 661 struct X {662 int *p;663 constexpr X(int *p) : p(p) {}664 constexpr X(const X &x, Highlander &&h = Highlander()) : p(x.p) {665 h.set(p);666 }667 };668 669 constexpr int f() {670 int n = 0;671 X x[3] = {&n, &n, &n};672 auto [a, b, c] = x;673 return n;674 }675 676 static_assert(f() == 0);677}678 679namespace NonPrimitiveOpaqueValue680{681 struct X {682 int x;683 constexpr operator bool() const { return x != 0; }684 };685 686 constexpr int ternary() { return X(0) ?: X(0); }687 688 static_assert(!ternary(), "");689}690 691namespace TryCatch {692 constexpr int foo() {693 int a = 10;694 try {695 ++a;696 } catch(int m) {697 --a;698 }699 return a;700 }701 static_assert(foo() == 11);702}703 704namespace IgnoredConstantExpr {705 consteval int immediate() { return 0;}706 struct ReferenceToNestedMembers {707 int m;708 int a = ((void)immediate(), m);709 int b = ((void)immediate(), this->m);710 };711 struct ReferenceToNestedMembersTest {712 void* m = nullptr;713 ReferenceToNestedMembers j{0};714 } test_reference_to_nested_members;715}716 717namespace RewrittenBinaryOperators {718 template <class T, T Val>719 struct Conv {720 constexpr operator T() const { return Val; }721 operator T() { return Val; }722 };723 724 struct X {725 constexpr const Conv<int, -1> operator<=>(X) { return {}; }726 };727 static_assert(X() < X(), "");728}729 730namespace GH61417 {731struct A {732 unsigned x : 1;733 unsigned : 0;734 unsigned y : 1;735 736 constexpr A() : x(0), y(0) {}737 bool operator==(const A& rhs) const noexcept = default;738};739 740void f1() {741 constexpr A a, b;742 constexpr bool c = (a == b); // no diagnostic, we should not be comparing the743 // unnamed bit-field which is indeterminate744}745 746void f2() {747 A a, b;748 bool c = (a == b); // no diagnostic nor crash during codegen attempting to749 // access info for unnamed bit-field750}751}752 753namespace FailingDestructor {754 struct D {755 int n;756 bool can_destroy;757 758 constexpr ~D() {759 if (!can_destroy)760 throw "oh no";761 }762 };763 template<D d>764 void f() {} // both-note {{invalid explicitly-specified argument}}765 766 void g() {767 f<D{0, false}>(); // both-error {{no matching function}}768 }769}770 771 772void overflowInSwitchCase(int n) {773 switch (n) {774 case (int)(float)1e300: // both-error {{constant expression}} \775 // both-note {{value +Inf is outside the range of representable values of type 'int'}}776 break;777 }778}779 780namespace APValues {781 int g;782 struct A { union { int n, m; }; int *p; int A::*q; char buffer[32]; };783 template<A a> constexpr const A &get = a;784 constexpr const A &v = get<A{}>;785 constexpr const A &w = get<A{1, &g, &A::n, "hello"}>;786}787 788namespace self_referencing {789 struct S {790 S* ptr = nullptr;791 constexpr S(int i) : ptr(this) {792 if (this == ptr && i)793 ptr = nullptr;794 }795 constexpr ~S() {}796 };797 798 void test() {799 S s(1);800 }801}802 803namespace GH64949 {804 struct f {805 int g; // both-note {{subobject declared here}}806 constexpr ~f() {}807 };808 809 class h {810 public:811 consteval h(char *) {}812 f i;813 };814 815 void test() { h{nullptr}; } // both-error {{call to consteval function 'GH64949::h::h' is not a constant expression}} \816 // both-note {{subobject 'g' is not initialized}} \817 // both-warning {{expression result unused}}818}819 820/// This used to cause an assertion failure inside EvaluationResult::checkFullyInitialized.821namespace CheckingNullPtrForInitialization {822 struct X {823 consteval operator const char *() const {824 return nullptr;825 }826 };827 const char *f() {828 constexpr X x;829 return x;830 }831}832 833namespace VariadicCallOperator {834 class F {835 public:836 constexpr void operator()(int a, int b, ...) {}837 };838 constexpr int foo() {839 F f;840 841 f(1,2, 3);842 return 1;843 }844 constexpr int A = foo();845}846 847namespace DefinitionLoc {848 849 struct NonConstexprCopy {850 constexpr NonConstexprCopy() = default;851 NonConstexprCopy(const NonConstexprCopy &);852 constexpr NonConstexprCopy(NonConstexprCopy &&) = default;853 854 int n = 42;855 };856 857 NonConstexprCopy::NonConstexprCopy(const NonConstexprCopy &) = default; // both-note {{here}}858 859 constexpr NonConstexprCopy ncc1 = NonConstexprCopy(NonConstexprCopy());860 constexpr NonConstexprCopy ncc2 = ncc1; // both-error {{constant expression}} \861 // both-note {{non-constexpr constructor}}862}863 864namespace VirtDtor {865 class B {866 public:867 constexpr B(char *p) : p(p) {}868 virtual constexpr ~B() {869 *p = 'B';870 ++p;871 }872 873 char *p;874 };875 876 class C : public B {877 public:878 constexpr C(char *p) : B(p) {}879 virtual constexpr ~C() override {880 *p = 'C';881 ++p;882 }883 };884 885 union U {886 constexpr U(char *p) : c(p) {}887 constexpr ~U() {}888 889 C c;890 };891 892 constexpr int test(char a, char b) {893 char buff[2] = {};894 U u(buff);895 896 /// U is a union, so it won't call the destructor of its fields.897 /// We do this manually here. Explicitly calling ~C() here should898 /// also call the destructor of the base classes however.899 u.c.~C();900 901 return buff[0] == a && buff[1] == b;902 }903 904 static_assert(test('C', 'B'));905}906 907namespace TemporaryInNTTP {908 template<auto n> struct B { /* ... */ };909 struct J1 {910 J1 *self=this;911 };912 /// FIXME: The bytecode interpreter emits a different diagnostic here.913 /// The current interpreter creates a fake MaterializeTemporaryExpr (see EvaluateAsConstantExpr)914 /// which is later used as the LValueBase of the created APValue.915 B<J1{}> j1; // ref-error {{pointer to temporary object is not allowed in a template argument}} \916 // expected-error {{non-type template argument is not a constant expression}} \917 // expected-note {{pointer to temporary is not a constant expression}} \918 // expected-note {{created here}}919 B<2> j2; /// Ok.920}921 922namespace LocalDestroy {923 /// This is reduced from a libc++ test case.924 /// The local f.TI.copied points to the local variable Copied, and we used to925 /// destroy Copied before f, causing problems later on when a DeadBlock had a926 /// pointer pointing to it that was already destroyed.927 struct TrackInitialization {928 bool *copied_;929 };930 struct TrackingPred : TrackInitialization {931 constexpr TrackingPred(bool *copied) : TrackInitialization(copied) {}932 };933 struct F {934 const TrackingPred &TI;935 };936 constexpr int f() {937 bool Copied = false;938 TrackingPred TI(&Copied);939 F f{TI};940 return 1;941 }942 static_assert(f() == 1);943}944 945namespace PseudoDtor {946 constexpr int f1() {947 using T = int;948 int a = 0;949 a.~T();950 return a; // both-note {{read of object outside its lifetime}}951 }952 static_assert(f1() == 0); // both-error {{not an integral constant expression}} \953 // both-note {{in call to}}954 955 constexpr int f2() {956 using T = int;957 int a = 0;958 a.~T();959 a = 0; // both-note {{assignment to object outside its lifetime}}960 return a;961 }962 static_assert(f2() == 0); // both-error {{not an integral constant expression}} \963 // both-note {{in call to}}964 965#ifdef NEW_INTERP966 /// FIXME: Currently crashes with the current interpreter, see https://github.com/llvm/llvm-project/issues/53741967 constexpr int f3() {968 using T = int;969 0 .~T();970 return 0;971 }972 static_assert(f3() == 0);973#endif974}975 976namespace NastyChar {977 struct nasty_char {978 template <typename T> friend auto operator<=>(T, T) = delete;979 template <typename T> friend void operator+(T &&) = delete;980 template <typename T> friend void operator-(T &&) = delete;981 template <typename T> friend void operator&(T &&) = delete;982 983 char c;984 };985 986 987 template <unsigned N> struct ToNastyChar {988 constexpr ToNastyChar(const char (&r)[N]) {989 for (unsigned I = 0; I != N; ++I)990 text[I] = nasty_char{r[I]};991 }992 nasty_char text[N];993 };994 995 template <unsigned N> ToNastyChar(const char (&)[N]) -> ToNastyChar<N>;996 997 template <ToNastyChar t> constexpr auto to_nasty_char() { return t; }998 constexpr auto result = to_nasty_char<"12345">();999}1000 1001namespace TempDtor {1002 struct A {1003 int n;1004 };1005 constexpr A &&a_ref = A(); // both-note {{temporary created here}}1006 constexpr void destroy_extern_2() { // both-error {{never produces a constant expression}}1007 a_ref.~A(); // both-note {{destruction of temporary is not allowed in a constant expression outside the expression that created the temporary}}1008 }1009}1010 1011namespace OnePastEndDtor {1012 struct A {int n; };1013 constexpr void destroy_past_end() { // both-error {{never produces a constant expression}}1014 A a;1015 (&a+1)->~A(); // both-note {{destruction of dereferenced one-past-the-end pointer}}1016 }1017}1018 1019namespace Virtual {1020 struct NonZeroOffset { int padding = 123; };1021 1022 constexpr void assert(bool b) { if (!b) throw 0; }1023 1024 // Ensure that we pick the right final overrider during construction.1025 struct A {1026 virtual constexpr char f() const { return 'A'; }1027 char a = f();1028 constexpr ~A() { assert(f() == 'A'); }1029 };1030 struct NoOverrideA : A {};1031 struct B : NonZeroOffset, NoOverrideA {1032 virtual constexpr char f() const { return 'B'; }1033 char b = f();1034 constexpr ~B() { assert(f() == 'B'); }1035 };1036 struct NoOverrideB : B {};1037 struct C : NonZeroOffset, A {1038 virtual constexpr char f() const { return 'C'; }1039 A *pba;1040 char c = ((A*)this)->f();1041 char ba = pba->f();1042 constexpr C(A *pba) : pba(pba) {}1043 constexpr ~C() { assert(f() == 'C'); }1044 };1045 struct D : NonZeroOffset, NoOverrideB, C { // both-warning {{inaccessible}}1046 virtual constexpr char f() const { return 'D'; }1047 char d = f();1048 constexpr D() : C((B*)this) {}1049 constexpr ~D() { assert(f() == 'D'); }1050 };1051 constexpr int n = (D(), 0);1052 1053 constexpr D d;1054 static_assert(((B&)d).a == 'A');1055 static_assert(((C&)d).a == 'A');1056 static_assert(d.b == 'B');1057 static_assert(d.c == 'C');1058 // During the construction of C, the dynamic type of B's A is B.1059 static_assert(d.ba == 'B'); // expected-error {{failed}} \1060 // expected-note {{expression evaluates to}}1061 static_assert(d.d == 'D');1062 static_assert(d.f() == 'D');1063 constexpr const A &a = (B&)d;1064 constexpr const B &b = d;1065 static_assert(a.f() == 'D');1066 static_assert(b.f() == 'D');1067 1068 1069 class K {1070 public:1071 int a = f();1072 1073 virtual constexpr int f() const { return 10; }1074 };1075 1076 K k;1077 static_assert(k.f() == 10); // both-error {{not an integral constant expression}} \1078 // both-note {{virtual function called on object 'k' whose dynamic type is not constant}}1079 1080 void f() {1081 constexpr K k;1082 static_assert(k.f() == 10);1083 }1084 1085 void f2() {1086 K k;1087 static_assert(k.f() == 10); // both-error {{not an integral constant expression}} \1088 // both-note {{virtual function called on object 'k' whose dynamic type is not constant}}1089 }1090 1091 static_assert(K().f() == 10);1092 1093 void f3() {1094 static_assert(K().f() == 10);1095 }1096 1097 class L : public K {1098 public:1099 int b = f();1100 int c =((L*)this)->f();1101 };1102 1103 constexpr L l;1104 static_assert(l.a == 10);1105 static_assert(l.b == 10);1106 static_assert(l.c == 10);1107 static_assert(l.f() == 10);1108 1109 struct M {1110 K& mk = k;1111 };1112 static_assert(M{}.mk.f() == 10); // both-error {{not an integral constant expression}} \1113 // both-note {{virtual function called on object 'k' whose dynamic type is not constant}}1114 1115 struct N {1116 K* mk = &k;1117 };1118 static_assert(N{}.mk->f() == 10); // both-error {{not an integral constant expression}} \1119 // both-note {{virtual function called on object 'k' whose dynamic type is not constant}}1120 1121 extern K o;1122 static_assert(o.f() == 10); // both-error {{not an integral constant expression}} \1123 // both-note {{virtual function called on object 'o' whose dynamic type is not constant}}1124 static K p;1125 static_assert(p.f() == 10); // both-error {{not an integral constant expression}} \1126 // both-note {{virtual function called on object 'p' whose dynamic type is not constant}}1127 1128 void f4() {1129 static K p;1130 static_assert(p.f() == 10); // both-error {{not an integral constant expression}} \1131 // both-note {{virtual function called on object 'p' whose dynamic type is not constant}}1132 }1133 1134 const K q;1135 static_assert(q.f() == 10); // both-error {{not an integral constant expression}} \1136 // both-note {{virtual function called on object 'q' whose dynamic type is not constant}}1137 1138 void f5() {1139 const K q;1140 static_assert(q.f() == 10); // both-error {{not an integral constant expression}} \1141 // both-note {{virtual function called on object 'q' whose dynamic type is not constant}}1142 }1143}1144 1145namespace DiscardedTrivialCXXConstructExpr {1146 struct S {1147 constexpr S(int a) : x(a) {}1148 int x;1149 };1150 1151 constexpr int foo(int x) { // ref-error {{never produces a constant expression}}1152 throw S(3); // both-note {{not valid in a constant expression}} \1153 // ref-note {{not valid in a constant expression}}1154 return 1;1155 }1156 1157 constexpr int y = foo(12); // both-error {{must be initialized by a constant expression}} \1158 // both-note {{in call to}}1159}1160 1161namespace VirtualFunctionCallThroughArrayElem {1162 struct X {1163 constexpr virtual int foo() const {1164 return 3;1165 }1166 };1167 constexpr X xs[5];1168 static_assert(xs[3].foo() == 3);1169 1170 constexpr X xs2[1][2];1171 static_assert(xs2[0].foo() == 3); // both-error {{is not a structure or union}}1172 static_assert(xs2[0][0].foo() == 3);1173 1174 struct Y: public X {1175 constexpr int foo() const override {1176 return 1;1177 }1178 };1179 constexpr Y ys[20];1180 static_assert(ys[12].foo() == static_cast<const X&>(ys[12]).foo());1181 1182 X a[3][4];1183 static_assert(a[2][3].foo()); // both-error {{not an integral constant expression}} \1184 // both-note {{virtual function called on object 'a[2][3]' whose dynamic type is not constant}}1185}1186 1187namespace NonPureVirtualCall {1188 struct A {1189 constexpr virtual void call(int) = 0;1190 constexpr void call2() { call(0); }1191 };1192 1193 struct B : A {1194 constexpr void call(int) override {}1195 };1196 1197 consteval void check() {1198 B b;1199 b.call2();1200 }1201 1202 int main() { check(); }1203}1204 1205namespace DyamicCast {1206 struct X {1207 virtual constexpr ~X() {}1208 };1209 struct Y : X {};1210 constexpr Y y;1211 constexpr const X *p = &y;1212 constexpr const Y *q = dynamic_cast<const Y*>(p);1213}1214