llvm/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp

// RUN: %clang_cc1 -fsyntax-only -verify=expected -std=c++23 %s

// This test covers modifications made by P2448R2.

// Check that there is no error when a constexpr function that never produces a
// constant expression, but still an error if such function is called from
// constexpr context.
constexpr int F(int N) {
  double D = 2.0 / 0.0; // expected-note {{division by zero}}
  return 1;
}

constexpr int F0(int N) {
  if (N == 0)
    double d2 = 2.0 / 0.0; // expected-note {{division by zero}}
  return 1;
}

template <typename T>
constexpr int FT(T N) {
  double D = 2.0 / 0.0; // expected-note {{division by zero}}
  return 1;
}

class NonLiteral { // expected-note {{'NonLiteral' is not literal because it is not an aggregate and has no constexpr constructors}}
public:
  NonLiteral() {}
  ~NonLiteral() {} // expected-note {{declared here}}
};

constexpr NonLiteral F1() {
  return NonLiteral{};
}

constexpr int F2(NonLiteral N) { // expected-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}}
  return 8;
}

class Derived : public NonLiteral {
  constexpr ~Derived() {};
};

class Derived1 : public NonLiteral {
  constexpr Derived1() : NonLiteral () {}
};


struct X {
  X(); // expected-note 2{{declared here}}
  X(const X&);
  X(X&&);
  X& operator=(X&);
  X& operator=(X&& other);
  bool operator==(X const&) const;
};

template <typename T>
struct Wrapper {
  constexpr Wrapper() = default;
  constexpr Wrapper(Wrapper const&) = default;
  constexpr Wrapper(T const& t) : t(t) { }
  constexpr Wrapper(Wrapper &&) = default;
  constexpr X get() const { return t; }
  constexpr bool operator==(Wrapper const&) const = default;
  private:
  T t;
};

struct WrapperNonT {
  constexpr WrapperNonT() = default;
  constexpr WrapperNonT(WrapperNonT const&) = default;
  constexpr WrapperNonT(X const& t) : t(t) { }
  constexpr WrapperNonT(WrapperNonT &&) = default;
  constexpr WrapperNonT& operator=(WrapperNonT &) = default;
  constexpr WrapperNonT& operator=(WrapperNonT&& other) = default;
  constexpr X get() const { return t; }
  constexpr bool operator==(WrapperNonT const&) const = default;
  private:
  X t;
};

struct NonDefaultMembers {
  constexpr NonDefaultMembers() {}; // expected-note 2{{non-constexpr constructor 'X' cannot be used in a constant expression}}
  constexpr NonDefaultMembers(NonDefaultMembers const&) {};
  constexpr NonDefaultMembers(NonDefaultMembers &&) {};
  constexpr NonDefaultMembers& operator=(NonDefaultMembers &other) {this->t = other.t; return *this;}
  constexpr NonDefaultMembers& operator=(NonDefaultMembers&& other) {this->t = other.t; return *this;}
  constexpr bool operator==(NonDefaultMembers const& other) const {return this->t == other.t;}
  X t;
};

int Glob = 0;
class C1 {
public:
  constexpr C1() : D(Glob) {};
private:
  int D;
};

void test() {

  constexpr int A = F(3); // expected-error {{constexpr variable 'A' must be initialized by a constant expression}}
                          // expected-note@-1 {{in call}}
  F(3);
  constexpr int B = F0(0); // expected-error {{constexpr variable 'B' must be initialized by a constant expression}}
                           // expected-note@-1 {{in call}}
  F0(0);
  constexpr auto C = F1(); // expected-error {{constexpr variable cannot have non-literal type 'const NonLiteral'}}
  F1();
  NonLiteral L;
  constexpr auto D = F2(L); // expected-error {{constexpr variable 'D' must be initialized by a constant expression}}

  constexpr auto E = FT(1); // expected-error {{constexpr variable 'E' must be initialized by a constant expression}}
                            // expected-note@-1 {{in call}}
  F2(L);

  Wrapper<X> x;
  WrapperNonT x1;
  NonDefaultMembers x2;

  // TODO these produce notes with an invalid source location.
  // static_assert((Wrapper<X>(), true));
  // static_assert((WrapperNonT(), true),"");

  static_assert((NonDefaultMembers(), true),""); // expected-error{{expression is not an integral constant expression}} \
                                                 // expected-note {{in call to}}
  constexpr bool FFF = (NonDefaultMembers() == NonDefaultMembers()); // expected-error {{must be initialized by a constant expression}} \
								     // expected-note {{in call to 'NonDefaultMembers()'}}
}

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