// UNSUPPORTED:  target={{.*}}-zos{{.*}}
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=ref,ref20,all,all20 %s
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=ref,ref23,all,all23 %s
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected,expected20,all,all20 %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected,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<typename T, typename... Args>
constexpr T* construct_at(T* p, Args&&... args) { return ::new((void*)p) T(static_cast<Args&&>(args)...); }
template<typename T>
constexpr void destroy_at(T *p) { p->~T(); } // #destroy
}

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);

namespace ThreadLocalStore {
  thread_local int &&a = 0;
  void store() { a = 42; }
}

#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 <auto... p>
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<typename T> struct DerivedFromVBase : T {
    constexpr DerivedFromVBase();
  };
  constexpr int f(DerivedFromVBase<HasVBase>) {}
  template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {}
  constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // all23-error {{constant expression}} \
                                                            // all23-note {{cannot construct object of type 'DerivedFromVBase<VirtualBases::HasVBase>' 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]<typename Self>(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<int*>(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, "");
  }

  /// Failure case. The instance pointer is of type int.
  struct S2 {
      constexpr K(auto) { } // all-error {{a type specifier is required for all declarations}}
  };
  constexpr auto b = [](this K) { return 1; }; // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}} \
                                               // all-error {{unknown type name 'K'}}
  constexpr int (*fp)(K) = b; // all-error {{unknown type name 'K'}} \
                              // expected-error {{must be initialized by a constant expression}} \
                              // expected-note {{declared here}}
  static_assert(fp(1) == 1, ""); // expected-error {{not an integral constant expression}} \
                                 // expected-note {{initializer of 'fp' is not a constant expression}}
}

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 <class T>
  struct opt
  {
    union {
      char c;
      T data;
    };

    constexpr opt() {}

    constexpr ~opt()  {
     if (engaged)
       data.~T();
   }

    bool engaged = false;
  };

  consteval void foo() {
    opt<A> a;
  }

  void bar() { foo(); }
}

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}} \
                                   // all23-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}}
  }
}

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

namespace Volatile {
  constexpr void test1() {// all20-error {{never produces a constant expression}}
    int k;
    volatile int &m = k;
    m = 10; // all20-note {{assignment to volatile-qualified type 'volatile int'}}
  }

  constexpr void test2() { // all20-error {{never produces a constant expression}}
    volatile int k = 12;

    k = 13; // all20-note {{assignment to volatile-qualified type 'volatile int'}}
  }

  constexpr void test3() { // all20-error {{never produces a constant expression}}
    volatile int k = 12; // all20-note {{volatile object declared here}}

    *((int *)&k) = 13; // all20-note {{assignment to volatile object 'k' is not allowed in a constant expression}}
  }

  constexpr void test4() { // all20-error {{never produces a constant expression}}
    int k = 12;

    *((volatile int *)&k) = 13; // all20-note {{assignment to volatile-qualified type 'volatile int' is not allowed in a constant expression}}
  }

#if __cplusplus >= 202302L
  struct S {
    volatile int k;
  };
  constexpr int test5() {
    S s;
    s.k = 12; // all-note {{assignment to volatile-qualified type 'volatile int' is not}}

    return 0;
  }
  static_assert(test5() == 0); // all-error{{not an integral constant expression}} \
                               // all-note {{in call to}}
#endif

  constexpr bool test6(volatile int k) { // ref20-error {{never produces a constant expression}}
    k = 14; // ref20-note {{assignment to volatile-qualified type 'volatile int' is not}} \
            // all-note {{assignment to volatile-qualified type 'volatile int' is not}}
    return true;
  }
  static_assert(test6(5)); // all-error {{not an integral constant expression}} \
                           // all-note {{in call to}}

  constexpr bool test7(volatile int k) { // all-note {{declared here}}
    *((int *)&k) = 13; // all-note {{assignment to volatile object 'k' is not allowed in a constant expression}}
    return true;
  }
  static_assert(test7(12)); // all-error {{not an integral constant expression}} \
                            // all-note {{in call to}}

  constexpr int test8(bool b) {
    if (!b)
      return -1;
    struct C {
      int a;
    };
    volatile C c{12}; // all-note {{volatile object declared here}}
    return ((C&)(c)).a; // all-note {{read of volatile object}}
  }
  static_assert(test8(true) == 0); // all-error {{not an integral constant expression}} \
                                   // all-note {{in call to}}

  struct C {
    int n;
    constexpr C() : n(1) { n = 2; int b= n;}
  };
  constexpr int f(bool get) {
    if (get)
      return -1;
    volatile C c;
    return 2;
  }
  static_assert(f(false) == 2, "");
}

namespace AIEWithIndex0Narrows {
  template <class _Tp> struct greater {
    constexpr void operator()(_Tp, _Tp) {}
  };
  struct S {
    constexpr S() : i_() {}
    int i_;
  };

  constexpr void sort(S *__first) {
    for (int __start = 0; __start >= 0; --__start) {
      greater<S>{}(__first[0], __first[0]);
    }
  }
  constexpr bool test() {
    S *ia = new S[2];

    sort(ia + 1);
    delete[] ia;
    return true;
  }
  static_assert(test());
}

#if __cplusplus >= 202302L
namespace InactiveLocalsInConditionalOp {
  struct A { constexpr A(){}; ~A(); constexpr int get() { return 10; } }; // all-note 2{{declared here}}
  constexpr int get(bool b) {
    return b ? A().get() : 1; // all-note {{non-constexpr function '~A' cannot be used in a constant expression}}
  }
  static_assert(get(false) == 1, "");
  static_assert(get(true) == 10, ""); // all-error {{not an integral constant expression}} \
                                      // all-note {{in call to}}

  static_assert( (false ? A().get() : 1) == 1);
  static_assert( (true ? A().get() : 1) == 1); // all-error {{not an integral constant expression}} \
                                               // all-note {{non-constexpr function '~A' cannot be used in a constant expression}}

  constexpr bool test2(bool b) {
    unsigned long __ms = b ? (const unsigned long &)0 : __ms;
    return true;
  }
  static_assert(test2(true));

}

namespace PrimitiveArrayLifetimes {
  consteval int test1() {
    int a[3];
    assert_active(a[0]);
    assert_active(a[1]);
    assert_active(a[2]);
    std::destroy_at(&a[0]);
    assert_inactive(a[0]);

    std::construct_at(&a[0]);
    assert_active(a[0]);
    return a[0];
  }
  static_assert(test1() == 0);

  consteval int test2() {
    int a[3] = {1,2,3};
    assert_active(a[0]);
    assert_active(a[1]);
    assert_active(a[2]);
    std::destroy_at(&a[0]);
    assert_inactive(a[0]);

    std::construct_at(&a[0]);
    assert_active(a[0]);
    return a[0];
  }
  static_assert(test2() == 0);
}

#endif

namespace UnknownParams {
  class X {
  public:
    constexpr operator bool(){ return true; }
  };
  int foo(X x) {
    static_assert(x);
    return 1;
  }

  int foo2(X &x) { // all20-note {{declared here}}
    static_assert(x); // all20-error {{not an integral constant expression}} \
                      // all20-note {{function parameter 'x' with unknown value cannot be used in a constant expression}}
    return 1;
  }
}

namespace NonCompoundStmtBody {
  /// The body of the constructor is NOT a CompoundStmt.
  struct S {
    constexpr S() try { x = 20; } catch(...) {}

    int x = 0;
  };

  constexpr bool testS() {
    S s;
    return s.x == 20;
  }
  static_assert(testS());
}

namespace LValueConstant {
  struct D {
    unsigned y;
  };

  extern D d;
  consteval D& c() { return d; }
  long long f() { return c().y; }
}

#if __cplusplus >= 202302L
namespace PointerIntInc {
  constexpr const char *foo(const char *p, bool b) {
    auto q = reinterpret_cast<__UINTPTR_TYPE__>(p);
    if (b)
      q++;
    else
      q--;
    return p;
  }
  constexpr char p = 10;
  auto bar = foo(&p, true);
  auto bar2 = foo(&p, false);
}
#endif

namespace VariadicOperator {
  struct S {
    constexpr int operator()(this S, ...) { return 42; } // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}}
  };
  constexpr S s;
  static_assert(s() == 42);
}

namespace DynamicCast {

  struct A {virtual ~A();};
  struct B : A {};
  void f(A& a) { // all20-note 2{{declared here}}
    constexpr B* b = dynamic_cast<B*>(&a); // all-error {{must be initialized by a constant expression}} \
                                           // all23-note {{dynamic_cast applied to object 'a' whose dynamic type is not constant}} \
                                           // all20-note {{function parameter 'a' with unknown value cannot be used in a constant expression}}
    constexpr void* b2 = dynamic_cast<void*>(&a); // all-error {{must be initialized by a constant expression}} \
                                                  // all23-note {{dynamic_cast applied to object 'a' whose dynamic type is not constant}} \
                                                  // all20-note {{function parameter 'a' with unknown value cannot be used in a constant expression}}
  }

  struct S {};
  constexpr S s;
  constexpr int foo = (dynamic_cast<const S &>(s), 0);
}

#if __cplusplus >= 202302L
namespace BrokenShuffleVector {
  typedef float __m128 __attribute__((__vector_size__(16)));

  static inline constexpr __m128 _mm_cvtps_pd(__m128 z) {
    __builtin_convertvector(__builtin_shufflevector(z, z), __m128); // all-error {{first two arguments to '__builtin_shufflevector' must have the same type}} \
                                                                    // all-warning {{expression result unused}}
  }

  constexpr __m128 kf1{1.0f, 2.0f, 3.0f, 4.0f};
  constexpr __m128 v_mm_cvtps_pd = _mm_cvtps_pd(kf1); // all-error {{must be initialized by a constant expression}}
}

namespace BrokenExplicitInstanceParam {
  auto b = [](this C) { return 1; }; // all-error {{unknown type name 'C'}}
  static_assert( (&decltype(b)::operator())(1) == 1); // expected-error {{not an integral constant expression}}
}

#endif
