view clang/test/SemaCXX/cxx2a-consteval.cpp @ 222:81f6424ef0e3 llvm-original

LLVM original branch
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sun, 18 Jul 2021 22:10:01 +0900
parents 79ff65ed7e25
children c4bab56944e8
line wrap: on
line source

// RUN: %clang_cc1 -std=c++2a -emit-llvm-only -Wno-unused-value %s -verify

typedef __SIZE_TYPE__ size_t;

namespace basic_sema {

consteval int f1(int i) {
  return i;
}

consteval constexpr int f2(int i) { 
  //expected-error@-1 {{cannot combine}}
  return i;
}

constexpr auto l_eval = [](int i) consteval {
// expected-note@-1+ {{declared here}}

  return i;
};

constexpr consteval int f3(int i) {
  //expected-error@-1 {{cannot combine}}
  return i;
}

struct A {
  consteval int f1(int i) const {
// expected-note@-1 {{declared here}}
    return i;
  }
  consteval A(int i);
  consteval A() = default;
  consteval ~A() = default; // expected-error {{destructor cannot be declared consteval}}
};

consteval struct B {}; // expected-error {{struct cannot be marked consteval}}

consteval typedef B b; // expected-error {{typedef cannot be consteval}}

consteval int redecl() {return 0;} // expected-note {{previous declaration is here}}
constexpr int redecl() {return 0;} // expected-error {{constexpr declaration of 'redecl' follows consteval declaration}}

consteval int i = 0; // expected-error {{consteval can only be used in function declarations}}

consteval int; // expected-error {{consteval can only be used in function declarations}}

consteval int f1() {} // expected-error {{no return statement in consteval function}}

struct C {
  C() {}
  ~C() {}
};

struct D {
  C c;
  consteval D() = default; // expected-error {{cannot be consteval}}
  consteval ~D() = default; // expected-error {{destructor cannot be declared consteval}}
};

struct E : C {
  consteval ~E() {} // expected-error {{cannot be declared consteval}}
};
}

consteval int main() { // expected-error {{'main' is not allowed to be declared consteval}}
  return 0;
}

consteval int f_eval(int i) {
// expected-note@-1+ {{declared here}}
  return i;
}

namespace taking_address {

using func_type = int(int);

func_type* p1 = (&f_eval);
// expected-error@-1 {{take address}}
func_type* p7 = __builtin_addressof(f_eval);
// expected-error@-1 {{take address}}

auto p = f_eval;
// expected-error@-1 {{take address}}

auto m1 = &basic_sema::A::f1;
// expected-error@-1 {{take address}}
auto l1 = &decltype(basic_sema::l_eval)::operator();
// expected-error@-1 {{take address}}

consteval int f(int i) {
// expected-note@-1+ {{declared here}}
  return i;
}

auto ptr = &f;
// expected-error@-1 {{take address}}

auto f1() {
  return &f;
// expected-error@-1 {{take address}}
}

}

namespace invalid_function {

struct A {
  consteval void *operator new(size_t count);
  // expected-error@-1 {{'operator new' cannot be declared consteval}}
  consteval void *operator new[](size_t count);
  // expected-error@-1 {{'operator new[]' cannot be declared consteval}}
  consteval void operator delete(void* ptr);
  // expected-error@-1 {{'operator delete' cannot be declared consteval}}
  consteval void operator delete[](void* ptr);
  // expected-error@-1 {{'operator delete[]' cannot be declared consteval}}
  consteval ~A() {}
  // expected-error@-1 {{destructor cannot be declared consteval}}
};

}

namespace nested {
consteval int f() {
  return 0;
}

consteval int f1(...) {
  return 1;
}

enum E {};

using T = int(&)();

consteval auto operator+ (E, int(*a)()) {
  return 0;
}

void d() {
  auto i = f1(E() + &f);
}

auto l0 = [](auto) consteval {
  return 0;
};

int i0 = l0(&f1);

int i1 = f1(l0(4));

int i2 = f1(&f1, &f1, &f1, &f1, &f1, &f1, &f1);

int i3 = f1(f1(f1(&f1, &f1), f1(&f1, &f1), f1(f1(&f1, &f1), &f1)));

}

namespace user_defined_literal {

consteval int operator"" _test(unsigned long long i) {
// expected-note@-1+ {{declared here}}
  return 0;
}

int i = 0_test;

auto ptr = &operator"" _test;
// expected-error@-1 {{take address}}

consteval auto operator"" _test1(unsigned long long i) {
  return &f_eval;
}

auto i1 = 0_test1; // expected-error {{is not a constant expression}}
// expected-note@-1 {{is not a constant expression}}

}

namespace return_address {

consteval int f() {
// expected-note@-1 {{declared here}}
  return 0;
}

consteval int(*ret1(int i))() {
  return &f;
}

auto ptr = ret1(0);
// expected-error@-1 {{is not a constant expression}}
// expected-note@-2 {{pointer to a consteval}}

struct A {
  consteval int f(int) {
    // expected-note@-1+ {{declared here}}
    return 0;    
  }
};

using mem_ptr_type = int (A::*)(int);

template<mem_ptr_type ptr>
struct C {};

C<&A::f> c;
// expected-error@-1 {{is not a constant expression}}
// expected-note@-2 {{pointer to a consteval}}

consteval mem_ptr_type ret2() {
  return &A::f;
}

C<ret2()> c1;
// expected-error@-1 {{is not a constant expression}}
// expected-note@-2 {{pointer to a consteval}}

}

namespace context {

int g_i;
// expected-note@-1 {{declared here}}

consteval int f(int) {
  return 0;
}

constexpr int c_i = 0;

int t1 = f(g_i);
// expected-error@-1 {{is not a constant expression}}
// expected-note@-2 {{read of non-const variable}}
int t3 = f(c_i);

constexpr int f_c(int i) {
// expected-note@-1 {{declared here}}
  int t = f(i);
// expected-error@-1 {{is not a constant expression}}
// expected-note@-2 {{function parameter}}
  return f(0);  
}

consteval int f_eval(int i) {
  return f(i);
}

auto l0 = [](int i) consteval {
  return f(i);
};

auto l1 = [](int i) constexpr {
// expected-note@-1 {{declared here}}
  int t = f(i);
// expected-error@-1 {{is not a constant expression}}
// expected-note@-2 {{function parameter}}
  return f(0);  
};

}

namespace std {

template <typename T> struct remove_reference { using type = T; };
template <typename T> struct remove_reference<T &> { using type = T; };
template <typename T> struct remove_reference<T &&> { using type = T; };

template <typename T>
constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {
  return static_cast<typename std::remove_reference<T>::type &&>(t);
}

}

namespace temporaries {

struct A {
  consteval int ret_i() const { return 0; }
  consteval A ret_a() const { return A{}; }
  constexpr ~A() { }
};

consteval int by_value_a(A a) { return a.ret_i(); }

consteval int const_a_ref(const A &a) {
  return a.ret_i();
}

consteval int rvalue_ref(const A &&a) {
  return a.ret_i();
}

consteval const A &to_lvalue_ref(const A &&a) {
  return a;
}

void test() {
  constexpr A a {};
  { int k = A().ret_i(); }
  { A k = A().ret_a(); }
  { A k = to_lvalue_ref(A()); }// expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
  { A k = to_lvalue_ref(A().ret_a()); } // expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
  { int k = A().ret_a().ret_i(); }
  { int k = by_value_a(A()); }
  { int k = const_a_ref(A()); }
  { int k = const_a_ref(a); }
  { int k = rvalue_ref(A()); }
  { int k = rvalue_ref(std::move(a)); }
  { int k = const_a_ref(A().ret_a()); }
  { int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
  { int k = const_a_ref(to_lvalue_ref(std::move(a))); }
  { int k = by_value_a(A().ret_a()); }
  { int k = by_value_a(to_lvalue_ref(std::move(a))); }
  { int k = (A().ret_a(), A().ret_i()); }
  { int k = (const_a_ref(A().ret_a()), A().ret_i()); }//
}

}

namespace alloc {

consteval int f() {
  int *A = new int(0);
// expected-note@-1+ {{allocation performed here was not deallocated}}
  return *A;
}

int i1 = f(); // expected-error {{is not a constant expression}}

struct A {
  int* p = new int(42);
  // expected-note@-1+ {{heap allocation performed here}}
  consteval int ret_i() const { return p ? *p : 0; }
  consteval A ret_a() const { return A{}; }
  constexpr ~A() { delete p; }
};

consteval int by_value_a(A a) { return a.ret_i(); }

consteval int const_a_ref(const A &a) {
  return a.ret_i();
}

consteval int rvalue_ref(const A &&a) {
  return a.ret_i();
}

consteval const A &to_lvalue_ref(const A &&a) {
  return a;
}

void test() {
  constexpr A a{ nullptr };
  { int k = A().ret_i(); }
  { A k = A().ret_a(); } // expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}}
  { A k = to_lvalue_ref(A()); } // expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
  { A k = to_lvalue_ref(A().ret_a()); } // expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
  { int k = A().ret_a().ret_i(); }
  { int k = by_value_a(A()); }
  { int k = const_a_ref(A()); }
  { int k = const_a_ref(a); }
  { int k = rvalue_ref(A()); }
  { int k = rvalue_ref(std::move(a)); }
  { int k = const_a_ref(A().ret_a()); }
  { int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
  { int k = const_a_ref(to_lvalue_ref(std::move(a))); }
  { int k = by_value_a(A().ret_a()); }
  { int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
  { int k = (A().ret_a(), A().ret_i()); }// expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}}
  { int k = (const_a_ref(A().ret_a()), A().ret_i()); }
}

}

namespace self_referencing {

struct S {
  S* ptr = nullptr;
  constexpr S(int i) : ptr(this) {
    if (this == ptr && i)
      ptr = nullptr;
  }
  constexpr ~S() {}
};

consteval S f(int i) {
  return S(i);
}

void test() {
  S s(1);
  s = f(1);
  s = f(0); // expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
}

struct S1 {
  S1* ptr = nullptr;
  consteval S1(int i) : ptr(this) {
    if (this == ptr && i)
      ptr = nullptr;
  }
  constexpr ~S1() {}
};

void test1() {
  S1 s(1);
  s = S1(1);
  s = S1(0); // expected-error {{is not a constant expression}}
  // expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
}

}
namespace ctor {

consteval int f_eval() { // expected-note+ {{declared here}}
  return 0;
}

namespace std {
  struct strong_ordering {
    int 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};
  constexpr bool operator!=(strong_ordering, int);
}

namespace override {
  struct A {
    virtual consteval void f(); // expected-note {{overridden}}
    virtual void g(); // expected-note {{overridden}}
  };
  struct B : A {
    consteval void f();
    void g();
  };
  struct C : A {
    void f(); // expected-error {{non-consteval function 'f' cannot override a consteval function}}
    consteval void g(); // expected-error {{consteval function 'g' cannot override a non-consteval function}}
  };

  namespace implicit_equals_1 {
    struct Y;
    struct X {
      std::strong_ordering operator<=>(const X&) const;
      constexpr bool operator==(const X&) const;
      virtual consteval bool operator==(const Y&) const; // expected-note {{here}}
    };
    struct Y : X {
      std::strong_ordering operator<=>(const Y&) const = default;
      // expected-error@-1 {{non-consteval function 'operator==' cannot override a consteval function}}
    };
  }

  namespace implicit_equals_2 {
    struct Y;
    struct X {
      constexpr std::strong_ordering operator<=>(const X&) const;
      constexpr bool operator==(const X&) const;
      virtual bool operator==(const Y&) const; // expected-note {{here}}
    };
    struct Y : X {
      consteval std::strong_ordering operator<=>(const Y&) const = default;
      // expected-error@-1 {{consteval function 'operator==' cannot override a non-consteval function}}
    };
  }
}

namespace operator_rewrite {
  struct A {
    friend consteval int operator<=>(const A&, const A&) { return 0; }
  };
  const bool k = A() < A();
  static_assert(!k);

  A a;
  bool k2 = A() < a; // OK, does not access 'a'.

  struct B {
    friend consteval int operator<=>(const B &l, const B &r) { return r.n - l.n; } // expected-note {{read of }}
    int n;
  };
  static_assert(B() >= B());
  B b; // expected-note {{here}}
  bool k3 = B() < b; // expected-error-re {{call to consteval function '{{.*}}::operator<=>' is not a constant expression}} expected-note {{in call}}
}

struct A {
  int(*ptr)();
  consteval A(int(*p)() = nullptr) : ptr(p) {}
};

struct B {
  int(*ptr)();
  B() : ptr(nullptr) {}
  consteval B(int(*p)(), int) : ptr(p) {}
};

void test() {
  { A a; }
  { A a(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B b(nullptr, 0); }
  { B b(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { A a{}; }
  { A a{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B b{nullptr, 0}; }
  { B b{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { A a = A(); }
  { A a = A(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B b = B(nullptr, 0); }
  { B b = B(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { A a = A{}; }
  { A a = A{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B b = B{nullptr, 0}; }
  { B b = B{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { A a; a = A(); }
  { A a; a = A(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B b; b = B(nullptr, 0); }
  { B b; b = B(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { A a; a = A{}; }
  { A a; a = A{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B b; b = B{nullptr, 0}; }
  { B b; b = B{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { A* a; a = new A(); }
  { A* a; a = new A(&f_eval); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B* b; b = new B(nullptr, 0); }
  { B* b; b = new B(&f_eval, 0); } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { A* a; a = new A{}; }
  { A* a; a = new A{&f_eval}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { B* b; b = new B{nullptr, 0}; }
  { B* b; b = new B{&f_eval, 0}; } // expected-error {{is not a constant expression}} expected-note {{to a consteval}}
}

}

namespace copy_ctor {

consteval int f_eval() { // expected-note+ {{declared here}}
  return 0;
}

struct Copy {
  int(*ptr)();
  constexpr Copy(int(*p)() = nullptr) : ptr(p) {}
  consteval Copy(const Copy&) = default;
};

constexpr const Copy &to_lvalue_ref(const Copy &&a) {
  return a;
}

void test() {
  constexpr const Copy C;
  // there is no the copy constructor call when its argument is a prvalue because of garanteed copy elision.
  // so we need to test with both prvalue and xvalues.
  { Copy c(C); }
  { Copy c((Copy(&f_eval))); }// expected-error {{cannot take address of consteval}}
  { Copy c(std::move(C)); }
  { Copy c(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c(to_lvalue_ref((Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c(to_lvalue_ref(std::move(C))); }
  { Copy c(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c = Copy(C); }
  { Copy c = Copy(Copy(&f_eval)); }// expected-error {{cannot take address of consteval}}
  { Copy c = Copy(std::move(C)); }
  { Copy c = Copy(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c = Copy(to_lvalue_ref(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c = Copy(to_lvalue_ref(std::move(C))); }
  { Copy c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c; c = Copy(C); }
  { Copy c; c = Copy(Copy(&f_eval)); }// expected-error {{cannot take address of consteval}}
  { Copy c; c = Copy(std::move(C)); }
  { Copy c; c = Copy(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c; c = Copy(to_lvalue_ref(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy c; c = Copy(to_lvalue_ref(std::move(C))); }
  { Copy c; c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy* c; c = new Copy(C); }
  { Copy* c; c = new Copy(Copy(&f_eval)); }// expected-error {{cannot take address of consteval}}
  { Copy* c; c = new Copy(std::move(C)); }
  { Copy* c; c = new Copy(std::move(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy* c; c = new Copy(to_lvalue_ref(Copy(&f_eval))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
  { Copy* c; c = new Copy(to_lvalue_ref(std::move(C))); }
  { Copy* c; c = new Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}}
}

} // namespace special_ctor