366 lines
10 KiB
C++
366 lines
10 KiB
C++
// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++14-extensions -Werror=c++20-extensions %s
|
|
// RUN: %clang_cc1 -verify -std=c++14 -fcxx-exceptions -DCXX14 -Werror=c++20-extensions %s
|
|
// RUN: %clang_cc1 -verify -std=c++20 -fcxx-exceptions -DCXX14 -DCXX2A %s
|
|
|
|
namespace N {
|
|
typedef char C;
|
|
}
|
|
|
|
namespace M {
|
|
typedef double D;
|
|
}
|
|
|
|
struct NonLiteral { // expected-note 2{{no constexpr constructors}}
|
|
NonLiteral() {}
|
|
NonLiteral(int) {}
|
|
};
|
|
struct Literal {
|
|
constexpr Literal() {}
|
|
explicit Literal(int); // expected-note 2 {{here}}
|
|
operator int() const { return 0; }
|
|
};
|
|
|
|
// In the definition of a constexpr constructor, each of the parameter types
|
|
// shall be a literal type.
|
|
struct S {
|
|
constexpr S(int, N::C) {}
|
|
constexpr S(int, NonLiteral, N::C) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
|
|
constexpr S(int, NonLiteral = 42) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
|
|
|
|
// In addition, either its function-body shall be = delete or = default
|
|
constexpr S() = default;
|
|
constexpr S(Literal) = delete;
|
|
};
|
|
|
|
// or it shall satisfy the following constraints:
|
|
|
|
// - the class shall not have any virtual base classes;
|
|
struct T : virtual S { // expected-note {{here}}
|
|
constexpr T() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
|
|
};
|
|
namespace IndirectVBase {
|
|
struct A {};
|
|
struct B : virtual A {}; // expected-note {{here}}
|
|
class C : public B {
|
|
public:
|
|
constexpr C() {} // expected-error {{constexpr constructor not allowed in class with virtual base class}}
|
|
};
|
|
}
|
|
|
|
// - its function-body shall not be a function-try-block;
|
|
struct U {
|
|
constexpr U()
|
|
try
|
|
#ifndef CXX2A
|
|
// expected-error@-2 {{function try block in constexpr constructor is a C++20 extension}}
|
|
#endif
|
|
: u() {
|
|
#ifndef CXX14
|
|
// expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}}
|
|
#endif
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
int u;
|
|
};
|
|
|
|
// - the compound-statememt of its function-body shall contain only
|
|
struct V {
|
|
constexpr V() {
|
|
// - null statements,
|
|
;
|
|
|
|
// - static_assert-declarations,
|
|
static_assert(true, "the impossible happened!");
|
|
|
|
// - typedef declarations and alias-declarations that do not define classes
|
|
// or enumerations,
|
|
typedef int I;
|
|
typedef struct S T;
|
|
using J = int;
|
|
using K = int[sizeof(I) + sizeof(J)];
|
|
// Note, the standard requires we reject this.
|
|
struct U;
|
|
|
|
// - using-declarations,
|
|
using N::C;
|
|
|
|
// - and using-directives;
|
|
using namespace N;
|
|
}
|
|
|
|
constexpr V(int(&)[1]) {
|
|
for (int n = 0; n < 10; ++n)
|
|
/**/;
|
|
#ifndef CXX14
|
|
// expected-error@-3 {{statement not allowed in constexpr constructor}}
|
|
#endif
|
|
}
|
|
constexpr V(int(&)[2]) {
|
|
constexpr int a = 0;
|
|
#ifndef CXX14
|
|
// expected-error@-2 {{variable declaration in a constexpr constructor is a C++14 extension}}
|
|
#endif
|
|
}
|
|
constexpr V(int(&)[3]) {
|
|
constexpr int ForwardDecl(int);
|
|
#ifndef CXX14
|
|
// expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}}
|
|
#endif
|
|
}
|
|
constexpr V(int(&)[4]) {
|
|
typedef struct { } S1;
|
|
#ifndef CXX14
|
|
// expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}}
|
|
#endif
|
|
}
|
|
constexpr V(int(&)[5]) {
|
|
using S2 = struct { };
|
|
#ifndef CXX14
|
|
// expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}}
|
|
#endif
|
|
}
|
|
constexpr V(int(&)[6]) {
|
|
struct S3 { };
|
|
#ifndef CXX14
|
|
// expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}}
|
|
#endif
|
|
}
|
|
constexpr V(int(&)[7]) {
|
|
return;
|
|
#ifndef CXX14
|
|
// expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}}
|
|
#endif
|
|
}
|
|
};
|
|
|
|
// - every non-static data member and base class sub-object shall be initialized
|
|
struct W {
|
|
int n;
|
|
constexpr W() {}
|
|
#ifndef CXX2A
|
|
// expected-error@-2 {{constexpr constructor that does not initialize all members}}
|
|
// expected-note@-4 {{member not initialized by constructor}}
|
|
#endif
|
|
};
|
|
struct AnonMembers {
|
|
int a; // expected-note 0-1{{member not initialized by constructor}}
|
|
union { // expected-note 0-2{{member not initialized by constructor}}
|
|
char b;
|
|
struct {
|
|
double c;
|
|
long d; // expected-note 0-1{{member not initialized by constructor}}
|
|
};
|
|
union {
|
|
char e;
|
|
void *f;
|
|
};
|
|
};
|
|
struct { // expected-note 0-1{{member not initialized by constructor}}
|
|
long long g;
|
|
struct {
|
|
int h; // expected-note 0-1{{member not initialized by constructor}}
|
|
double i; // expected-note 0-1{{member not initialized by constructor}}
|
|
};
|
|
union { // expected-note 0-2{{member not initialized by constructor}}
|
|
char *j;
|
|
AnonMembers *k;
|
|
};
|
|
};
|
|
|
|
constexpr AnonMembers(int(&)[1]) : a(), b(), g(), h(), i(), j() {} // ok
|
|
// missing d, i, j/k union
|
|
constexpr AnonMembers(int(&)[2]) : a(), c(), g(), h() {}
|
|
#ifndef CXX2A
|
|
// expected-error@-2 {{constexpr constructor that does not initialize all members}}
|
|
#endif
|
|
constexpr AnonMembers(int(&)[3]) : a(), e(), g(), h(), i(), k() {} // ok
|
|
// missing h, j/k union
|
|
constexpr AnonMembers(int(&)[4]) : a(), c(), d(), g(), i() {}
|
|
#ifndef CXX2A
|
|
// expected-error@-2 {{constexpr constructor that does not initialize all members}}
|
|
#endif
|
|
// missing b/c/d/e/f union
|
|
constexpr AnonMembers(int(&)[5]) : a(), g(), h(), i(), k() {}
|
|
#ifndef CXX2A
|
|
// expected-error@-2 {{constexpr constructor that does not initialize all members}}
|
|
#endif
|
|
// missing a, b/c/d/e/f union, g/h/i/j/k struct
|
|
constexpr AnonMembers(int(&)[6]) {}
|
|
#ifndef CXX2A
|
|
// expected-error@-2 {{constexpr constructor that does not initialize all members}}
|
|
#endif
|
|
};
|
|
|
|
union Empty {
|
|
constexpr Empty() {} // ok
|
|
} constexpr empty1;
|
|
|
|
struct EmptyVariant {
|
|
union {}; // expected-warning {{does not declare anything}}
|
|
struct {}; // expected-warning {{does not declare anything}}
|
|
constexpr EmptyVariant() {} // ok
|
|
} constexpr empty2;
|
|
|
|
template<typename T> using Int = int;
|
|
template<typename T>
|
|
struct TemplateInit {
|
|
T a;
|
|
int b; // desired-note {{not initialized}}
|
|
Int<T> c; // desired-note {{not initialized}}
|
|
struct {
|
|
T d;
|
|
int e; // desired-note {{not initialized}}
|
|
Int<T> f; // desired-note {{not initialized}}
|
|
};
|
|
struct {
|
|
Literal l;
|
|
Literal m;
|
|
Literal n[3];
|
|
};
|
|
union { // desired-note {{not initialized}}
|
|
T g;
|
|
T h;
|
|
};
|
|
// FIXME: This is ill-formed (no diagnostic required). We should diagnose it.
|
|
constexpr TemplateInit() {} // desired-error {{must initialize all members}}
|
|
};
|
|
template<typename T> struct TemplateInit2 {
|
|
Literal l;
|
|
constexpr TemplateInit2() {} // ok
|
|
};
|
|
|
|
template<typename T> struct weak_ptr {
|
|
constexpr weak_ptr() : p(0) {}
|
|
T *p;
|
|
};
|
|
template<typename T> struct enable_shared_from_this {
|
|
weak_ptr<T> weak_this;
|
|
constexpr enable_shared_from_this() {} // ok
|
|
};
|
|
constexpr int f(enable_shared_from_this<int>);
|
|
|
|
// - every constructor involved in initializing non-static data members and base
|
|
// class sub-objects shall be a constexpr constructor.
|
|
struct ConstexprBaseMemberCtors : Literal {
|
|
Literal l;
|
|
|
|
constexpr ConstexprBaseMemberCtors() : Literal(), l() {} // ok
|
|
constexpr ConstexprBaseMemberCtors(char) : // expected-error {{constexpr constructor never produces a constant expression}}
|
|
Literal(0), // expected-note {{non-constexpr constructor}}
|
|
l() {}
|
|
constexpr ConstexprBaseMemberCtors(double) : Literal(), // expected-error {{constexpr constructor never produces a constant expression}}
|
|
l(0) // expected-note {{non-constexpr constructor}}
|
|
{}
|
|
};
|
|
|
|
// - every assignment-expression that is an initializer-clause appearing
|
|
// directly or indirectly within a brace-or-equal-initializer for a non-static
|
|
// data member that is not named by a mem-initializer-id shall be a constant
|
|
// expression; and
|
|
//
|
|
// Note, we deliberately do not implement this bullet, so that we can allow the
|
|
// following example. (See N3308).
|
|
struct X {
|
|
int a = 0;
|
|
int b = 2 * a + 1; // ok, not a constant expression.
|
|
|
|
constexpr X() {}
|
|
constexpr X(int c) : a(c) {} // ok, b initialized by 2 * c + 1
|
|
};
|
|
|
|
union XU1 { int a; constexpr XU1() = default; };
|
|
#ifndef CXX2A
|
|
// expected-error@-2{{not constexpr}}
|
|
#endif
|
|
union XU2 { int a = 1; constexpr XU2() = default; };
|
|
|
|
struct XU3 {
|
|
union {
|
|
int a;
|
|
};
|
|
constexpr XU3() = default;
|
|
#ifndef CXX2A
|
|
// expected-error@-2{{not constexpr}}
|
|
#endif
|
|
};
|
|
struct XU4 {
|
|
union {
|
|
int a = 1;
|
|
};
|
|
constexpr XU4() = default;
|
|
};
|
|
|
|
static_assert(XU2().a == 1, "");
|
|
static_assert(XU4().a == 1, "");
|
|
|
|
// - every implicit conversion used in converting a constructor argument to the
|
|
// corresponding parameter type and converting a full-expression to the
|
|
// corresponding member type shall be one of those allowed in a constant
|
|
// expression.
|
|
//
|
|
// We implement the proposed resolution of DR1364 and ignore this bullet.
|
|
// However, we implement the intent of this wording as part of the p5 check that
|
|
// the function must be able to produce a constant expression.
|
|
int kGlobal; // expected-note {{here}}
|
|
struct Z {
|
|
constexpr Z(int a) : n(a) {}
|
|
constexpr Z() : n(kGlobal) {} // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
|
|
int n;
|
|
};
|
|
|
|
|
|
namespace StdExample {
|
|
struct Length {
|
|
explicit constexpr Length(int i = 0) : val(i) { }
|
|
private:
|
|
int val;
|
|
};
|
|
}
|
|
|
|
namespace CtorLookup {
|
|
// Ensure that we look up which constructor will actually be used.
|
|
struct A {
|
|
constexpr A(const A&) {}
|
|
A(A&) {}
|
|
constexpr A(int = 0);
|
|
};
|
|
|
|
struct B : A {
|
|
B() = default;
|
|
constexpr B(const B&);
|
|
constexpr B(B&);
|
|
};
|
|
constexpr B::B(const B&) = default;
|
|
constexpr B::B(B&) = default; // expected-error {{not constexpr}}
|
|
|
|
struct C {
|
|
A a;
|
|
C() = default;
|
|
constexpr C(const C&);
|
|
constexpr C(C&);
|
|
};
|
|
constexpr C::C(const C&) = default;
|
|
constexpr C::C(C&) = default; // expected-error {{not constexpr}}
|
|
}
|
|
|
|
namespace PR14503 {
|
|
template<typename> struct V {
|
|
union {
|
|
int n;
|
|
struct {
|
|
int x,
|
|
y; // expected-note {{subobject declared here}}
|
|
};
|
|
};
|
|
constexpr V() : x(0) {}
|
|
};
|
|
|
|
// The constructor is still 'constexpr' here, but the result is not intended
|
|
// to be a constant expression. The standard is not clear on how this should
|
|
// work.
|
|
constexpr V<int> v; // expected-error {{constant expression}} expected-note {{subobject of type 'int' is not initialized}}
|
|
|
|
constexpr int k = V<int>().x; // FIXME: ok?
|
|
}
|