499 lines · cpp
1// UNSUPPORTED: target={{.*}}-zos{{.*}}2// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=ref,ref20,all,all20 %s3// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=ref,ref23,all,all23 %s4// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter5// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected23,all,all23 %s -fexperimental-new-constant-interpreter6 7 8#define assert_active(F) if (!__builtin_is_within_lifetime(&F)) (1/0);9#define assert_inactive(F) if ( __builtin_is_within_lifetime(&F)) (1/0);10 11inline constexpr void* operator new(__SIZE_TYPE__, void* p) noexcept { return p; }12namespace std {13template<typename T, typename... Args>14constexpr T* construct_at(T* p, Args&&... args) { return ::new((void*)p) T(static_cast<Args&&>(args)...); }15}16 17constexpr int f(int n) { // all20-error {{constexpr function never produces a constant expression}}18 static const int m = n; // all-note {{control flows through the definition of a static variable}} \19 // all20-note {{control flows through the definition of a static variable}} \20 // all20-warning {{is a C++23 extension}}21 22 return m;23}24static_assert(f(0) == 0, ""); // all-error {{not an integral constant expression}} \25 // all-note {{in call to}}26 27constexpr int g(int n) { // all20-error {{constexpr function never produces a constant expression}}28 thread_local const int m = n; // all-note {{control flows through the definition of a thread_local variable}} \29 // all20-note {{control flows through the definition of a thread_local variable}} \30 // all20-warning {{is a C++23 extension}}31 return m;32}33static_assert(g(0) == 0, ""); // all-error {{not an integral constant expression}} \34 // all-note {{in call to}}35 36constexpr int c_thread_local(int n) { // all20-error {{constexpr function never produces a constant expression}}37 static _Thread_local int m = 0; // all20-note 2{{control flows through the definition of a thread_local variable}} \38 // all23-note {{control flows through the definition of a thread_local variable}} \39 // all20-warning {{is a C++23 extension}}40 return m;41}42static_assert(c_thread_local(0) == 0, ""); // all-error {{not an integral constant expression}} \43 // all-note {{in call to}}44 45 46constexpr int gnu_thread_local(int n) { // all20-error {{constexpr function never produces a constant expression}}47 static __thread int m = 0; // all20-note 2{{control flows through the definition of a thread_local variable}} \48 // all23-note {{control flows through the definition of a thread_local variable}} \49 // all20-warning {{is a C++23 extension}}50 return m;51}52static_assert(gnu_thread_local(0) == 0, ""); // all-error {{not an integral constant expression}} \53 // all-note {{in call to}}54 55constexpr int h(int n) { // all20-error {{constexpr function never produces a constant expression}}56 static const int m = n; // all20-note {{control flows through the definition of a static variable}} \57 // all20-warning {{is a C++23 extension}}58 return &m - &m;59}60 61constexpr int i(int n) { // all20-error {{constexpr function never produces a constant expression}}62 thread_local const int m = n; // all20-note {{control flows through the definition of a thread_local variable}} \63 // all20-warning {{is a C++23 extension}}64 return &m - &m;65}66 67constexpr int j(int n) {68 if (!n)69 return 0;70 static const int m = n; // ref20-warning {{is a C++23 extension}} \71 // expected20-warning {{is a C++23 extension}}72 return m;73}74constexpr int j0 = j(0);75 76constexpr int k(int n) {77 if (!n)78 return 0;79 thread_local const int m = n; // ref20-warning {{is a C++23 extension}} \80 // expected20-warning {{is a C++23 extension}}81 82 return m;83}84constexpr int k0 = k(0);85 86namespace ThreadLocalStore {87 thread_local int &&a = 0;88 void store() { a = 42; }89}90 91#if __cplusplus >= 202302L92constexpr int &b = b; // all-error {{must be initialized by a constant expression}} \93 // all-note {{initializer of 'b' is not a constant expression}} \94 // all-note {{declared here}}95#endif96 97namespace StaticLambdas {98 constexpr auto static_capture_constexpr() {99 char n = 'n';100 return [n] static { return n; }(); // expected23-error {{a static lambda cannot have any captures}} \101 // expected20-error {{a static lambda cannot have any captures}} \102 // expected20-warning {{are a C++23 extension}} \103 // expected20-warning {{is a C++23 extension}} \104 // ref23-error {{a static lambda cannot have any captures}} \105 // ref20-error {{a static lambda cannot have any captures}} \106 // ref20-warning {{are a C++23 extension}} \107 // ref20-warning {{is a C++23 extension}}108 }109 static_assert(static_capture_constexpr()); // expected23-error {{static assertion expression is not an integral constant expression}} \110 // expected20-error {{static assertion expression is not an integral constant expression}} \111 // ref23-error {{static assertion expression is not an integral constant expression}} \112 // ref20-error {{static assertion expression is not an integral constant expression}}113 114 constexpr auto capture_constexpr() {115 char n = 'n';116 return [n] { return n; }();117 }118 static_assert(capture_constexpr());119}120 121namespace StaticOperators {122 auto lstatic = []() static { return 3; }; // ref20-warning {{C++23 extension}} \123 // expected20-warning {{C++23 extension}}124 static_assert(lstatic() == 3, "");125 constexpr int (*f2)(void) = lstatic;126 static_assert(f2() == 3);127 128 struct S1 {129 constexpr S1() { // all20-error {{never produces a constant expression}}130 throw; // all-note {{not valid in a constant expression}} \131 // all20-note {{not valid in a constant expression}}132 }133 static constexpr int operator()() { return 3; } // ref20-warning {{C++23 extension}} \134 // expected20-warning {{C++23 extension}}135 };136 static_assert(S1{}() == 3, ""); // all-error {{not an integral constant expression}} \137 // all-note {{in call to}}138 139 140 141}142 143int test_in_lambdas() {144 auto c = [](int n) constexpr {145 if (n == 0)146 return 0;147 else148 goto test; // all-note {{subexpression not valid in a constant expression}} \149 // all20-warning {{use of this statement in a constexpr function is a C++23 extension}}150 test:151 return 1;152 };153 c(0);154 constexpr auto A = c(1); // all-error {{must be initialized by a constant expression}} \155 // all-note {{in call to}}156 return 0;157}158 159/// PackIndexExpr.160template <auto... p>161struct check_ice {162 enum e {163 x = p...[0] // all-warning {{is a C++2c extension}}164 };165};166static_assert(check_ice<42>::x == 42);167 168 169namespace VirtualBases {170 namespace One {171 struct U { int n; };172 struct V : U { int n; };173 struct A : virtual V { int n; };174 struct Aa { int n; };175 struct B : virtual A, Aa {};176 struct C : virtual A, Aa {};177 struct D : B, C {};178 179 /// Calls the constructor of D.180 D d;181 }182 183#if __cplusplus >= 202302L184 struct VBase {};185 struct HasVBase : virtual VBase {}; // all23-note 1{{virtual base class declared here}}186 struct Derived : HasVBase {187 constexpr Derived() {} // all23-error {{constexpr constructor not allowed in struct with virtual base class}}188 };189 template<typename T> struct DerivedFromVBase : T {190 constexpr DerivedFromVBase();191 };192 constexpr int f(DerivedFromVBase<HasVBase>) {}193 template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {}194 constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // all23-error {{constant expression}} \195 // all23-note {{cannot construct object of type 'DerivedFromVBase<VirtualBases::HasVBase>' with virtual base class in a constant expression}}196#endif197}198 199namespace LabelGoto {200 constexpr int foo() { // all20-error {{never produces a constant expression}}201 a: // all20-warning {{use of this statement in a constexpr function is a C++23 extension}}202 goto a; // all20-note 2{{subexpression not valid in a constant expression}} \203 // ref23-note {{subexpression not valid in a constant expression}} \204 // expected23-note {{subexpression not valid in a constant expression}}205 206 return 1;207 }208 static_assert(foo() == 1, ""); // all-error {{not an integral constant expression}} \209 // all-note {{in call to}}210}211 212namespace ExplicitLambdaThis {213 constexpr auto f = [x = 3]<typename Self>(this Self self) { // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}}214 return x;215 };216 static_assert(f());217}218 219namespace std {220 struct strong_ordering {221 int n;222 constexpr operator int() const { return n; }223 static const strong_ordering less, equal, greater;224 };225 constexpr strong_ordering strong_ordering::less = {-1};226 constexpr strong_ordering strong_ordering::equal = {0};227 constexpr strong_ordering strong_ordering::greater = {1};228}229 230namespace UndefinedThreeWay {231 struct A {232 friend constexpr std::strong_ordering operator<=>(const A&, const A&) = default; // all-note {{declared here}}233 };234 235 constexpr std::strong_ordering operator<=>(const A&, const A&) noexcept;236 constexpr std::strong_ordering (*test_a_threeway)(const A&, const A&) = &operator<=>;237 static_assert(!(*test_a_threeway)(A(), A())); // all-error {{static assertion expression is not an integral constant expression}} \238 // all-note {{undefined function 'operator<=>' cannot be used in a constant expression}}239}240 241/// FIXME: The new interpreter is missing the "initializer of q is not a constant expression" diagnostics.a242/// That's because the cast from void* to int* is considered fine, but diagnosed. So we don't consider243/// q to be uninitialized.244namespace VoidCast {245 constexpr void* p = nullptr;246 constexpr int* q = static_cast<int*>(p); // all-error {{must be initialized by a constant expression}} \247 // all-note {{cast from 'void *' is not allowed in a constant expression}} \248 // ref-note {{declared here}}249 static_assert(q == nullptr); // ref-error {{not an integral constant expression}} \250 // ref-note {{initializer of 'q' is not a constant expression}}251}252 253namespace ExplicitLambdaInstancePointer {254 struct C {255 constexpr C(auto) { }256 };257 void foo() {258 constexpr auto b = [](this C) { return 1; }; // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}}259 constexpr int (*fp)(C) = b;260 static_assert(fp(1) == 1, "");261 }262}263 264namespace TwosComplementShifts {265 using uint32 = __UINT32_TYPE__;266 using int32 = __INT32_TYPE__;267 static_assert(uint32(int32(0x1234) << 16) == 0x12340000);268 static_assert(uint32(int32(0x1234) << 19) == 0x91a00000);269 static_assert(uint32(int32(0x1234) << 20) == 0x23400000);270 static_assert(uint32(int32(0x1234) << 24) == 0x34000000);271 static_assert(uint32(int32(-1) << 31) == 0x80000000);272 273 static_assert(-2 >> 1 == -1);274 static_assert(-3 >> 1 == -2);275 static_assert(-7 >> 1 == -4);276}277 278namespace AnonUnionDtor {279 struct A {280 A ();281 ~A();282 };283 284 template <class T>285 struct opt286 {287 union {288 char c;289 T data;290 };291 292 constexpr opt() {}293 294 constexpr ~opt() {295 if (engaged)296 data.~T();297 }298 299 bool engaged = false;300 };301 302 consteval void foo() {303 opt<A> a;304 }305 306 void bar() { foo(); }307}308 309/// FIXME: The two interpreters disagree about there to diagnose the non-constexpr destructor call.310namespace NonLiteralDtorInParam {311 class NonLiteral { // all20-note {{is not an aggregate and has no constexpr constructors other than copy or move constructors}}312 public:313 NonLiteral() {}314 ~NonLiteral() {} // all23-note {{declared here}}315 };316 constexpr int F2(NonLiteral N) { // all20-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}} \317 // all23-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}}318 return 8;319 }320 321 322 void test() {323 NonLiteral L;324 constexpr auto D = F2(L); // all23-error {{must be initialized by a constant expression}}325 }326}327 328namespace ZeroSizedArray {329 struct S {330 constexpr ~S() {331 }332 };333 constexpr int foo() {334 S s[0];335 return 1;336 }337 static_assert(foo() == 1);338}339namespace VoidCast {340 constexpr int a = 12;341 constexpr const int *b = &a;342 constexpr int *f = (int*)(void*)b; // all-error {{must be initialized by a constant expression}} \343 // all-note {{cast from 'void *' is not allowed in a constant expression}}344}345 346#if __cplusplus >= 202302L347namespace NestedUnions {348 consteval bool test_nested() {349 union {350 union { int i; char c; } u;351 long l;352 };353 std::construct_at(&l);354 assert_active(l);355 assert_inactive(u);356 357 std::construct_at(&u);358 assert_active(u);359 assert_inactive(l);360 assert_active(u.i);361 assert_inactive(u.c);362 363 std::construct_at(&u.i);364 assert_active(u);365 assert_inactive(u.c);366 367 368 std::construct_at(&u.c);369 assert_active(u);370 assert_inactive(u.i);371 assert_active(u.c);372 assert_inactive(l);373 return true;374 }375 static_assert(test_nested());376}377 378namespace UnionMemberCallDiags {379 struct A { int n; };380 struct B { A a; };381 constexpr A a = (A() = B().a);382 383 union C {384 int n;385 A a;386 };387 388 constexpr bool g() {389 C c = {.n = 1};390 c.a.operator=(B{2}.a); // all-note {{member call on member 'a' of union with active member 'n' is not allowed in a constant expression}}391 return c.a.n == 2;392 }393 static_assert(g()); // all-error {{not an integral constant expression}} \394 // all-note {{in call to}}395}396#endif397 398namespace VolatileWrites {399 constexpr void test1() {// all20-error {{never produces a constant expression}}400 int k;401 volatile int &m = k;402 m = 10; // all20-note {{assignment to volatile-qualified type 'volatile int'}}403 }404 405 constexpr void test2() { // all20-error {{never produces a constant expression}}406 volatile int k = 12;407 408 k = 13; // all20-note {{assignment to volatile-qualified type 'volatile int'}}409 }410 411 constexpr void test3() { // all20-error {{never produces a constant expression}}412 volatile int k = 12; // all20-note {{volatile object declared here}}413 414 *((int *)&k) = 13; // all20-note {{assignment to volatile object 'k' is not allowed in a constant expression}}415 }416 417 constexpr void test4() { // all20-error {{never produces a constant expression}}418 int k = 12;419 420 *((volatile int *)&k) = 13; // all20-note {{assignment to volatile-qualified type 'volatile int' is not allowed in a constant expression}}421 }422 423#if __cplusplus >= 202302L424 struct S {425 volatile int k;426 };427 constexpr int test5() {428 S s;429 s.k = 12; // all-note {{assignment to volatile-qualified type 'volatile int' is not}}430 431 return 0;432 }433 static_assert(test5() == 0); // all-error{{not an integral constant expression}} \434 // all-note {{in call to}}435#endif436 437 constexpr bool test6(volatile int k) { // ref20-error {{never produces a constant expression}}438 k = 14; // ref20-note {{assignment to volatile-qualified type 'volatile int' is not}} \439 // all-note {{assignment to volatile-qualified type 'volatile int' is not}}440 return true;441 }442 static_assert(test6(5)); // all-error {{not an integral constant expression}} \443 // all-note {{in call to}}444 445 constexpr bool test7(volatile int k) { // all-note {{declared here}}446 *((int *)&k) = 13; // all-note {{assignment to volatile object 'k' is not allowed in a constant expression}}447 return true;448 }449 static_assert(test7(12)); // all-error {{not an integral constant expression}} \450 // all-note {{in call to}}451}452 453namespace AIEWithIndex0Narrows {454 template <class _Tp> struct greater {455 constexpr void operator()(_Tp, _Tp) {}456 };457 struct S {458 constexpr S() : i_() {}459 int i_;460 };461 462 constexpr void sort(S *__first) {463 for (int __start = 0; __start >= 0; --__start) {464 greater<S>{}(__first[0], __first[0]);465 }466 }467 constexpr bool test() {468 S *ia = new S[2];469 470 sort(ia + 1);471 delete[] ia;472 return true;473 }474 static_assert(test());475}476 477#if __cplusplus >= 202302L478namespace InactiveLocalsInConditionalOp {479 struct A { constexpr A(){}; ~A(); constexpr int get() { return 10; } }; // all-note 2{{declared here}}480 constexpr int get(bool b) {481 return b ? A().get() : 1; // all-note {{non-constexpr function '~A' cannot be used in a constant expression}}482 }483 static_assert(get(false) == 1, "");484 static_assert(get(true) == 10, ""); // all-error {{not an integral constant expression}} \485 // all-note {{in call to}}486 487 static_assert( (false ? A().get() : 1) == 1);488 static_assert( (true ? A().get() : 1) == 1); // all-error {{not an integral constant expression}} \489 // all-note {{non-constexpr function '~A' cannot be used in a constant expression}}490 491 constexpr bool test2(bool b) {492 unsigned long __ms = b ? (const unsigned long &)0 : __ms;493 return true;494 }495 static_assert(test2(true));496 497}498#endif499