// UNSUPPORTED: target={{.*}}-zos{{.*}} // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref,ref20,all,all20 %s // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=ref,ref23,all,all23 %s // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=expected23,all,all23 %s -fexperimental-new-constant-interpreter #define assert_active(F) if (!__builtin_is_within_lifetime(&F)) (1/0); #define assert_inactive(F) if ( __builtin_is_within_lifetime(&F)) (1/0); inline constexpr void* operator new(__SIZE_TYPE__, void* p) noexcept { return p; } namespace std { template constexpr T* construct_at(T* p, Args&&... args) { return ::new((void*)p) T(static_cast(args)...); } } constexpr int f(int n) { // all20-error {{constexpr function never produces a constant expression}} static const int m = n; // all-note {{control flows through the definition of a static variable}} \ // all20-note {{control flows through the definition of a static variable}} \ // all20-warning {{is a C++23 extension}} return m; } static_assert(f(0) == 0, ""); // all-error {{not an integral constant expression}} \ // all-note {{in call to}} constexpr int g(int n) { // all20-error {{constexpr function never produces a constant expression}} thread_local const int m = n; // all-note {{control flows through the definition of a thread_local variable}} \ // all20-note {{control flows through the definition of a thread_local variable}} \ // all20-warning {{is a C++23 extension}} return m; } static_assert(g(0) == 0, ""); // all-error {{not an integral constant expression}} \ // all-note {{in call to}} constexpr int c_thread_local(int n) { // all20-error {{constexpr function never produces a constant expression}} static _Thread_local int m = 0; // all20-note 2{{control flows through the definition of a thread_local variable}} \ // all23-note {{control flows through the definition of a thread_local variable}} \ // all20-warning {{is a C++23 extension}} return m; } static_assert(c_thread_local(0) == 0, ""); // all-error {{not an integral constant expression}} \ // all-note {{in call to}} constexpr int gnu_thread_local(int n) { // all20-error {{constexpr function never produces a constant expression}} static __thread int m = 0; // all20-note 2{{control flows through the definition of a thread_local variable}} \ // all23-note {{control flows through the definition of a thread_local variable}} \ // all20-warning {{is a C++23 extension}} return m; } static_assert(gnu_thread_local(0) == 0, ""); // all-error {{not an integral constant expression}} \ // all-note {{in call to}} constexpr int h(int n) { // all20-error {{constexpr function never produces a constant expression}} static const int m = n; // all20-note {{control flows through the definition of a static variable}} \ // all20-warning {{is a C++23 extension}} return &m - &m; } constexpr int i(int n) { // all20-error {{constexpr function never produces a constant expression}} thread_local const int m = n; // all20-note {{control flows through the definition of a thread_local variable}} \ // all20-warning {{is a C++23 extension}} return &m - &m; } constexpr int j(int n) { if (!n) return 0; static const int m = n; // ref20-warning {{is a C++23 extension}} \ // expected20-warning {{is a C++23 extension}} return m; } constexpr int j0 = j(0); constexpr int k(int n) { if (!n) return 0; thread_local const int m = n; // ref20-warning {{is a C++23 extension}} \ // expected20-warning {{is a C++23 extension}} return m; } constexpr int k0 = k(0); #if __cplusplus >= 202302L constexpr int &b = b; // all-error {{must be initialized by a constant expression}} \ // all-note {{initializer of 'b' is not a constant expression}} \ // all-note {{declared here}} #endif namespace StaticLambdas { constexpr auto static_capture_constexpr() { char n = 'n'; return [n] static { return n; }(); // expected23-error {{a static lambda cannot have any captures}} \ // expected20-error {{a static lambda cannot have any captures}} \ // expected20-warning {{are a C++23 extension}} \ // expected20-warning {{is a C++23 extension}} \ // ref23-error {{a static lambda cannot have any captures}} \ // ref20-error {{a static lambda cannot have any captures}} \ // ref20-warning {{are a C++23 extension}} \ // ref20-warning {{is a C++23 extension}} } static_assert(static_capture_constexpr()); // expected23-error {{static assertion expression is not an integral constant expression}} \ // expected20-error {{static assertion expression is not an integral constant expression}} \ // ref23-error {{static assertion expression is not an integral constant expression}} \ // ref20-error {{static assertion expression is not an integral constant expression}} constexpr auto capture_constexpr() { char n = 'n'; return [n] { return n; }(); } static_assert(capture_constexpr()); } namespace StaticOperators { auto lstatic = []() static { return 3; }; // ref20-warning {{C++23 extension}} \ // expected20-warning {{C++23 extension}} static_assert(lstatic() == 3, ""); constexpr int (*f2)(void) = lstatic; static_assert(f2() == 3); struct S1 { constexpr S1() { // all20-error {{never produces a constant expression}} throw; // all-note {{not valid in a constant expression}} \ // all20-note {{not valid in a constant expression}} } static constexpr int operator()() { return 3; } // ref20-warning {{C++23 extension}} \ // expected20-warning {{C++23 extension}} }; static_assert(S1{}() == 3, ""); // all-error {{not an integral constant expression}} \ // all-note {{in call to}} } int test_in_lambdas() { auto c = [](int n) constexpr { if (n == 0) return 0; else goto test; // all-note {{subexpression not valid in a constant expression}} \ // all20-warning {{use of this statement in a constexpr function is a C++23 extension}} test: return 1; }; c(0); constexpr auto A = c(1); // all-error {{must be initialized by a constant expression}} \ // all-note {{in call to}} return 0; } /// PackIndexExpr. template struct check_ice { enum e { x = p...[0] // all-warning {{is a C++2c extension}} }; }; static_assert(check_ice<42>::x == 42); namespace VirtualBases { namespace One { struct U { int n; }; struct V : U { int n; }; struct A : virtual V { int n; }; struct Aa { int n; }; struct B : virtual A, Aa {}; struct C : virtual A, Aa {}; struct D : B, C {}; /// Calls the constructor of D. D d; } #if __cplusplus >= 202302L struct VBase {}; struct HasVBase : virtual VBase {}; // all23-note 1{{virtual base class declared here}} struct Derived : HasVBase { constexpr Derived() {} // all23-error {{constexpr constructor not allowed in struct with virtual base class}} }; template struct DerivedFromVBase : T { constexpr DerivedFromVBase(); }; constexpr int f(DerivedFromVBase) {} template constexpr DerivedFromVBase::DerivedFromVBase() : T() {} constexpr int nVBase = (DerivedFromVBase(), 0); // all23-error {{constant expression}} \ // all23-note {{cannot construct object of type 'DerivedFromVBase' with virtual base class in a constant expression}} #endif } namespace LabelGoto { constexpr int foo() { // all20-error {{never produces a constant expression}} a: // all20-warning {{use of this statement in a constexpr function is a C++23 extension}} goto a; // all20-note 2{{subexpression not valid in a constant expression}} \ // ref23-note {{subexpression not valid in a constant expression}} \ // expected23-note {{subexpression not valid in a constant expression}} return 1; } static_assert(foo() == 1, ""); // all-error {{not an integral constant expression}} \ // all-note {{in call to}} } namespace ExplicitLambdaThis { constexpr auto f = [x = 3](this Self self) { // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}} return x; }; static_assert(f()); } namespace std { struct strong_ordering { int n; constexpr operator int() const { return n; } static const strong_ordering less, equal, greater; }; constexpr strong_ordering strong_ordering::less = {-1}; constexpr strong_ordering strong_ordering::equal = {0}; constexpr strong_ordering strong_ordering::greater = {1}; } namespace UndefinedThreeWay { struct A { friend constexpr std::strong_ordering operator<=>(const A&, const A&) = default; // all-note {{declared here}} }; constexpr std::strong_ordering operator<=>(const A&, const A&) noexcept; constexpr std::strong_ordering (*test_a_threeway)(const A&, const A&) = &operator<=>; static_assert(!(*test_a_threeway)(A(), A())); // all-error {{static assertion expression is not an integral constant expression}} \ // all-note {{undefined function 'operator<=>' cannot be used in a constant expression}} } /// FIXME: The new interpreter is missing the "initializer of q is not a constant expression" diagnostics.a /// That's because the cast from void* to int* is considered fine, but diagnosed. So we don't consider /// q to be uninitialized. namespace VoidCast { constexpr void* p = nullptr; constexpr int* q = static_cast(p); // all-error {{must be initialized by a constant expression}} \ // all-note {{cast from 'void *' is not allowed in a constant expression}} \ // ref-note {{declared here}} static_assert(q == nullptr); // ref-error {{not an integral constant expression}} \ // ref-note {{initializer of 'q' is not a constant expression}} } namespace ExplicitLambdaInstancePointer { struct C { constexpr C(auto) { } }; void foo() { constexpr auto b = [](this C) { return 1; }; // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}} constexpr int (*fp)(C) = b; static_assert(fp(1) == 1, ""); } } namespace TwosComplementShifts { using uint32 = __UINT32_TYPE__; using int32 = __INT32_TYPE__; static_assert(uint32(int32(0x1234) << 16) == 0x12340000); static_assert(uint32(int32(0x1234) << 19) == 0x91a00000); static_assert(uint32(int32(0x1234) << 20) == 0x23400000); static_assert(uint32(int32(0x1234) << 24) == 0x34000000); static_assert(uint32(int32(-1) << 31) == 0x80000000); static_assert(-2 >> 1 == -1); static_assert(-3 >> 1 == -2); static_assert(-7 >> 1 == -4); } namespace AnonUnionDtor { struct A { A (); ~A(); }; template struct opt { union { char c; T data; }; constexpr opt() {} constexpr ~opt() { if (engaged) data.~T(); } bool engaged = false; }; consteval void foo() { opt a; } void bar() { foo(); } } /// FIXME: The two interpreters disagree about there to diagnose the non-constexpr destructor call. namespace NonLiteralDtorInParam { class NonLiteral { // all20-note {{is not an aggregate and has no constexpr constructors other than copy or move constructors}} public: NonLiteral() {} ~NonLiteral() {} // all23-note {{declared here}} }; constexpr int F2(NonLiteral N) { // all20-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}} \ // ref23-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}} return 8; } void test() { NonLiteral L; constexpr auto D = F2(L); // all23-error {{must be initialized by a constant expression}} \ // expected23-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}} } } namespace ZeroSizedArray { struct S { constexpr ~S() { } }; constexpr int foo() { S s[0]; return 1; } static_assert(foo() == 1); } namespace VoidCast { constexpr int a = 12; constexpr const int *b = &a; constexpr int *f = (int*)(void*)b; // all-error {{must be initialized by a constant expression}} \ // all-note {{cast from 'void *' is not allowed in a constant expression}} } #if __cplusplus >= 202302L namespace NestedUnions { consteval bool test_nested() { union { union { int i; char c; } u; long l; }; std::construct_at(&l); assert_active(l); assert_inactive(u); std::construct_at(&u); assert_active(u); assert_inactive(l); assert_active(u.i); assert_inactive(u.c); std::construct_at(&u.i); assert_active(u); assert_inactive(u.c); std::construct_at(&u.c); assert_active(u); assert_inactive(u.i); assert_active(u.c); assert_inactive(l); return true; } static_assert(test_nested()); } namespace UnionMemberCallDiags { struct A { int n; }; struct B { A a; }; constexpr A a = (A() = B().a); union C { int n; A a; }; constexpr bool g() { C c = {.n = 1}; 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}} return c.a.n == 2; } static_assert(g()); // all-error {{not an integral constant expression}} \ // all-note {{in call to}} } #endif