| // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify=expected,both %s |
| // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=expected,both %s |
| // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -triple i686 -verify=expected,both %s |
| // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,both %s |
| // RUN: %clang_cc1 -verify=ref,both -std=c++14 %s |
| // RUN: %clang_cc1 -verify=ref,both -std=c++17 %s |
| // RUN: %clang_cc1 -verify=ref,both -std=c++17 -triple i686 %s |
| // RUN: %clang_cc1 -verify=ref,both -std=c++20 %s |
| |
| /// Used to crash. |
| struct Empty {}; |
| constexpr Empty e = {Empty()}; |
| |
| struct BoolPair { |
| bool first; |
| bool second; |
| }; |
| |
| struct Ints { |
| int a = 20; |
| int b = 30; |
| bool c = true; |
| BoolPair bp = {true, false}; |
| int numbers[3] = {1,2,3}; |
| |
| static const int five = 5; |
| static constexpr int getFive() { |
| return five; |
| } |
| |
| constexpr int getTen() const { |
| return 10; |
| } |
| }; |
| |
| static_assert(Ints::getFive() == 5, ""); |
| |
| constexpr Ints ints; |
| static_assert(ints.a == 20, ""); |
| static_assert(ints.b == 30, ""); |
| static_assert(ints.c, ""); |
| static_assert(ints.getTen() == 10, ""); |
| static_assert(ints.numbers[0] == 1, ""); |
| static_assert(ints.numbers[1] == 2, ""); |
| static_assert(ints.numbers[2] == 3, ""); |
| |
| constexpr const BoolPair &BP = ints.bp; |
| static_assert(BP.first, ""); |
| static_assert(!BP.second, ""); |
| static_assert(ints.bp.first, ""); |
| static_assert(!ints.bp.second, ""); |
| |
| |
| constexpr Ints ints2{-20, -30, false}; |
| static_assert(ints2.a == -20, ""); |
| static_assert(ints2.b == -30, ""); |
| static_assert(!ints2.c, ""); |
| |
| constexpr Ints getInts() { |
| return {64, 128, true}; |
| } |
| constexpr Ints ints3 = getInts(); |
| static_assert(ints3.a == 64, ""); |
| static_assert(ints3.b == 128, ""); |
| static_assert(ints3.c, ""); |
| |
| constexpr Ints ints4 = { |
| .a = 40 * 50, |
| .b = 0, |
| .c = (ints.a > 0), |
| |
| }; |
| static_assert(ints4.a == (40 * 50), ""); |
| static_assert(ints4.b == 0, ""); |
| static_assert(ints4.c, ""); |
| static_assert(ints4.numbers[0] == 1, ""); |
| static_assert(ints4.numbers[1] == 2, ""); |
| static_assert(ints4.numbers[2] == 3, ""); |
| |
| constexpr Ints ints5 = ints4; |
| static_assert(ints5.a == (40 * 50), ""); |
| static_assert(ints5.b == 0, ""); |
| static_assert(ints5.c, ""); |
| static_assert(ints5.numbers[0] == 1, ""); |
| static_assert(ints5.numbers[1] == 2, ""); |
| static_assert(ints5.numbers[2] == 3, ""); |
| |
| |
| struct Ints2 { |
| int a = 10; |
| int b; |
| }; |
| constexpr Ints2 ints22; // both-error {{without a user-provided default constructor}} |
| |
| constexpr Ints2 I2 = Ints2{12, 25}; |
| static_assert(I2.a == 12, ""); |
| static_assert(I2.b == 25, ""); |
| |
| class C { |
| public: |
| int a; |
| int b; |
| |
| constexpr C() : a(100), b(200) {} |
| |
| constexpr C get() const { |
| return *this; |
| } |
| }; |
| |
| constexpr C c; |
| static_assert(c.a == 100, ""); |
| static_assert(c.b == 200, ""); |
| |
| constexpr C c2 = C().get(); |
| static_assert(c2.a == 100, ""); |
| static_assert(c2.b == 200, ""); |
| |
| |
| /// A global, composite temporary variable. |
| constexpr const C &c3 = C().get(); |
| |
| /// Same, but with a bitfield. |
| class D { |
| public: |
| unsigned a : 4; |
| constexpr D() : a(15) {} |
| constexpr D get() const { |
| return *this; |
| } |
| }; |
| constexpr const D &d4 = D().get(); |
| |
| constexpr int getB() { |
| C c; |
| int &j = c.b; |
| |
| j = j * 2; |
| |
| return c.b; |
| } |
| static_assert(getB() == 400, ""); |
| |
| constexpr int getA(const C &c) { |
| return c.a; |
| } |
| static_assert(getA(c) == 100, ""); |
| |
| constexpr const C* getPointer() { |
| return &c; |
| } |
| static_assert(getPointer()->a == 100, ""); |
| |
| constexpr C RVOAndParams(const C *c) { |
| return C(); |
| } |
| constexpr C RVOAndParamsResult = RVOAndParams(&c); |
| |
| /// Parameter and return value have different types. |
| constexpr C RVOAndParams(int a) { |
| return C(); |
| } |
| constexpr C RVOAndParamsResult2 = RVOAndParams(12); |
| |
| class Bar { // both-note {{definition of 'Bar' is not complete}} |
| public: |
| constexpr Bar(){} |
| constexpr Bar b; // both-error {{cannot be constexpr}} \ |
| // both-error {{has incomplete type 'const Bar'}} |
| }; |
| constexpr Bar B; // both-error {{must be initialized by a constant expression}} |
| constexpr Bar *pb = nullptr; |
| |
| constexpr int locals() { |
| C c; |
| c.a = 10; |
| |
| // Assignment, not an initializer. |
| c = C(); |
| c.a = 10; |
| |
| |
| // Assignment, not an initializer. |
| c = RVOAndParams(&c); |
| |
| return c.a; |
| } |
| static_assert(locals() == 100, ""); |
| |
| namespace thisPointer { |
| struct S { |
| constexpr int get12() { return 12; } |
| }; |
| |
| constexpr int foo() { // both-error {{never produces a constant expression}} |
| S *s = nullptr; |
| return s->get12(); // both-note 2{{member call on dereferenced null pointer}} |
| |
| } |
| static_assert(foo() == 12, ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to 'foo()'}} |
| }; |
| |
| struct FourBoolPairs { |
| BoolPair v[4] = { |
| {false, false}, |
| {false, true}, |
| {true, false}, |
| {true, true }, |
| }; |
| }; |
| // Init |
| constexpr FourBoolPairs LT; |
| // Copy ctor |
| constexpr FourBoolPairs LT2 = LT; |
| static_assert(LT2.v[0].first == false, ""); |
| static_assert(LT2.v[0].second == false, ""); |
| static_assert(LT2.v[2].first == true, ""); |
| static_assert(LT2.v[2].second == false, ""); |
| |
| class Base { |
| public: |
| int i; |
| constexpr Base() : i(10) {} |
| constexpr Base(int i) : i(i) {} |
| }; |
| |
| class A : public Base { |
| public: |
| constexpr A() : Base(100) {} |
| constexpr A(int a) : Base(a) {} |
| }; |
| constexpr A a{}; |
| static_assert(a.i == 100, ""); |
| constexpr A a2{12}; |
| static_assert(a2.i == 12, ""); |
| static_assert(a2.i == 200, ""); // both-error {{static assertion failed}} \ |
| // both-note {{evaluates to '12 == 200'}} |
| |
| |
| struct S { |
| int a = 0; |
| constexpr int get5() const { return 5; } |
| constexpr void fo() const { |
| this; // both-warning {{expression result unused}} |
| this->a; // both-warning {{expression result unused}} |
| get5(); |
| getInts(); |
| } |
| |
| constexpr int m() const { |
| fo(); |
| return 1; |
| } |
| }; |
| constexpr S s; |
| static_assert(s.m() == 1, ""); |
| |
| namespace InitializerTemporaries { |
| class Bar { |
| private: |
| int a; |
| |
| public: |
| constexpr Bar() : a(10) {} |
| constexpr int getA() const { return a; } |
| }; |
| |
| class Foo { |
| public: |
| int a; |
| |
| constexpr Foo() : a(Bar().getA()) {} |
| }; |
| constexpr Foo F; |
| static_assert(F.a == 10, ""); |
| |
| |
| /// Needs constexpr destructors. |
| #if __cplusplus >= 202002L |
| /// Does |
| /// Arr[Pos] = Value; |
| /// ++Pos; |
| /// in its destructor. |
| class BitSetter { |
| private: |
| int *Arr; |
| int &Pos; |
| int Value; |
| |
| public: |
| constexpr BitSetter(int *Arr, int &Pos, int Value) : |
| Arr(Arr), Pos(Pos), Value(Value) {} |
| |
| constexpr int getValue() const { return 0; } |
| constexpr ~BitSetter() { |
| Arr[Pos] = Value; |
| ++Pos; |
| } |
| }; |
| |
| class Test { |
| int a, b, c; |
| public: |
| constexpr Test(int *Arr, int &Pos) : |
| a(BitSetter(Arr, Pos, 1).getValue()), |
| b(BitSetter(Arr, Pos, 2).getValue()), |
| c(BitSetter(Arr, Pos, 3).getValue()) |
| {} |
| }; |
| |
| |
| constexpr int T(int Index) { |
| int Arr[] = {0, 0, 0}; |
| int Pos = 0; |
| |
| { |
| Test(Arr, Pos); |
| // End of scope, should destroy Test. |
| } |
| |
| return Arr[Index]; |
| } |
| static_assert(T(0) == 1); |
| static_assert(T(1) == 2); |
| static_assert(T(2) == 3); |
| |
| // Invalid destructor. |
| struct S { |
| constexpr S() {} |
| constexpr ~S() noexcept(false) { throw 12; } // both-error {{cannot use 'throw'}} \ |
| // both-error {{never produces a constant expression}} \ |
| // both-note 2{{subexpression not valid}} |
| }; |
| |
| constexpr int f() { |
| S{}; // both-note {{in call to 'S{}.~S()'}} |
| return 12; |
| } |
| static_assert(f() == 12); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to 'f()'}} |
| |
| |
| #endif |
| } |
| |
| #if __cplusplus >= 201703L |
| namespace BaseInit { |
| class _A {public: int a;}; |
| class _B : public _A {}; |
| class _C : public _B {}; |
| |
| constexpr _C c{12}; |
| constexpr const _B &b = c; |
| static_assert(b.a == 12); |
| |
| class A {public: int a;}; |
| class B : public A {}; |
| class C : public A {}; |
| class D : public B, public C {}; |
| |
| // This initializes D::B::A::a and not D::C::A::a. |
| constexpr D d{12}; |
| static_assert(d.B::a == 12); |
| static_assert(d.C::a == 0); |
| }; |
| #endif |
| |
| namespace MI { |
| class A { |
| public: |
| int a; |
| constexpr A(int a) : a(a) {} |
| }; |
| |
| class B { |
| public: |
| int b; |
| constexpr B(int b) : b(b) {} |
| }; |
| |
| class C : public A, public B { |
| public: |
| constexpr C() : A(10), B(20) {} |
| }; |
| constexpr C c = {}; |
| static_assert(c.a == 10, ""); |
| static_assert(c.b == 20, ""); |
| |
| constexpr const A *aPointer = &c; |
| constexpr const B *bPointer = &c; |
| |
| class D : private A, private B { |
| public: |
| constexpr D() : A(20), B(30) {} |
| constexpr int getA() const { return a; } |
| constexpr int getB() const { return b; } |
| }; |
| constexpr D d = {}; |
| static_assert(d.getA() == 20, ""); |
| static_assert(d.getB() == 30, ""); |
| }; |
| |
| namespace DeriveFailures { |
| #if __cplusplus < 202002L |
| struct Base { // both-note {{declared here}} \ |
| // ref-note {{declared here}} |
| int Val; |
| }; |
| |
| struct Derived : Base { |
| int OtherVal; |
| |
| constexpr Derived(int i) : OtherVal(i) {} // ref-error {{never produces a constant expression}} \ |
| // both-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} \ |
| // ref-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} |
| }; |
| |
| constexpr Derived D(12); // both-error {{must be initialized by a constant expression}} \ |
| // both-note {{in call to 'Derived(12)'}} \ |
| // both-note {{declared here}} |
| |
| static_assert(D.Val == 0, ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{initializer of 'D' is not a constant expression}} |
| #endif |
| |
| struct AnotherBase { |
| int Val; |
| constexpr AnotherBase(int i) : Val(12 / i) {} // both-note {{division by zero}} |
| }; |
| |
| struct AnotherDerived : AnotherBase { |
| constexpr AnotherDerived(int i) : AnotherBase(i) {} |
| }; |
| constexpr AnotherBase Derp(0); // both-error {{must be initialized by a constant expression}} \ |
| // both-note {{in call to 'AnotherBase(0)'}} |
| |
| struct YetAnotherBase { |
| int Val; |
| constexpr YetAnotherBase(int i) : Val(i) {} |
| }; |
| |
| struct YetAnotherDerived : YetAnotherBase { |
| using YetAnotherBase::YetAnotherBase; // both-note {{declared here}} |
| int OtherVal; |
| |
| constexpr bool doit() const { return Val == OtherVal; } |
| }; |
| |
| constexpr YetAnotherDerived Oops(0); // both-error {{must be initialized by a constant expression}} \ |
| // both-note {{constructor inherited from base class 'YetAnotherBase' cannot be used in a constant expression}} |
| }; |
| |
| namespace EmptyCtor { |
| struct piecewise_construct_t { explicit piecewise_construct_t() = default; }; |
| constexpr piecewise_construct_t piecewise_construct = |
| piecewise_construct_t(); |
| }; |
| |
| namespace ConditionalInit { |
| struct S { int a; }; |
| |
| constexpr S getS(bool b) { |
| return b ? S{12} : S{13}; |
| } |
| |
| static_assert(getS(true).a == 12, ""); |
| static_assert(getS(false).a == 13, ""); |
| }; |
| namespace DeclRefs { |
| struct A{ int m; const int &f = m; }; |
| |
| constexpr A a{10}; |
| static_assert(a.m == 10, ""); |
| static_assert(a.f == 10, ""); |
| |
| class Foo { |
| public: |
| int z = 1337; |
| constexpr int a() const { |
| A b{this->z}; |
| |
| return b.f; |
| } |
| }; |
| constexpr Foo f; |
| static_assert(f.a() == 1337, ""); |
| |
| |
| struct B { |
| A a = A{100}; |
| }; |
| constexpr B b; |
| static_assert(b.a.m == 100, ""); |
| static_assert(b.a.f == 100, ""); |
| |
| constexpr B b2{}; |
| static_assert(b2.a.m == 100, ""); |
| static_assert(b2.a.f == 100, ""); |
| static_assert(b2.a.f == 101, ""); // both-error {{failed}} \ |
| // both-note {{evaluates to '100 == 101'}} |
| } |
| |
| namespace PointerArith { |
| struct A {}; |
| struct B : A { int n; }; |
| |
| B b = {}; |
| constexpr A *a1 = &b; |
| constexpr B *b1 = &b + 1; |
| constexpr B *b2 = &b + 0; |
| |
| constexpr A *a2 = &b + 1; // both-error {{must be initialized by a constant expression}} \ |
| // both-note {{cannot access base class of pointer past the end of object}} |
| constexpr const int *pn = &(&b + 1)->n; // both-error {{must be initialized by a constant expression}} \ |
| // both-note {{cannot access field of pointer past the end of object}} |
| } |
| |
| #if __cplusplus >= 202002L |
| namespace VirtualCalls { |
| namespace Obvious { |
| |
| class A { |
| public: |
| constexpr A(){} |
| constexpr virtual int foo() { |
| return 3; |
| } |
| }; |
| class B : public A { |
| public: |
| constexpr int foo() override { |
| return 6; |
| } |
| }; |
| |
| constexpr int getFooB(bool b) { |
| A *a; |
| A myA; |
| B myB; |
| |
| if (b) |
| a = &myA; |
| else |
| a = &myB; |
| |
| return a->foo(); |
| } |
| static_assert(getFooB(true) == 3, ""); |
| static_assert(getFooB(false) == 6, ""); |
| } |
| |
| namespace MultipleBases { |
| class A { |
| public: |
| constexpr virtual int getInt() const { return 10; } |
| }; |
| class B { |
| public: |
| }; |
| class C : public A, public B { |
| public: |
| constexpr int getInt() const override { return 20; } |
| }; |
| |
| constexpr int callGetInt(const A& a) { return a.getInt(); } |
| static_assert(callGetInt(C()) == 20, ""); |
| static_assert(callGetInt(A()) == 10, ""); |
| } |
| |
| namespace Destructors { |
| class Base { |
| public: |
| int i; |
| constexpr Base(int &i) : i(i) {i++;} |
| constexpr virtual ~Base() {i--;} |
| }; |
| |
| class Derived : public Base { |
| public: |
| constexpr Derived(int &i) : Base(i) {} |
| constexpr virtual ~Derived() {i--;} |
| }; |
| |
| constexpr int test() { |
| int i = 0; |
| Derived d(i); |
| return i; |
| } |
| static_assert(test() == 1); |
| |
| struct S { |
| constexpr S() {} |
| constexpr ~S() { // both-error {{never produces a constant expression}} |
| int i = 1 / 0; // both-warning {{division by zero}} \ |
| // both-note 2{{division by zero}} |
| } |
| }; |
| constexpr int testS() { |
| S{}; // both-note {{in call to 'S{}.~S()'}} |
| return 1; |
| } |
| static_assert(testS() == 1); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to 'testS()'}} |
| } |
| |
| namespace BaseToDerived { |
| namespace A { |
| struct A {}; |
| struct B : A { int n; }; |
| struct C : B {}; |
| C c = {}; |
| constexpr C *pb = (C*)((A*)&c + 1); // both-error {{must be initialized by a constant expression}} \ |
| // both-note {{cannot access derived class of pointer past the end of object}} |
| } |
| namespace B { |
| struct A {}; |
| struct Z {}; |
| struct B : Z, A { |
| int n; |
| constexpr B() : n(10) {} |
| }; |
| struct C : B { |
| constexpr C() : B() {} |
| }; |
| |
| constexpr C c = {}; |
| constexpr const A *pa = &c; |
| constexpr const C *cp = (C*)pa; |
| constexpr const B *cb = (B*)cp; |
| |
| static_assert(cb->n == 10); |
| static_assert(cp->n == 10); |
| } |
| |
| namespace C { |
| struct Base { int *a; }; |
| struct Base2 : Base { int f[12]; }; |
| |
| struct Middle1 { int b[3]; }; |
| struct Middle2 : Base2 { char c; }; |
| struct Middle3 : Middle2 { char g[3]; }; |
| struct Middle4 { int f[3]; }; |
| struct Middle5 : Middle4, Middle3 { char g2[3]; }; |
| |
| struct NotQuiteDerived : Middle1, Middle5 { bool d; }; |
| struct Derived : NotQuiteDerived { int e; }; |
| |
| constexpr NotQuiteDerived NQD1 = {}; |
| |
| constexpr Middle5 *M4 = (Middle5*)((Base2*)&NQD1); |
| static_assert(M4->a == nullptr); |
| static_assert(M4->g2[0] == 0); |
| } |
| } |
| |
| |
| namespace VirtualDtors { |
| class A { |
| public: |
| unsigned &v; |
| constexpr A(unsigned &v) : v(v) {} |
| constexpr virtual ~A() { |
| v |= (1 << 0); |
| } |
| }; |
| class B : public A { |
| public: |
| constexpr B(unsigned &v) : A(v) {} |
| constexpr virtual ~B() { |
| v |= (1 << 1); |
| } |
| }; |
| class C : public B { |
| public: |
| constexpr C(unsigned &v) : B(v) {} |
| constexpr virtual ~C() { |
| v |= (1 << 2); |
| } |
| }; |
| |
| constexpr bool foo() { |
| unsigned a = 0; |
| { |
| C c(a); |
| } |
| return ((a & (1 << 0)) && (a & (1 << 1)) && (a & (1 << 2))); |
| } |
| |
| static_assert(foo()); |
| }; |
| |
| namespace QualifiedCalls { |
| class A { |
| public: |
| constexpr virtual int foo() const { |
| return 5; |
| } |
| }; |
| class B : public A {}; |
| class C : public B { |
| public: |
| constexpr int foo() const override { |
| return B::foo(); // B doesn't have a foo(), so this should call A::foo(). |
| } |
| constexpr int foo2() const { |
| return this->A::foo(); |
| } |
| }; |
| constexpr C c; |
| static_assert(c.foo() == 5); |
| static_assert(c.foo2() == 5); |
| |
| |
| struct S { |
| int _c = 0; |
| virtual constexpr int foo() const { return 1; } |
| }; |
| |
| struct SS : S { |
| int a; |
| constexpr SS() { |
| a = S::foo(); |
| } |
| constexpr int foo() const override { |
| return S::foo(); |
| } |
| }; |
| |
| constexpr SS ss; |
| static_assert(ss.a == 1); |
| } |
| |
| namespace CtorDtor { |
| struct Base { |
| int i = 0; |
| int j = 0; |
| |
| constexpr Base() : i(func()) { |
| j = func(); |
| } |
| constexpr Base(int i) : i(i), j(i) {} |
| |
| constexpr virtual int func() const { return 1; } |
| }; |
| |
| struct Derived : Base { |
| constexpr Derived() {} |
| constexpr Derived(int i) : Base(i) {} |
| constexpr int func() const override { return 2; } |
| }; |
| |
| struct Derived2 : Derived { |
| constexpr Derived2() : Derived(func()) {} // ref-note {{subexpression not valid in a constant expression}} |
| constexpr int func() const override { return 3; } |
| }; |
| |
| constexpr Base B; |
| static_assert(B.i == 1 && B.j == 1, ""); |
| |
| constexpr Derived D; |
| static_assert(D.i == 1, ""); |
| static_assert(D.j == 1, ""); |
| |
| constexpr Derived2 D2; // ref-error {{must be initialized by a constant expression}} \ |
| // ref-note {{in call to 'Derived2()'}} \ |
| // ref-note 2{{declared here}} |
| static_assert(D2.i == 3, ""); // ref-error {{not an integral constant expression}} \ |
| // ref-note {{initializer of 'D2' is not a constant expression}} |
| static_assert(D2.j == 3, ""); // ref-error {{not an integral constant expression}} \ |
| // ref-note {{initializer of 'D2' is not a constant expression}} |
| |
| } |
| |
| namespace VirtualFunctionPointers { |
| struct S { |
| virtual constexpr int func() const { return 1; } |
| }; |
| |
| struct Middle : S { |
| constexpr Middle(int i) : i(i) {} |
| int i; |
| }; |
| |
| struct Other { |
| constexpr Other(int k) : k(k) {} |
| int k; |
| }; |
| |
| struct S2 : Middle, Other { |
| int j; |
| constexpr S2(int i, int j, int k) : Middle(i), Other(k), j(j) {} |
| virtual constexpr int func() const { return i + j + k + S::func(); } |
| }; |
| |
| constexpr S s; |
| constexpr decltype(&S::func) foo = &S::func; |
| constexpr int value = (s.*foo)(); |
| static_assert(value == 1); |
| |
| |
| constexpr S2 s2(1, 2, 3); |
| static_assert(s2.i == 1); |
| static_assert(s2.j == 2); |
| static_assert(s2.k == 3); |
| |
| constexpr int value2 = s2.func(); |
| constexpr int value3 = (s2.*foo)(); |
| static_assert(value3 == 7); |
| |
| constexpr int dynamicDispatch(const S &s) { |
| constexpr decltype(&S::func) SFunc = &S::func; |
| |
| return (s.*SFunc)(); |
| } |
| |
| static_assert(dynamicDispatch(s) == 1); |
| static_assert(dynamicDispatch(s2) == 7); |
| }; |
| |
| }; |
| #endif |
| |
| #if __cplusplus < 202002L |
| 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>), ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{cannot evaluate call to virtual function}} |
| } |
| #endif |
| |
| namespace CompositeDefaultArgs { |
| struct Foo { |
| int a; |
| int b; |
| constexpr Foo() : a(12), b(13) {} |
| }; |
| |
| class Bar { |
| public: |
| bool B = false; |
| |
| constexpr int someFunc(Foo F = Foo()) { |
| this->B = true; |
| return 5; |
| } |
| }; |
| |
| constexpr bool testMe() { |
| Bar B; |
| B.someFunc(); |
| return B.B; |
| } |
| static_assert(testMe(), ""); |
| } |
| |
| constexpr bool BPand(BoolPair bp) { |
| return bp.first && bp.second; |
| } |
| static_assert(BPand(BoolPair{true, false}) == false, ""); |
| |
| namespace TemporaryObjectExpr { |
| struct F { |
| int a; |
| constexpr F() : a(12) {} |
| }; |
| constexpr int foo(F f) { |
| return 0; |
| } |
| static_assert(foo(F()) == 0, ""); |
| } |
| |
| namespace ZeroInit { |
| struct F { |
| int a; |
| }; |
| |
| namespace Simple { |
| struct A { |
| char a; |
| bool b; |
| int c[4]; |
| float d; |
| }; |
| constexpr int foo(A x) { |
| return x.a + static_cast<int>(x.b) + x.c[0] + x.c[3] + static_cast<int>(x.d); |
| } |
| static_assert(foo(A()) == 0, ""); |
| } |
| |
| namespace Inheritance { |
| struct F2 : F { |
| float f; |
| }; |
| |
| constexpr int foo(F2 f) { |
| return (int)f.f + f.a; |
| } |
| static_assert(foo(F2()) == 0, ""); |
| } |
| |
| namespace BitFields { |
| struct F { |
| unsigned a : 6; |
| }; |
| constexpr int foo(F f) { |
| return f.a; |
| } |
| static_assert(foo(F()) == 0, ""); |
| } |
| |
| namespace Nested { |
| struct F2 { |
| float f; |
| char c; |
| }; |
| |
| struct F { |
| F2 f2; |
| int i; |
| }; |
| |
| constexpr int foo(F f) { |
| return f.i + f.f2.f + f.f2.c; |
| } |
| static_assert(foo(F()) == 0, ""); |
| } |
| |
| namespace CompositeArrays { |
| struct F2 { |
| float f; |
| char c; |
| }; |
| |
| struct F { |
| F2 f2[2]; |
| int i; |
| }; |
| |
| constexpr int foo(F f) { |
| return f.i + f.f2[0].f + f.f2[0].c + f.f2[1].f + f.f2[1].c; |
| } |
| static_assert(foo(F()) == 0, ""); |
| } |
| |
| #if __cplusplus > 201402L |
| namespace Unions { |
| struct F { |
| union { |
| int a; |
| char c[4]; |
| float f; |
| } U; |
| int i; |
| }; |
| |
| constexpr int foo(F f) { |
| return f.i + f.U.f; // both-note {{read of member 'f' of union with active member 'a'}} |
| } |
| static_assert(foo(F()) == 0, ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to}} |
| } |
| #endif |
| |
| #if __cplusplus >= 202002L |
| namespace Failure { |
| struct S { |
| int a; |
| F f{12}; |
| }; |
| constexpr int foo(S x) { |
| return x.a; |
| } |
| static_assert(foo(S()) == 0, ""); |
| }; |
| #endif |
| } |
| |
| #if __cplusplus >= 202002L |
| namespace ParenInit { |
| struct A { |
| int a; |
| }; |
| |
| struct B : A { |
| int b; |
| }; |
| |
| constexpr B b(A(1),2); |
| |
| |
| struct O { |
| int &&j; |
| }; |
| |
| /// Not constexpr! |
| O o1(0); // both-warning {{temporary whose address is used as value of}} |
| // FIXME: the secondary warning message is bogus, would be nice to suppress it. |
| constinit O o2(0); // both-error {{variable does not have a constant initializer}} \ |
| // both-note {{required by 'constinit' specifier}} \ |
| // both-note {{reference to temporary is not a constant expression}} \ |
| // both-note {{temporary created here}} \ |
| // both-warning {{temporary whose address is used as value}} |
| |
| |
| /// Initializing an array. |
| constexpr void bar(int i, int j) { |
| int arr[4](i, j); |
| } |
| } |
| #endif |
| |
| namespace DelegatingConstructors { |
| struct S { |
| int a; |
| constexpr S() : S(10) {} |
| constexpr S(int a) : a(a) {} |
| }; |
| constexpr S s = {}; |
| static_assert(s.a == 10, ""); |
| |
| struct B { |
| int a; |
| int b; |
| |
| constexpr B(int a) : a(a), b(a + 2) {} |
| }; |
| struct A : B { |
| constexpr A() : B(10) {}; |
| }; |
| constexpr A d4 = {}; |
| static_assert(d4.a == 10, ""); |
| static_assert(d4.b == 12, ""); |
| } |
| |
| namespace AccessOnNullptr { |
| struct F { |
| int a; |
| }; |
| |
| constexpr int a() { // both-error {{never produces a constant expression}} |
| F *f = nullptr; |
| |
| f->a = 0; // both-note 2{{cannot access field of null pointer}} |
| return f->a; |
| } |
| static_assert(a() == 0, ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to 'a()'}} |
| |
| constexpr int a2() { // both-error {{never produces a constant expression}} |
| F *f = nullptr; |
| |
| |
| const int *a = &(f->a); // both-note 2{{cannot access field of null pointer}} |
| return f->a; |
| } |
| static_assert(a2() == 0, ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to 'a2()'}} |
| } |
| |
| namespace IndirectFieldInit { |
| #if __cplusplus >= 202002L |
| /// Primitive. |
| struct Nested1 { |
| struct { |
| int first; |
| }; |
| int x; |
| constexpr Nested1(int x) : first(12), x() { x = 4; } |
| constexpr Nested1() : Nested1(42) {} |
| }; |
| constexpr Nested1 N1{}; |
| static_assert(N1.first == 12, ""); |
| |
| /// Composite. |
| struct Nested2 { |
| struct First { int x = 42; }; |
| struct { |
| First first; |
| }; |
| int x; |
| constexpr Nested2(int x) : first(12), x() { x = 4; } |
| constexpr Nested2() : Nested2(42) {} |
| }; |
| constexpr Nested2 N2{}; |
| static_assert(N2.first.x == 12, ""); |
| |
| /// Bitfield. |
| struct Nested3 { |
| struct { |
| unsigned first : 2; |
| }; |
| int x; |
| constexpr Nested3(int x) : first(3), x() { x = 4; } |
| constexpr Nested3() : Nested3(42) {} |
| }; |
| |
| constexpr Nested3 N3{}; |
| static_assert(N3.first == 3, ""); |
| |
| /// Test that we get the offset right if the |
| /// record has a base. |
| struct Nested4Base { |
| int a; |
| int b; |
| char c; |
| }; |
| struct Nested4 : Nested4Base{ |
| struct { |
| int first; |
| }; |
| int x; |
| constexpr Nested4(int x) : first(123), x() { a = 1; b = 2; c = 3; x = 4; } |
| constexpr Nested4() : Nested4(42) {} |
| }; |
| constexpr Nested4 N4{}; |
| static_assert(N4.first == 123, ""); |
| |
| struct S { |
| struct { |
| int x, y; |
| }; |
| |
| constexpr S(int x_, int y_) : x(x_), y(y_) {} |
| }; |
| |
| constexpr S s(1, 2); |
| static_assert(s.x == 1 && s.y == 2); |
| |
| struct S2 { |
| int a; |
| struct { |
| int b; |
| struct { |
| int x, y; |
| }; |
| }; |
| |
| constexpr S2(int x_, int y_) : a(3), b(4), x(x_), y(y_) {} |
| }; |
| |
| constexpr S2 s2(1, 2); |
| static_assert(s2.x == 1 && s2.y == 2 && s2.a == 3 && s2.b == 4); |
| |
| #endif |
| } |
| |
| namespace InheritedConstructor { |
| namespace PR47555 { |
| struct A { |
| int c; |
| int d; |
| constexpr A(int c, int d) : c(c), d(d){} |
| }; |
| struct B : A { using A::A; }; |
| |
| constexpr B b = {13, 1}; |
| static_assert(b.c == 13, ""); |
| static_assert(b.d == 1, ""); |
| } |
| |
| namespace PR47555_2 { |
| struct A { |
| int c; |
| int d; |
| double e; |
| constexpr A(int c, int &d, double e) : c(c), d(++d), e(e){} |
| }; |
| struct B : A { using A::A; }; |
| |
| constexpr int f() { |
| int a = 10; |
| B b = {10, a, 40.0}; |
| return a; |
| } |
| static_assert(f() == 11, ""); |
| } |
| |
| namespace AaronsTest { |
| struct T { |
| constexpr T(float) {} |
| }; |
| |
| struct Base { |
| constexpr Base(T t = 1.0f) {} |
| constexpr Base(float) {} |
| }; |
| |
| struct FirstMiddle : Base { |
| using Base::Base; |
| constexpr FirstMiddle() : Base(2.0f) {} |
| }; |
| |
| struct SecondMiddle : Base { |
| constexpr SecondMiddle() : Base(3.0f) {} |
| constexpr SecondMiddle(T t) : Base(t) {} |
| }; |
| |
| struct S : FirstMiddle, SecondMiddle { |
| using FirstMiddle::FirstMiddle; |
| constexpr S(int i) : S(4.0f) {} |
| }; |
| |
| constexpr S s(1); |
| } |
| } |
| |
| namespace InvalidCtorInitializer { |
| struct X { |
| int Y; |
| constexpr X() |
| : Y(fo_o_()) {} // both-error {{use of undeclared identifier 'fo_o_'}} |
| }; |
| // no crash on evaluating the constexpr ctor. |
| constexpr int Z = X().Y; // both-error {{constexpr variable 'Z' must be initialized by a constant expression}} |
| } |
| |
| extern int f(); // both-note {{here}} |
| struct HasNonConstExprMemInit { |
| int x = f(); // both-note {{non-constexpr function}} |
| constexpr HasNonConstExprMemInit() {} // both-error {{never produces a constant expression}} |
| }; |
| |
| namespace { |
| template <class Tp, Tp v> |
| struct integral_constant { |
| static const Tp value = v; |
| }; |
| |
| template <class Tp, Tp v> |
| const Tp integral_constant<Tp, v>::value; |
| |
| typedef integral_constant<bool, true> true_type; |
| typedef integral_constant<bool, false> false_type; |
| |
| /// This might look innocent, but we get an evaluateAsInitializer call for the |
| /// static bool member before evaluating the first static_assert, but we do NOT |
| /// get such a call for the second one. So the second one needs to lazily visit |
| /// the data member itself. |
| static_assert(true_type::value, ""); |
| static_assert(true_type::value, ""); |
| } |
| |
| #if __cplusplus >= 202002L |
| namespace { |
| /// Used to crash because the CXXDefaultInitExpr is of compound type. |
| struct A { |
| int &x; |
| constexpr ~A() { --x; } |
| }; |
| struct B { |
| int &x; |
| const A &a = A{x}; |
| }; |
| constexpr int a() { |
| int x = 1; |
| int f = B{x}.x; |
| B{x}; // both-warning {{expression result unused}} |
| |
| return 1; |
| } |
| } |
| #endif |
| |
| namespace pr18633 { |
| struct A1 { |
| static const int sz; |
| static const int sz2; |
| }; |
| const int A1::sz2 = 11; |
| template<typename T> |
| void func () { |
| int arr[A1::sz]; |
| // both-warning@-1 {{variable length arrays in C++ are a Clang extension}} |
| // both-note@-2 {{initializer of 'sz' is unknown}} |
| // both-note@-9 {{declared here}} |
| } |
| template<typename T> |
| void func2 () { |
| int arr[A1::sz2]; |
| } |
| const int A1::sz = 12; |
| void func2() { |
| func<int>(); |
| func2<int>(); |
| } |
| } |
| |
| namespace { |
| struct F { |
| static constexpr int Z = 12; |
| }; |
| F f; |
| static_assert(f.Z == 12, ""); |
| } |
| |
| namespace UnnamedBitFields { |
| struct A { |
| int : 1; |
| double f; |
| int : 1; |
| char c; |
| }; |
| |
| constexpr A a = (A){1.0, 'a'}; |
| static_assert(a.f == 1.0, ""); |
| static_assert(a.c == 'a', ""); |
| } |
| |
| namespace VirtualBases { |
| /// This used to crash. |
| namespace One { |
| class A { |
| protected: |
| int x; |
| }; |
| class B : public virtual A { |
| public: |
| int getX() { return x; } // both-note {{declared here}} |
| }; |
| |
| class DV : virtual public B{}; |
| |
| void foo() { |
| DV b; |
| int a[b.getX()]; // both-warning {{variable length arrays}} \ |
| // both-note {{non-constexpr function 'getX' cannot be used}} |
| } |
| } |
| |
| namespace Two { |
| struct U { int n; }; |
| struct A : virtual U { int n; }; |
| struct B : A {}; |
| B a; |
| static_assert((U*)(A*)(&a) == (U*)(&a), ""); |
| |
| struct C : virtual A {}; |
| struct D : B, C {}; |
| D d; |
| constexpr B *p = &d; |
| constexpr C *q = &d; |
| static_assert((A*)p == (A*)q, ""); // both-error {{failed}} |
| } |
| |
| namespace Three { |
| struct U { int n; }; |
| struct V : U { int n; }; |
| struct A : virtual V { int n; }; |
| struct Aa { int n; }; |
| struct B : virtual A, Aa {}; |
| |
| struct C : virtual A, Aa {}; |
| |
| struct D : B, C {}; |
| |
| D d; |
| |
| constexpr B *p = &d; |
| constexpr C *q = &d; |
| |
| static_assert((void*)p != (void*)q, ""); |
| static_assert((A*)p == (A*)q, ""); |
| static_assert((Aa*)p != (Aa*)q, ""); |
| |
| constexpr V *v = p; |
| constexpr V *w = q; |
| constexpr V *x = (A*)p; |
| static_assert(v == w, ""); |
| static_assert(v == x, ""); |
| |
| static_assert((U*)&d == p, ""); |
| static_assert((U*)&d == q, ""); |
| static_assert((U*)&d == v, ""); |
| static_assert((U*)&d == w, ""); |
| static_assert((U*)&d == x, ""); |
| |
| struct X {}; |
| struct Y1 : virtual X {}; |
| struct Y2 : X {}; |
| struct Z : Y1, Y2 {}; |
| Z z; |
| static_assert((X*)(Y1*)&z != (X*)(Y2*)&z, ""); |
| } |
| } |
| |
| namespace ZeroInit { |
| struct S3 { |
| S3() = default; |
| S3(const S3&) = default; |
| S3(S3&&) = default; |
| constexpr S3(int n) : n(n) {} |
| int n; |
| }; |
| constexpr S3 s3d; // both-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}} |
| static_assert(s3d.n == 0, ""); |
| |
| struct P { |
| int a = 10; |
| }; |
| static_assert(P().a == 10, ""); |
| } |
| |
| namespace { |
| #if __cplusplus >= 202002L |
| struct C { |
| template <unsigned N> constexpr C(const char (&)[N]) : n(N) {} |
| unsigned n; |
| }; |
| template <C c> |
| constexpr auto operator""_c() { return c.n; } |
| |
| constexpr auto waldo = "abc"_c; |
| static_assert(waldo == 4, ""); |
| #endif |
| } |
| |
| |
| namespace TemporaryWithInvalidDestructor { |
| #if __cplusplus >= 202002L |
| struct A { |
| bool a = true; |
| constexpr ~A() noexcept(false) { // both-error {{never produces a constant expression}} |
| throw; // both-note 2{{not valid in a constant expression}} \ |
| // both-error {{cannot use 'throw' with exceptions disabled}} |
| } |
| }; |
| static_assert(A().a, ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to}} |
| #endif |
| } |
| |
| namespace IgnoredCtorWithZeroInit { |
| struct S { |
| int a; |
| }; |
| |
| bool get_status() { |
| return (S(), true); |
| } |
| } |
| |
| #if __cplusplus >= 202002L |
| namespace VirtOperator { |
| /// This used to crash because it's a virtual CXXOperatorCallExpr. |
| struct B { |
| virtual constexpr bool operator==(const B&) const { return true; } |
| }; |
| struct D : B { |
| constexpr bool operator==(const B&) const override{ return false; } // both-note {{operator}} |
| }; |
| constexpr bool cmp_base_derived = D() == D(); // both-warning {{ambiguous}} |
| } |
| |
| namespace FloatAPValue { |
| struct ClassTemplateArg { |
| int a; |
| float f; |
| }; |
| template<ClassTemplateArg A> struct ClassTemplateArgTemplate { |
| static constexpr const ClassTemplateArg &Arg = A; |
| }; |
| ClassTemplateArgTemplate<ClassTemplateArg{1, 2.0f}> ClassTemplateArgObj; |
| template<const ClassTemplateArg&> struct ClassTemplateArgRefTemplate {}; |
| ClassTemplateArgRefTemplate<ClassTemplateArgObj.Arg> ClassTemplateArgRefObj; |
| } |
| #endif |
| |
| namespace LocalWithThisPtrInit { |
| struct S { |
| int i; |
| int *p = &i; |
| }; |
| constexpr int foo() { |
| S s{2}; |
| return *s.p; |
| } |
| static_assert(foo() == 2, ""); |
| } |
| |
| namespace OnePastEndAndBack { |
| struct Base { |
| constexpr Base() {} |
| int n = 0; |
| }; |
| |
| constexpr Base a; |
| constexpr const Base *c = &a + 1; |
| constexpr const Base *d = c - 1; |
| static_assert(d == &a, ""); |
| } |
| |
| namespace BitSet { |
| class Bitset { |
| unsigned Bit = 0; |
| |
| public: |
| constexpr Bitset() { |
| int Init[2] = {1,2}; |
| for (auto I : Init) |
| set(I); |
| } |
| constexpr void set(unsigned I) { |
| this->Bit++; |
| this->Bit = 1u << 1; |
| } |
| }; |
| |
| struct ArchInfo { |
| Bitset DefaultExts; |
| }; |
| |
| constexpr ArchInfo ARMV8A = { |
| Bitset() |
| }; |
| } |
| |
| namespace ArrayInitChain { |
| struct StringLiteral { |
| const char *S; |
| }; |
| |
| struct CustomOperandVal { |
| StringLiteral Str; |
| unsigned Width; |
| unsigned Mask = Width + 1; |
| }; |
| |
| constexpr CustomOperandVal A[] = { |
| {}, |
| {{"depctr_hold_cnt"}, 12, 13}, |
| }; |
| static_assert(A[0].Str.S == nullptr, ""); |
| static_assert(A[0].Width == 0, ""); |
| static_assert(A[0].Mask == 1, ""); |
| |
| static_assert(A[1].Width == 12, ""); |
| static_assert(A[1].Mask == 13, ""); |
| } |
| |
| #if __cplusplus >= 202002L |
| namespace ctorOverrider { |
| // Ensure that we pick the right final overrider during construction. |
| struct A { |
| virtual constexpr char f() const { return 'A'; } |
| char a = f(); |
| }; |
| |
| struct Covariant1 { |
| A d; |
| }; |
| |
| constexpr Covariant1 cb; |
| } |
| #endif |
| |
| #if __cplusplus >= 202002L |
| namespace VirtDtor { |
| struct X { char *p; constexpr ~X() { *p++ = 'X'; } }; |
| struct Y : X { int y; virtual constexpr ~Y() { *p++ = 'Y'; } }; |
| struct Z : Y { int z; constexpr ~Z() override { *p++ = 'Z'; } }; |
| |
| union VU { |
| constexpr VU() : z() {} |
| constexpr ~VU() {} |
| Z z; |
| }; |
| |
| constexpr char virt_dtor(int mode, const char *expected) { |
| char buff[4] = {}; |
| VU vu; |
| vu.z.p = buff; |
| |
| ((Y&)vu.z).~Y(); |
| return true; |
| } |
| static_assert(virt_dtor(0, "ZYX")); |
| } |
| |
| namespace DtorDestroysFieldsAfterSelf { |
| struct S { |
| int a = 10; |
| constexpr ~S() { |
| a = 0; |
| } |
| |
| }; |
| struct F { |
| S s; |
| int a; |
| int &b; |
| constexpr F(int a, int &b) : a(a), b(b) {} |
| constexpr ~F() { |
| b += s.a; |
| } |
| }; |
| |
| constexpr int foo() { |
| int a = 10; |
| int b = 5; |
| { |
| F f(a, b); |
| } |
| |
| return b; |
| } |
| |
| static_assert(foo() == 15); |
| } |
| #endif |
| |
| namespace ExprWithCleanups { |
| struct A { A(); ~A(); int get(); }; |
| constexpr int get() {return false ? A().get() : 1;} |
| static_assert(get() == 1, ""); |
| |
| |
| struct S { |
| int V; |
| constexpr S(int V) : V(V) {} |
| constexpr int get() { |
| return V; |
| } |
| }; |
| constexpr int get(bool b) { |
| S a = b ? S(1) : S(2); |
| |
| return a.get(); |
| } |
| static_assert(get(true) == 1, ""); |
| static_assert(get(false) == 2, ""); |
| |
| |
| constexpr auto F = true ? 1i : 2i; |
| static_assert(F == 1i, ""); |
| } |
| |
| namespace NullptrCast { |
| struct A {}; |
| struct B : A { int n; }; |
| constexpr A *na = nullptr; |
| constexpr B *nb = nullptr; |
| constexpr A &ra = *nb; // both-error {{constant expression}} \ |
| // ref-note {{dereferencing a null pointer}} \ |
| // expected-note {{cannot access base class of null pointer}} |
| constexpr B &rb = (B&)*na; // both-error {{constant expression}} \ |
| // ref-note {{dereferencing a null pointer}} \ |
| // expected-note {{cannot access derived class of null pointer}} |
| constexpr bool test() { |
| auto a = (A*)(B*)nullptr; |
| |
| return a == nullptr; |
| } |
| static_assert(test(), ""); |
| |
| constexpr bool test2() { |
| auto a = (B*)(A*)nullptr; |
| |
| return a == nullptr; |
| } |
| static_assert(test2(), ""); |
| } |
| |
| namespace NonConst { |
| template <int I> |
| struct S { |
| static constexpr int Size = I; |
| constexpr int getSize() const { return I; } |
| explicit S(int a) {} |
| }; |
| |
| void func() { |
| int a,b ; |
| const S<10> s{a}; |
| static_assert(s.getSize() == 10, ""); |
| } |
| } |
| |
| namespace ExplicitThisInTemporary { |
| struct B { B *p = this; }; |
| constexpr bool g(B b) { return &b == b.p; } |
| static_assert(g({}), ""); |
| } |
| |
| namespace IgnoredMemberExpr { |
| class A { |
| public: |
| int a; |
| }; |
| class B : public A { |
| public: |
| constexpr int foo() { |
| a; // both-warning {{expression result unused}} |
| return 0; |
| } |
| }; |
| static_assert(B{}.foo() == 0, ""); |
| } |
| |
| #if __cplusplus >= 202002L |
| namespace DeadUpcast { |
| struct A {}; |
| struct B : A{}; |
| constexpr bool foo() { |
| |
| B *pb; |
| { |
| B b; |
| pb = &b; |
| } |
| A *pa = pb; |
| |
| return true; |
| } |
| static_assert(foo(), ""); |
| } |
| #endif |
| |
| namespace CtorOfInvalidClass { |
| constexpr struct { Unknown U; } InvalidCtor; // both-error {{unknown type name 'Unknown'}} \ |
| // both-error {{must be initialized by a constant expression}} |
| |
| #if __cplusplus >= 202002L |
| template <typename T, auto Q> |
| concept ReferenceOf = Q; |
| /// This calls a valid and constexpr copy constructor of InvalidCtor, |
| /// but should still be rejected. |
| template<ReferenceOf<InvalidCtor> auto R, typename Rep> int F; // both-error {{non-type template argument is not a constant expression}} |
| #endif |
| } |
| |
| namespace IncompleteTypes { |
| struct Incomplete; |
| |
| constexpr bool foo() { |
| extern Incomplete bounded[10]; |
| extern Incomplete unbounded[]; |
| extern Incomplete IT; |
| return true; |
| } |
| static_assert(foo(), ""); |
| } |
| |
| namespace RedeclaredCtor { |
| |
| struct __sp_mut { |
| void *__lx_; |
| constexpr __sp_mut(void *) noexcept; |
| }; |
| int mut_back[1]; |
| |
| constexpr __sp_mut::__sp_mut(void *p) noexcept : __lx_(p) {} |
| constexpr __sp_mut muts = &mut_back[0]; |
| } |
| |
| namespace IntegralBaseCast { |
| class A {}; |
| class B : public A {}; |
| struct S { |
| B *a; |
| }; |
| |
| constexpr int f() { |
| S s{}; |
| A *a = s.a; |
| return 0; |
| } |
| |
| static_assert(f() == 0, ""); |
| } |
| |
| namespace AccessMismatch { |
| struct A { |
| public: |
| constexpr A() : a(0), b(0) {} |
| int a; |
| constexpr bool cmp() const { return &a < &b; } // both-note {{comparison of address of fields 'a' and 'b' of 'A' with differing access specifiers (public vs private) has unspecified value}} |
| private: |
| int b; |
| }; |
| static_assert(A().cmp(), ""); // both-error {{constant expression}} \ |
| // both-note {{in call}} |
| |
| class B { |
| public: |
| A a; |
| constexpr bool cmp() const { return &a.a < &b.a; } // both-note {{comparison of address of fields 'a' and 'b' of 'B' with differing access specifiers (public vs protected) has unspecified value}} |
| protected: |
| A b; |
| }; |
| static_assert(B().cmp(), ""); // both-error {{constant expression}} \ |
| // both-note {{in call}} |
| } |
| |
| namespace GlobalDtor { |
| struct A { |
| }; |
| constexpr A a = {}; |
| constexpr void destroy1() { // both-error {{constexpr}} |
| a.~A(); // both-note {{cannot modify an object that is visible outside}} |
| } |
| } |
| |
| namespace NullDtor { |
| struct S {}; |
| constexpr int foo() { // both-error {{never produces a constant expression}} |
| S *s = nullptr; |
| s->~S(); // both-note 2{{destruction of dereferenced null pointer is not allowed in a constant expression}} |
| return 10; |
| } |
| static_assert(foo() == 10, ""); // both-error {{not an integral constant expression}} \ |
| // both-note {{in call to}} |
| } |
| |
| namespace DiamondDowncast { |
| struct Top {}; |
| struct Middle1 : Top {}; |
| struct Middle2 : Top {}; |
| struct Bottom : Middle1, Middle2 {}; |
| |
| constexpr Bottom bottom; |
| constexpr Top &top1 = (Middle1&)bottom; |
| constexpr Middle2 &fail = (Middle2&)top1; // both-error {{must be initialized by a constant expression}} \ |
| // both-note {{cannot cast object of dynamic type 'const Bottom' to type 'Middle2'}} |
| } |