1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
|
// 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.
// This will no longer be the case once we support P2448R2
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 'y' is not initialized}}
constexpr int k = V<int>().x; // FIXME: ok?
}
|