blob: 5fd423eff025beca6d7a68ca32ee5dfe6f7cb920 [file] [log] [blame]
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple i686 -verify %s
// RUN: %clang_cc1 -verify=ref %s
// RUN: %clang_cc1 -verify=ref -std=c++14 %s
// RUN: %clang_cc1 -verify=ref -std=c++20 %s
// RUN: %clang_cc1 -verify=ref -triple i686 %s
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; // expected-error {{without a user-provided default constructor}} \
// expected-error {{must be initialized by a constant expression}} \
// ref-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, "");
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 { // expected-note {{definition of 'Bar' is not complete}} \
// ref-note {{definition of 'Bar' is not complete}}
public:
constexpr Bar(){}
constexpr Bar b; // expected-error {{cannot be constexpr}} \
// expected-error {{has incomplete type 'const Bar'}} \
// ref-error {{cannot be constexpr}} \
// ref-error {{has incomplete type 'const Bar'}}
};
constexpr Bar B; // expected-error {{must be initialized by a constant expression}} \
// expected-error {{failed to evaluate an expression}} \
// ref-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() { // ref-error {{never produces a constant expression}} \
// expected-error {{never produces a constant expression}}
S *s = nullptr;
return s->get12(); // ref-note 2{{member call on dereferenced null pointer}} \
// expected-note 2{{member call on dereferenced null pointer}}
}
static_assert(foo() == 12, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{in call to 'foo()'}} \
// expected-error {{not an integral constant expression}} \
// expected-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, ""); // ref-error {{static assertion failed}} \
// ref-note {{evaluates to '12 == 200'}} \
// expected-error {{static assertion failed}} \
// expected-note {{evaluates to '12 == 200'}}
struct S {
int a = 0;
constexpr int get5() const { return 5; }
constexpr void fo() const {
this; // expected-warning {{expression result unused}} \
// ref-warning {{expression result unused}}
this->a; // expected-warning {{expression result unused}} \
// ref-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;
{
auto T = 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);
#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 { // ref-note 2{{declared here}} expected-note {{declared here}}
int Val;
};
struct Derived : Base {
int OtherVal;
constexpr Derived(int i) : OtherVal(i) {} // ref-error {{never produces a constant expression}} \
// ref-note 2{{non-constexpr constructor 'Base' cannot be used in a constant expression}} \
// expected-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}}
};
constexpr Derived D(12); // ref-error {{must be initialized by a constant expression}} \
// ref-note {{in call to 'Derived(12)'}} \
// ref-note {{declared here}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{in call to 'Derived(12)'}}
static_assert(D.Val == 0, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{initializer of 'D' is not a constant expression}} \
// expected-error {{not an integral constant expression}} \
// expected-note {{read of uninitialized object}}
#endif
struct AnotherBase {
int Val;
constexpr AnotherBase(int i) : Val(12 / i) {} //ref-note {{division by zero}} \
//expected-note {{division by zero}}
};
struct AnotherDerived : AnotherBase {
constexpr AnotherDerived(int i) : AnotherBase(i) {}
};
constexpr AnotherBase Derp(0); // ref-error {{must be initialized by a constant expression}} \
// ref-note {{in call to 'AnotherBase(0)'}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{in call to 'AnotherBase(0)'}}
struct YetAnotherBase {
int Val;
constexpr YetAnotherBase(int i) : Val(i) {}
};
struct YetAnotherDerived : YetAnotherBase {
using YetAnotherBase::YetAnotherBase; // ref-note {{declared here}} \
// expected-note {{declared here}}
int OtherVal;
constexpr bool doit() const { return Val == OtherVal; }
};
constexpr YetAnotherDerived Oops(0); // ref-error {{must be initialized by a constant expression}} \
// ref-note {{constructor inherited from base class 'YetAnotherBase' cannot be used in a constant expression}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-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, "");
};
/// FIXME: The following tests are broken.
/// They are using CXXDefaultInitExprs which contain a CXXThisExpr. The This pointer
/// in those refers to the declaration we are currently initializing, *not* the
/// This pointer of the current stack frame. This is something we haven't
/// implemented in the new interpreter yet.
namespace DeclRefs {
struct A{ int m; const int &f = m; }; // expected-note {{implicit use of 'this'}}
constexpr A a{10}; // expected-error {{must be initialized by a constant expression}}
static_assert(a.m == 10, "");
static_assert(a.f == 10, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{read of uninitialized object}}
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;
/// FIXME: The following two lines don't work because we don't get the
/// pointers on the LHS correct. They make us run into an assertion
/// in CheckEvaluationResult. However, this may just be caused by the
/// problems in the previous examples.
//static_assert(b.a.m == 100, "");
//static_assert(b.a.f == 100, "");
}
#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);
}
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, ""); // expected-error {{static assertion failed}} \
// expected-note {{2 == 1}}
static_assert(D.j == 1, ""); // expected-error {{static assertion failed}} \
// expected-note {{2 == 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}}
}
};
#endif