constant-expression-cxx11.cpp revision 59efe266b804330f4c1f3a1b0ff783e67dd90378
1// RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 %s 2 3// This version of static_assert just requires a foldable value as the 4// expression, not an ICE. 5// FIXME: Once we implement the C++11 ICE rules, most uses of this here should 6// be converted to static_assert. 7#define static_assert_fold(expr, str) \ 8 static_assert(__builtin_constant_p(expr), "not an integral constant expression"); \ 9 static_assert(__builtin_constant_p(expr) ? expr : true, str) 10 11namespace StaticAssertFoldTest { 12 13int x; 14static_assert_fold(++x, "test"); // expected-error {{not an integral constant expression}} 15static_assert_fold(false, "test"); // expected-error {{test}} 16 17} 18 19// FIXME: support const T& parameters here. 20//template<typename T> constexpr T id(const T &t) { return t; } 21template<typename T> constexpr T id(T t) { return t; } 22// FIXME: support templates here. 23//template<typename T> constexpr T min(const T &a, const T &b) { 24// return a < b ? a : b; 25//} 26//template<typename T> constexpr T max(const T &a, const T &b) { 27// return a < b ? b : a; 28//} 29constexpr int min(const int &a, const int &b) { return a < b ? a : b; } 30constexpr int max(const int &a, const int &b) { return a < b ? b : a; } 31 32struct MemberZero { 33 constexpr int zero() { return 0; } 34}; 35 36namespace DerivedToVBaseCast { 37 38 struct U { int n; }; 39 struct V : U { int n; }; 40 struct A : virtual V { int n; }; 41 struct Aa { int n; }; 42 struct B : virtual A, Aa {}; 43 struct C : virtual A, Aa {}; 44 struct D : B, C {}; 45 46 D d; 47 constexpr B *p = &d; 48 constexpr C *q = &d; 49 static_assert_fold((void*)p != (void*)q, ""); 50 static_assert_fold((A*)p == (A*)q, ""); 51 static_assert_fold((Aa*)p != (Aa*)q, ""); 52 53 constexpr B &pp = d; 54 constexpr C &qq = d; 55 static_assert_fold((void*)&pp != (void*)&qq, ""); 56 static_assert_fold(&(A&)pp == &(A&)qq, ""); 57 static_assert_fold(&(Aa&)pp != &(Aa&)qq, ""); 58 59 constexpr V *v = p; 60 constexpr V *w = q; 61 constexpr V *x = (A*)p; 62 static_assert_fold(v == w, ""); 63 static_assert_fold(v == x, ""); 64 65 static_assert_fold((U*)&d == p, ""); 66 static_assert_fold((U*)&d == q, ""); 67 static_assert_fold((U*)&d == v, ""); 68 static_assert_fold((U*)&d == w, ""); 69 static_assert_fold((U*)&d == x, ""); 70 71 struct X {}; 72 struct Y1 : virtual X {}; 73 struct Y2 : X {}; 74 struct Z : Y1, Y2 {}; 75 Z z; 76 static_assert_fold((X*)(Y1*)&z != (X*)(Y2*)&z, ""); 77 78} 79 80namespace TemplateArgumentConversion { 81 template<int n> struct IntParam {}; 82 83 using IntParam0 = IntParam<0>; 84 // FIXME: This should be accepted once we do constexpr function invocation. 85 using IntParam0 = IntParam<id(0)>; // expected-error {{not an integral constant expression}} 86 using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}} expected-error {{not an integral constant expression}} 87} 88 89namespace CaseStatements { 90 void f(int n) { 91 switch (n) { 92 // FIXME: Produce the 'add ()' fixit for this. 93 case MemberZero().zero: // desired-error {{did you mean to call it with no arguments?}} expected-error {{not an integer constant expression}} 94 // FIXME: This should be accepted once we do constexpr function invocation. 95 case id(1): // expected-error {{not an integer constant expression}} 96 return; 97 } 98 } 99} 100 101extern int &Recurse1; 102int &Recurse2 = Recurse1, &Recurse1 = Recurse2; 103constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} 104 105namespace MemberEnum { 106 struct WithMemberEnum { 107 enum E { A = 42 }; 108 } wme; 109 110 static_assert_fold(wme.A == 42, ""); 111} 112 113namespace DefaultArguments { 114 115const int z = int(); 116constexpr int Sum(int a = 0, const int &b = 0, const int *c = &z, char d = 0) { 117 return a + b + *c + d; 118} 119const int four = 4; 120constexpr int eight = 8; 121constexpr const int twentyseven = 27; 122static_assert_fold(Sum() == 0, ""); 123static_assert_fold(Sum(1) == 1, ""); 124static_assert_fold(Sum(1, four) == 5, ""); 125static_assert_fold(Sum(1, eight, &twentyseven) == 36, ""); 126static_assert_fold(Sum(1, 2, &four, eight) == 15, ""); 127 128} 129 130namespace Ellipsis { 131 132// Note, values passed through an ellipsis can't actually be used. 133constexpr int F(int a, ...) { return a; } 134static_assert_fold(F(0) == 0, ""); 135static_assert_fold(F(1, 0) == 1, ""); 136static_assert_fold(F(2, "test") == 2, ""); 137static_assert_fold(F(3, &F) == 3, ""); 138int k = 0; 139static_assert_fold(F(4, k) == 3, ""); // expected-error {{constant expression}} 140 141} 142 143namespace Recursion { 144 constexpr int fib(int n) { return n > 1 ? fib(n-1) + fib(n-2) : n; } 145 static_assert_fold(fib(11) == 89, ""); 146 147 constexpr int gcd_inner(int a, int b) { 148 return b == 0 ? a : gcd_inner(b, a % b); 149 } 150 constexpr int gcd(int a, int b) { 151 return gcd_inner(max(a, b), min(a, b)); 152 } 153 154 static_assert_fold(gcd(1749237, 5628959) == 7, ""); 155} 156 157namespace FunctionCast { 158 // When folding, we allow functions to be cast to different types. Such 159 // cast functions cannot be called, even if they're constexpr. 160 constexpr int f() { return 1; } 161 typedef double (*DoubleFn)(); 162 typedef int (*IntFn)(); 163 int a[(int)DoubleFn(f)()]; // expected-error {{variable length array}} 164 int b[(int)IntFn(f)()]; // ok 165} 166 167namespace StaticMemberFunction { 168 struct S { 169 static constexpr int k = 42; 170 static constexpr int f(int n) { return n * k + 2; } 171 } s; 172 173 constexpr int n = s.f(19); 174 static_assert_fold(S::f(19) == 800, ""); 175 static_assert_fold(s.f(19) == 800, ""); 176 static_assert_fold(n == 800, ""); 177} 178 179namespace ParameterScopes { 180 181 const int k = 42; 182 constexpr const int &ObscureTheTruth(const int &a) { return a; } 183 constexpr const int &MaybeReturnJunk(bool b, const int a) { 184 return ObscureTheTruth(b ? a : k); 185 } 186 static_assert_fold(MaybeReturnJunk(false, 0) == 42, ""); // ok 187 constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} 188 189 constexpr const int MaybeReturnNonstaticRef(bool b, const int a) { 190 // If ObscureTheTruth returns a reference to 'a', the result is not a 191 // constant expression even though 'a' is still in scope. 192 return ObscureTheTruth(b ? a : k); 193 } 194 static_assert_fold(MaybeReturnNonstaticRef(false, 0) == 42, ""); // ok 195 constexpr int b = MaybeReturnNonstaticRef(true, 0); // expected-error {{constant expression}} 196 197 constexpr int InternalReturnJunk(int n) { 198 // FIXME: We should reject this: it never produces a constant expression. 199 return MaybeReturnJunk(true, n); 200 } 201 constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} 202 203 constexpr int LToR(int &n) { return n; } 204 constexpr int GrabCallersArgument(bool which, int a, int b) { 205 return LToR(which ? b : a); 206 } 207 static_assert_fold(GrabCallersArgument(false, 1, 2) == 1, ""); 208 static_assert_fold(GrabCallersArgument(true, 4, 8) == 8, ""); 209 210} 211 212namespace Pointers { 213 214 constexpr int f(int n, const int *a, const int *b, const int *c) { 215 return n == 0 ? 0 : *a + f(n-1, b, c, a); 216 } 217 218 const int x = 1, y = 10, z = 100; 219 static_assert_fold(f(23, &x, &y, &z) == 788, ""); 220 221 constexpr int g(int n, int a, int b, int c) { 222 return f(n, &a, &b, &c); 223 } 224 static_assert_fold(g(23, x, y, z) == 788, ""); 225 226} 227 228namespace FunctionPointers { 229 230 constexpr int Double(int n) { return 2 * n; } 231 constexpr int Triple(int n) { return 3 * n; } 232 constexpr int Twice(int (*F)(int), int n) { return F(F(n)); } 233 constexpr int Quadruple(int n) { return Twice(Double, n); } 234 constexpr auto Select(int n) -> int (*)(int) { 235 return n == 2 ? &Double : n == 3 ? &Triple : n == 4 ? &Quadruple : 0; 236 } 237 constexpr int Apply(int (*F)(int), int n) { return F(n); } 238 239 static_assert_fold(1 + Apply(Select(4), 5) + Apply(Select(3), 7) == 42, ""); 240 241 constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}} 242 243} 244 245namespace PointerComparison { 246 247int x, y; 248static_assert_fold(&x == &y, "false"); // expected-error {{false}} 249static_assert_fold(&x != &y, ""); 250constexpr bool g1 = &x == &y; 251constexpr bool g2 = &x != &y; 252constexpr bool g3 = &x <= &y; // expected-error {{must be initialized by a constant expression}} 253constexpr bool g4 = &x >= &y; // expected-error {{must be initialized by a constant expression}} 254constexpr bool g5 = &x < &y; // expected-error {{must be initialized by a constant expression}} 255constexpr bool g6 = &x > &y; // expected-error {{must be initialized by a constant expression}} 256 257struct S { int x, y; } s; 258static_assert_fold(&s.x == &s.y, "false"); // expected-error {{false}} 259static_assert_fold(&s.x != &s.y, ""); 260static_assert_fold(&s.x <= &s.y, ""); 261static_assert_fold(&s.x >= &s.y, "false"); // expected-error {{false}} 262static_assert_fold(&s.x < &s.y, ""); 263static_assert_fold(&s.x > &s.y, "false"); // expected-error {{false}} 264 265static_assert_fold(0 == &y, "false"); // expected-error {{false}} 266static_assert_fold(0 != &y, ""); 267constexpr bool n3 = 0 <= &y; // expected-error {{must be initialized by a constant expression}} 268constexpr bool n4 = 0 >= &y; // expected-error {{must be initialized by a constant expression}} 269constexpr bool n5 = 0 < &y; // expected-error {{must be initialized by a constant expression}} 270constexpr bool n6 = 0 > &y; // expected-error {{must be initialized by a constant expression}} 271 272static_assert_fold(&x == 0, "false"); // expected-error {{false}} 273static_assert_fold(&x != 0, ""); 274constexpr bool n9 = &x <= 0; // expected-error {{must be initialized by a constant expression}} 275constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a constant expression}} 276constexpr bool n11 = &x < 0; // expected-error {{must be initialized by a constant expression}} 277constexpr bool n12 = &x > 0; // expected-error {{must be initialized by a constant expression}} 278 279static_assert_fold(&x == &x, ""); 280static_assert_fold(&x != &x, "false"); // expected-error {{false}} 281static_assert_fold(&x <= &x, ""); 282static_assert_fold(&x >= &x, ""); 283static_assert_fold(&x < &x, "false"); // expected-error {{false}} 284static_assert_fold(&x > &x, "false"); // expected-error {{false}} 285 286constexpr S* sptr = &s; 287// FIXME: This is not a constant expression; check we reject this and move this 288// test elsewhere. 289constexpr bool dyncast = sptr == dynamic_cast<S*>(sptr); 290 291extern char externalvar[]; 292// FIXME: This is not a constant expression; check we reject this and move this 293// test elsewhere. 294constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} 295constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}} 296static_assert_fold(0 != "foo", ""); 297 298} 299 300namespace MaterializeTemporary { 301 302constexpr int f(const int &r) { return r; } 303constexpr int n = f(1); 304 305constexpr bool same(const int &a, const int &b) { return &a == &b; } 306constexpr bool sameTemporary(const int &n) { return same(n, n); } 307 308static_assert_fold(n, ""); 309static_assert_fold(!same(4, 4), ""); 310static_assert_fold(same(n, n), ""); 311static_assert_fold(sameTemporary(9), ""); 312 313} 314 315constexpr int strcmp_ce(const char *p, const char *q) { 316 return (!*p || *p != *q) ? *p - *q : strcmp_ce(p+1, q+1); 317} 318 319namespace StringLiteral { 320 321// FIXME: Refactor this once we support constexpr templates. 322constexpr int MangleChars(const char *p) { 323 return *p + 3 * (*p ? MangleChars(p+1) : 0); 324} 325constexpr int MangleChars(const char16_t *p) { 326 return *p + 3 * (*p ? MangleChars(p+1) : 0); 327} 328constexpr int MangleChars(const char32_t *p) { 329 return *p + 3 * (*p ? MangleChars(p+1) : 0); 330} 331 332static_assert_fold(MangleChars("constexpr!") == 1768383, ""); 333static_assert_fold(MangleChars(u"constexpr!") == 1768383, ""); 334static_assert_fold(MangleChars(U"constexpr!") == 1768383, ""); 335 336constexpr char c0 = "nought index"[0]; 337constexpr char c1 = "nice index"[10]; 338constexpr char c2 = "nasty index"[12]; // expected-error {{must be initialized by a constant expression}} expected-warning {{indexes past the end}} 339constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{indexes before the beginning}} 340constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}} 341 342constexpr const char *p = "test" + 2; 343static_assert_fold(*p == 's', ""); 344 345constexpr const char *max_iter(const char *a, const char *b) { 346 return *a < *b ? b : a; 347} 348constexpr const char *max_element(const char *a, const char *b) { 349 return (a+1 >= b) ? a : max_iter(a, max_element(a+1, b)); 350} 351 352constexpr const char *begin(const char (&arr)[45]) { return arr; } 353constexpr const char *end(const char (&arr)[45]) { return arr + 45; } 354 355constexpr char str[] = "the quick brown fox jumped over the lazy dog"; 356constexpr const char *max = max_element(begin(str), end(str)); 357static_assert_fold(*max == 'z', ""); 358static_assert_fold(max == str + 38, ""); 359 360static_assert_fold(strcmp_ce("hello world", "hello world") == 0, ""); 361static_assert_fold(strcmp_ce("hello world", "hello clang") > 0, ""); 362static_assert_fold(strcmp_ce("constexpr", "test") < 0, ""); 363static_assert_fold(strcmp_ce("", " ") < 0, ""); 364 365} 366 367namespace Array { 368 369// FIXME: Use templates for these once we support constexpr templates. 370constexpr int Sum(const int *begin, const int *end) { 371 return begin == end ? 0 : *begin + Sum(begin+1, end); 372} 373constexpr const int *begin(const int (&xs)[5]) { return xs; } 374constexpr const int *end(const int (&xs)[5]) { return xs + 5; } 375 376constexpr int xs[] = { 1, 2, 3, 4, 5 }; 377constexpr int ys[] = { 5, 4, 3, 2, 1 }; 378constexpr int sum_xs = Sum(begin(xs), end(xs)); 379static_assert_fold(sum_xs == 15, ""); 380 381constexpr int ZipFoldR(int (*F)(int x, int y, int c), int n, 382 const int *xs, const int *ys, int c) { 383 return n ? F(*xs, *ys, ZipFoldR(F, n-1, xs+1, ys+1, c)) : c; 384} 385constexpr int MulAdd(int x, int y, int c) { return x * y + c; } 386constexpr int InnerProduct = ZipFoldR(MulAdd, 5, xs, ys, 0); 387static_assert_fold(InnerProduct == 35, ""); 388 389constexpr int SubMul(int x, int y, int c) { return (x - y) * c; } 390constexpr int DiffProd = ZipFoldR(SubMul, 2, xs+3, ys+3, 1); 391static_assert_fold(DiffProd == 8, ""); 392static_assert_fold(ZipFoldR(SubMul, 3, xs+3, ys+3, 1), ""); // expected-error {{constant expression}} 393 394constexpr const int *p = xs + 3; 395constexpr int xs4 = p[1]; // ok 396constexpr int xs5 = p[2]; // expected-error {{constant expression}} 397constexpr int xs0 = p[-3]; // ok 398constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} 399 400constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 401static_assert_fold(zs[0][0][0][0] == 1, ""); 402static_assert_fold(zs[1][1][1][1] == 16, ""); 403static_assert_fold(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}} 404static_assert_fold((&zs[0][0][0][2])[-1] == 2, ""); 405static_assert_fold(**(**(zs + 1) + 1) == 11, ""); 406static_assert_fold(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, ""); 407 408constexpr int arr[40] = { 1, 2, 3, [8] = 4 }; 409constexpr int SumNonzero(const int *p) { 410 return *p + (*p ? SumNonzero(p+1) : 0); 411} 412constexpr int CountZero(const int *p, const int *q) { 413 return p == q ? 0 : (*p == 0) + CountZero(p+1, q); 414} 415static_assert_fold(SumNonzero(arr) == 6, ""); 416static_assert_fold(CountZero(arr, arr + 40) == 36, ""); 417 418} 419 420namespace DependentValues { 421 422struct I { int n; typedef I V[10]; }; 423I::V x, y; 424template<bool B> struct S { 425 int k; 426 void f() { 427 I::V &cells = B ? x : y; 428 I &i = cells[k]; 429 switch (i.n) {} 430 } 431}; 432 433} 434 435namespace Class { 436 437struct A { constexpr A(int a, int b) : k(a + b) {} int k; }; 438constexpr int fn(const A &a) { return a.k; } 439static_assert_fold(fn(A(4,5)) == 9, ""); 440 441struct B { int n; int m; } constexpr b = { 0, b.n }; // expected-warning {{uninitialized}} 442struct C { 443 constexpr C(C *this_) : m(42), n(this_->m) {} // ok 444 int m, n; 445}; 446struct D { 447 C c; 448 constexpr D() : c(&c) {} 449}; 450static_assert_fold(D().c.n == 42, ""); 451 452struct E { 453 constexpr E() : p(&p) {} 454 void *p; 455}; 456constexpr const E &e1 = E(); // expected-error {{constant expression}} 457// This is a constant expression if we elide the copy constructor call, and 458// is not a constant expression if we don't! But we do, so it is. 459// FIXME: The move constructor is not currently implicitly defined as constexpr. 460// We notice this when evaluating an expression which uses it, but not when 461// checking its initializer. 462constexpr E e2 = E(); // unexpected-error {{constant expression}} 463static_assert_fold(e2.p == &e2.p, ""); // unexpected-error {{constant expression}} 464// FIXME: We don't pass through the fact that 'this' is ::e3 when checking the 465// initializer of this declaration. 466constexpr E e3; // unexpected-error {{constant expression}} 467static_assert_fold(e3.p == &e3.p, ""); 468 469extern const class F f; 470struct F { 471 constexpr F() : p(&f.p) {} 472 const void *p; 473}; 474constexpr F f = F(); 475 476struct G { 477 struct T { 478 constexpr T(T *p) : u1(), u2(p) {} 479 union U1 { 480 constexpr U1() {} 481 int a, b = 42; 482 } u1; 483 union U2 { 484 constexpr U2(T *p) : c(p->u1.b) {} 485 int c, d; 486 } u2; 487 } t; 488 constexpr G() : t(&t) {} 489} constexpr g; 490 491static_assert_fold(g.t.u1.a == 42, ""); // expected-error {{constant expression}} 492static_assert_fold(g.t.u1.b == 42, ""); 493static_assert_fold(g.t.u2.c == 42, ""); 494static_assert_fold(g.t.u2.d == 42, ""); // expected-error {{constant expression}} 495 496struct S { 497 int a, b; 498 const S *p; 499 double d; 500 const char *q; 501 502 constexpr S(int n, const S *p) : a(5), b(n), p(p), d(n), q("hello") {} 503}; 504 505S global(43, &global); 506 507static_assert_fold(S(15, &global).b == 15, ""); 508 509constexpr bool CheckS(const S &s) { 510 return s.a == 5 && s.b == 27 && s.p == &global && s.d == 27. && s.q[3] == 'l'; 511} 512static_assert_fold(CheckS(S(27, &global)), ""); 513 514struct Arr { 515 char arr[3]; 516 constexpr Arr() : arr{'x', 'y', 'z'} {} 517}; 518constexpr int hash(Arr &&a) { 519 return a.arr[0] + a.arr[1] * 0x100 + a.arr[2] * 0x10000; 520} 521constexpr int k = hash(Arr()); 522static_assert_fold(k == 0x007a7978, ""); 523 524 525struct AggregateInit { 526 const char &c; 527 int n; 528 double d; 529 int arr[5]; 530 void *p; 531}; 532 533constexpr AggregateInit agg1 = { "hello"[0] }; 534 535static_assert_fold(strcmp_ce(&agg1.c, "hello") == 0, ""); 536static_assert_fold(agg1.n == 0, ""); 537static_assert_fold(agg1.d == 0.0, ""); 538static_assert_fold(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} 539static_assert_fold(agg1.arr[0] == 0, ""); 540static_assert_fold(agg1.arr[4] == 0, ""); 541static_assert_fold(agg1.arr[5] == 0, ""); // expected-error {{constant expression}} 542static_assert_fold(agg1.p == nullptr, ""); 543 544namespace SimpleDerivedClass { 545 546struct B { 547 constexpr B(int n) : a(n) {} 548 int a; 549}; 550struct D : B { 551 constexpr D(int n) : B(n) {} 552}; 553constexpr D d(3); 554static_assert_fold(d.a == 3, ""); 555 556} 557 558struct Base { 559 constexpr Base(int a = 42, const char *b = "test") : a(a), b(b) {} 560 int a; 561 const char *b; 562}; 563struct Base2 { 564 constexpr Base2(const int &r) : r(r) {} 565 int q = 123; 566 // FIXME: When we track the global for which we are computing the initializer, 567 // use a reference here. 568 //const int &r; 569 int r; 570}; 571struct Derived : Base, Base2 { 572 constexpr Derived() : Base(76), Base2(a) {} 573 int c = r + b[1]; 574}; 575 576constexpr bool operator==(const Base &a, const Base &b) { 577 return a.a == b.a && strcmp_ce(a.b, b.b) == 0; 578} 579 580constexpr Base base; 581constexpr Base base2(76); 582constexpr Derived derived; 583static_assert_fold(derived.a == 76, ""); 584static_assert_fold(derived.b[2] == 's', ""); 585static_assert_fold(derived.c == 76 + 'e', ""); 586static_assert_fold(derived.q == 123, ""); 587static_assert_fold(derived.r == 76, ""); 588static_assert_fold(&derived.r == &derived.a, ""); // expected-error {{}} 589 590static_assert_fold(!(derived == base), ""); 591static_assert_fold(derived == base2, ""); 592 593} 594 595namespace Union { 596 597union U { 598 int a; 599 int b; 600}; 601 602constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } }; 603static_assert_fold(u[0].a == 0, ""); 604static_assert_fold(u[0].b, ""); // expected-error {{constant expression}} 605static_assert_fold(u[1].b == 1, ""); 606static_assert_fold((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}} 607static_assert_fold(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} 608static_assert_fold((&(u[1]) + 1 + 1)->b == 3, ""); 609 610} 611 612namespace Complex { 613 614class complex { 615 int re, im; 616public: 617 constexpr complex(int re = 0, int im = 0) : re(re), im(im) {} 618 constexpr complex(const complex &o) : re(o.re), im(o.im) {} 619 constexpr complex operator-() const { return complex(-re, -im); } 620 friend constexpr complex operator+(const complex &l, const complex &r) { 621 return complex(l.re + r.re, l.im + r.im); 622 } 623 friend constexpr complex operator-(const complex &l, const complex &r) { 624 return l + -r; 625 } 626 friend constexpr complex operator*(const complex &l, const complex &r) { 627 return complex(l.re * r.re - l.im * r.im, l.re * r.im + l.im * r.re); 628 } 629 friend constexpr bool operator==(const complex &l, const complex &r) { 630 return l.re == r.re && l.im == r.im; 631 } 632 constexpr bool operator!=(const complex &r) const { 633 return re != r.re || im != r.im; 634 } 635 constexpr int real() const { return re; } 636 constexpr int imag() const { return im; } 637}; 638 639constexpr complex i = complex(0, 1); 640constexpr complex k = (3 + 4*i) * (6 - 4*i); 641static_assert_fold(complex(1,0).real() == 1, ""); 642static_assert_fold(complex(1,0).imag() == 0, ""); 643static_assert_fold(((complex)1).imag() == 0, ""); 644static_assert_fold(k.real() == 34, ""); 645static_assert_fold(k.imag() == 12, ""); 646static_assert_fold(k - 34 == 12*i, ""); 647static_assert_fold((complex)1 == complex(1), ""); 648static_assert_fold((complex)1 != complex(0, 1), ""); 649static_assert_fold(complex(1) == complex(1), ""); 650static_assert_fold(complex(1) != complex(0, 1), ""); 651constexpr complex makeComplex(int re, int im) { return complex(re, im); } 652static_assert_fold(makeComplex(1,0) == complex(1), ""); 653static_assert_fold(makeComplex(1,0) != complex(0, 1), ""); 654 655class complex_wrap : public complex { 656public: 657 constexpr complex_wrap(int re, int im = 0) : complex(re, im) {} 658 constexpr complex_wrap(const complex_wrap &o) : complex(o) {} 659}; 660 661static_assert_fold((complex_wrap)1 == complex(1), ""); 662static_assert_fold((complex)1 != complex_wrap(0, 1), ""); 663static_assert_fold(complex(1) == complex_wrap(1), ""); 664static_assert_fold(complex_wrap(1) != complex(0, 1), ""); 665constexpr complex_wrap makeComplexWrap(int re, int im) { 666 return complex_wrap(re, im); 667} 668static_assert_fold(makeComplexWrap(1,0) == complex(1), ""); 669static_assert_fold(makeComplexWrap(1,0) != complex(0, 1), ""); 670 671} 672