forked from OSchip/llvm-project
1021 lines
31 KiB
C++
1021 lines
31 KiB
C++
// 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@-1 {{'alloc::A::ret_a' is not a constant expression}}
|
|
// expected-note@-2 {{heap-allocated object is not a constant expression}}
|
|
// expected-error@-3 {{'alloc::to_lvalue_ref' is not a constant expression}}
|
|
// expected-note@-4 {{reference to temporary is not a constant expression}}
|
|
// expected-note@-5 {{temporary created here}}
|
|
{ int k = A().ret_a().ret_i(); }
|
|
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
|
|
// expected-note@-2 {{heap-allocated object is not a constant expression}}
|
|
{ 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()); }
|
|
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
|
|
// expected-note@-2 {{is not a constant expression}}
|
|
{ int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
|
|
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
|
|
// expected-note@-2 {{is not a constant expression}}
|
|
{ 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()); }
|
|
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
|
|
// expected-note@-2 {{is not a constant expression}}
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
|
namespace unevaluated {
|
|
|
|
template <typename T, typename U> struct is_same { static const bool value = false; };
|
|
template <typename T> struct is_same<T, T> { static const bool value = true; };
|
|
|
|
long f(); // expected-note {{declared here}}
|
|
auto consteval g(auto a) {
|
|
return a;
|
|
}
|
|
|
|
auto e = g(f()); // expected-error {{is not a constant expression}}
|
|
// expected-note@-1 {{non-constexpr function 'f' cannot be used in a constant expression}}
|
|
|
|
using T = decltype(g(f()));
|
|
static_assert(is_same<long, T>::value);
|
|
|
|
} // namespace unevaluated
|
|
|
|
namespace value_dependent {
|
|
|
|
consteval int foo(int x) {
|
|
return x;
|
|
}
|
|
|
|
template <int X> constexpr int bar() {
|
|
// Previously this call was rejected as value-dependent constant expressions
|
|
// can't be immediately evaluated. Now we show that we don't immediately
|
|
// evaluate them until they are instantiated.
|
|
return foo(X);
|
|
}
|
|
|
|
template <typename T> constexpr int baz() {
|
|
constexpr int t = sizeof(T);
|
|
// Previously this call was rejected as `t` is value-dependent and its value
|
|
// is unknown until the function is instantiated. Now we show that we don't
|
|
// reject such calls.
|
|
return foo(t);
|
|
}
|
|
|
|
static_assert(bar<15>() == 15);
|
|
static_assert(baz<int>() == sizeof(int));
|
|
} // namespace value_dependent
|
|
|
|
// https://github.com/llvm/llvm-project/issues/55601
|
|
namespace issue_55601 {
|
|
template<typename T>
|
|
class Bar {
|
|
consteval static T x() { return 5; } // expected-note {{non-constexpr constructor 'derp' cannot be used in a constant expression}}
|
|
public:
|
|
Bar() : a(x()) {} // expected-error {{call to consteval function 'issue_55601::Bar<issue_55601::derp>::x' is not a constant expression}}
|
|
// expected-error@-1 {{call to consteval function 'issue_55601::derp::operator int' is not a constant expression}}
|
|
// expected-note@-2 {{in call to 'x()'}}
|
|
// expected-note@-3 {{non-literal type 'issue_55601::derp' cannot be used in a constant expression}}
|
|
private:
|
|
int a;
|
|
};
|
|
Bar<int> f;
|
|
Bar<float> g;
|
|
|
|
struct derp {
|
|
// Can't be used in a constant expression
|
|
derp(int); // expected-note {{declared here}}
|
|
consteval operator int() const { return 5; }
|
|
};
|
|
Bar<derp> a; // expected-note {{in instantiation of member function 'issue_55601::Bar<issue_55601::derp>::Bar' requested here}}
|
|
|
|
struct constantDerp {
|
|
// Can be used in a constant expression.
|
|
consteval constantDerp(int) {}
|
|
consteval operator int() const { return 5; }
|
|
};
|
|
Bar<constantDerp> b;
|
|
|
|
} // namespace issue_55601
|
|
|
|
namespace default_argument {
|
|
|
|
// Previously calls of consteval functions in default arguments were rejected.
|
|
// Now we show that we don't reject such calls.
|
|
consteval int foo() { return 1; }
|
|
consteval int bar(int i = foo()) { return i * i; }
|
|
|
|
struct Test1 {
|
|
Test1(int i = bar(13)) {}
|
|
void v(int i = bar(13) * 2 + bar(15)) {}
|
|
};
|
|
Test1 t1;
|
|
|
|
struct Test2 {
|
|
constexpr Test2(int i = bar()) {}
|
|
constexpr void v(int i = bar(bar(bar(foo())))) {}
|
|
};
|
|
Test2 t2;
|
|
|
|
} // namespace default_argument
|
|
|
|
namespace PR50779 {
|
|
struct derp {
|
|
int b = 0;
|
|
};
|
|
|
|
constexpr derp d;
|
|
|
|
struct test {
|
|
consteval int operator[](int i) const { return {}; }
|
|
consteval const derp * operator->() const { return &d; }
|
|
consteval int f() const { return 12; } // expected-note 2{{declared here}}
|
|
};
|
|
|
|
constexpr test a;
|
|
|
|
// We previously rejected both of these overloaded operators as taking the
|
|
// address of a consteval function outside of an immediate context, but we
|
|
// accepted direct calls to the overloaded operator. Now we show that we accept
|
|
// both forms.
|
|
constexpr int s = a.operator[](1);
|
|
constexpr int t = a[1];
|
|
constexpr int u = a.operator->()->b;
|
|
constexpr int v = a->b;
|
|
// FIXME: I believe this case should work, but we currently reject.
|
|
constexpr int w = (a.*&test::f)(); // expected-error {{cannot take address of consteval function 'f' outside of an immediate invocation}}
|
|
constexpr int x = a.f();
|
|
|
|
// Show that we reject when not in an immediate context.
|
|
int w2 = (a.*&test::f)(); // expected-error {{cannot take address of consteval function 'f' outside of an immediate invocation}}
|
|
}
|
|
|
|
namespace PR48235 {
|
|
consteval int d() {
|
|
return 1;
|
|
}
|
|
|
|
struct A {
|
|
consteval int a() const { return 1; }
|
|
|
|
void b() {
|
|
this->a() + d(); // expected-error {{call to consteval function 'PR48235::A::a' is not a constant expression}} \
|
|
// expected-note {{use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}}
|
|
}
|
|
|
|
void c() {
|
|
a() + d(); // expected-error {{call to consteval function 'PR48235::A::a' is not a constant expression}} \
|
|
// expected-note {{use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}}
|
|
}
|
|
};
|
|
} // PR48235
|
|
|
|
namespace NamespaceScopeConsteval {
|
|
struct S {
|
|
int Val; // expected-note {{subobject declared here}}
|
|
consteval S() {}
|
|
};
|
|
|
|
S s1; // expected-error {{call to consteval function 'NamespaceScopeConsteval::S::S' is not a constant expression}} \
|
|
expected-note {{subobject of type 'int' is not initialized}}
|
|
|
|
template <typename Ty>
|
|
struct T {
|
|
Ty Val; // expected-note {{subobject declared here}}
|
|
consteval T() {}
|
|
};
|
|
|
|
T<int> t; // expected-error {{call to consteval function 'NamespaceScopeConsteval::T<int>::T' is not a constant expression}} \
|
|
expected-note {{subobject of type 'int' is not initialized}}
|
|
|
|
} // namespace NamespaceScopeConsteval
|
|
|
|
namespace Issue54578 {
|
|
// We expect the user-defined literal to be resovled entirely at compile time
|
|
// despite being instantiated through a template.
|
|
inline consteval unsigned char operator""_UC(const unsigned long long n) {
|
|
return static_cast<unsigned char>(n);
|
|
}
|
|
|
|
inline constexpr char f1(const auto octet) {
|
|
return 4_UC;
|
|
}
|
|
|
|
template <typename Ty>
|
|
inline constexpr char f2(const Ty octet) {
|
|
return 4_UC;
|
|
}
|
|
|
|
void test() {
|
|
static_assert(f1('a') == 4);
|
|
static_assert(f2('a') == 4);
|
|
constexpr int c = f1('a') + f2('a');
|
|
static_assert(c == 8);
|
|
}
|
|
}
|
|
|
|
namespace defaulted_special_member_template {
|
|
template <typename T>
|
|
struct default_ctor {
|
|
T data;
|
|
consteval default_ctor() = default; // expected-note {{non-constexpr constructor 'foo' cannot be used in a constant expression}}
|
|
};
|
|
|
|
template <typename T>
|
|
struct copy {
|
|
T data;
|
|
|
|
consteval copy(const copy &) = default; // expected-note {{non-constexpr constructor 'foo' cannot be used in a constant expression}}
|
|
consteval copy &operator=(const copy &) = default; // expected-note {{non-constexpr function 'operator=' cannot be used in a constant expression}}
|
|
copy() = default;
|
|
};
|
|
|
|
template <typename T>
|
|
struct move {
|
|
T data;
|
|
|
|
consteval move(move &&) = default; // expected-note {{non-constexpr constructor 'foo' cannot be used in a constant expression}}
|
|
consteval move &operator=(move &&) = default; // expected-note {{non-constexpr function 'operator=' cannot be used in a constant expression}}
|
|
move() = default;
|
|
};
|
|
|
|
struct foo {
|
|
foo() {} // expected-note {{declared here}}
|
|
foo(const foo &) {} // expected-note {{declared here}}
|
|
foo(foo &&) {} // expected-note {{declared here}}
|
|
|
|
foo& operator=(const foo &) { return *this; } // expected-note {{declared here}}
|
|
foo& operator=(foo &&) { return *this; } // expected-note {{declared here}}
|
|
};
|
|
|
|
void func() {
|
|
default_ctor<foo> fail0; // expected-error {{call to consteval function 'defaulted_special_member_template::default_ctor<defaulted_special_member_template::foo>::default_ctor' is not a constant expression}} \
|
|
expected-note {{in call to 'default_ctor()'}}
|
|
|
|
copy<foo> good0;
|
|
copy<foo> fail1{good0}; // expected-error {{call to consteval function 'defaulted_special_member_template::copy<defaulted_special_member_template::foo>::copy' is not a constant expression}} \
|
|
expected-note {{in call to 'copy(good0)'}}
|
|
fail1 = good0; // expected-error {{call to consteval function 'defaulted_special_member_template::copy<defaulted_special_member_template::foo>::operator=' is not a constant expression}} \
|
|
expected-note {{in call to '&fail1->operator=(good0)'}}
|
|
|
|
move<foo> good1;
|
|
move<foo> fail2{static_cast<move<foo>&&>(good1)}; // expected-error {{call to consteval function 'defaulted_special_member_template::move<defaulted_special_member_template::foo>::move' is not a constant expression}} \
|
|
expected-note {{in call to 'move(good1)'}}
|
|
fail2 = static_cast<move<foo>&&>(good1); // expected-error {{call to consteval function 'defaulted_special_member_template::move<defaulted_special_member_template::foo>::operator=' is not a constant expression}} \
|
|
expected-note {{in call to '&fail2->operator=(good1)'}}
|
|
}
|
|
} // namespace defaulted_special_member_template
|
|
|
|
namespace multiple_default_constructors {
|
|
struct Foo {
|
|
Foo() {} // expected-note {{declared here}}
|
|
};
|
|
struct Bar {
|
|
Bar() = default;
|
|
};
|
|
struct Baz {
|
|
consteval Baz() {}
|
|
};
|
|
|
|
template <typename T, unsigned N>
|
|
struct S {
|
|
T data;
|
|
S() requires (N==1) = default;
|
|
// This cannot be used in constexpr context.
|
|
S() requires (N==2) {} // expected-note {{declared here}}
|
|
consteval S() requires (N==3) = default; // expected-note {{non-constexpr constructor 'Foo' cannot be used in a constant expression}}
|
|
};
|
|
|
|
void func() {
|
|
// Explictly defaulted constructor.
|
|
S<Foo, 1> s1;
|
|
S<Bar, 1> s2;
|
|
// User provided constructor.
|
|
S<Foo, 2> s3;
|
|
S<Bar, 2> s4;
|
|
// Consteval explictly defaulted constructor.
|
|
S<Foo, 3> s5; // expected-error {{call to consteval function 'multiple_default_constructors::S<multiple_default_constructors::Foo, 3>::S' is not a constant expression}} \
|
|
expected-note {{in call to 'S()'}}
|
|
S<Bar, 3> s6;
|
|
S<Baz, 3> s7;
|
|
}
|
|
|
|
consteval int aConstevalFunction() { // expected-error {{consteval function never produces a constant expression}}
|
|
// Defaulted default constructors are implicitly consteval.
|
|
S<Bar, 1> s1;
|
|
|
|
S<Baz, 2> s4; // expected-note {{non-constexpr constructor 'S' cannot be used in a constant expression}}
|
|
|
|
S<Bar, 3> s2;
|
|
S<Baz, 3> s3;
|
|
return 0;
|
|
}
|
|
|
|
} // namespace multiple_default_constructors
|
|
|
|
namespace GH50055 {
|
|
enum E {e1=0, e2=1};
|
|
consteval int testDefaultArgForParam(E eParam = (E)-1) {
|
|
// expected-error@-1 {{integer value -1 is outside the valid range of values [0, 1] for this enumeration type}}
|
|
return (int)eParam;
|
|
}
|
|
|
|
int test() {
|
|
return testDefaultArgForParam() + testDefaultArgForParam((E)1);
|
|
}
|
|
}
|
|
|
|
namespace GH51182 {
|
|
// Nested consteval function.
|
|
consteval int f(int v) {
|
|
return v;
|
|
}
|
|
|
|
template <typename T>
|
|
consteval int g(T a) {
|
|
// An immediate function context.
|
|
int n = f(a);
|
|
return n;
|
|
}
|
|
static_assert(g(100) == 100);
|
|
// --------------------------------------
|
|
template <typename T>
|
|
consteval T max(const T& a, const T& b) {
|
|
return (a > b) ? a : b;
|
|
}
|
|
template <typename T>
|
|
consteval T mid(const T& a, const T& b, const T& c) {
|
|
T m = max(max(a, b), c);
|
|
if (m == a)
|
|
return max(b, c);
|
|
if (m == b)
|
|
return max(a, c);
|
|
return max(a, b);
|
|
}
|
|
static_assert(max(1,2)==2);
|
|
static_assert(mid(1,2,3)==2);
|
|
} // namespace GH51182
|
|
|
|
// https://github.com/llvm/llvm-project/issues/56183
|
|
namespace GH56183 {
|
|
consteval auto Foo(auto c) { return c; }
|
|
consteval auto Bar(auto f) { return f(); }
|
|
void test() {
|
|
constexpr auto x = Foo(Bar([] { return 'a'; }));
|
|
static_assert(x == 'a');
|
|
}
|
|
} // namespace GH56183
|
|
|
|
// https://github.com/llvm/llvm-project/issues/51695
|
|
namespace GH51695 {
|
|
// Original ========================================
|
|
template <typename T>
|
|
struct type_t {};
|
|
|
|
template <typename...>
|
|
struct list_t {};
|
|
|
|
template <typename T, typename... Ts>
|
|
consteval auto pop_front(list_t<T, Ts...>) -> auto {
|
|
return list_t<Ts...>{};
|
|
}
|
|
|
|
template <typename... Ts, typename F>
|
|
consteval auto apply(list_t<Ts...>, F fn) -> auto {
|
|
return fn(type_t<Ts>{}...);
|
|
}
|
|
|
|
void test1() {
|
|
constexpr auto x = apply(pop_front(list_t<char, char>{}),
|
|
[]<typename... Us>(type_t<Us>...) { return 42; });
|
|
static_assert(x == 42);
|
|
}
|
|
// Reduced 1 ========================================
|
|
consteval bool zero() { return false; }
|
|
|
|
template <typename F>
|
|
consteval bool foo(bool, F f) {
|
|
return f();
|
|
}
|
|
|
|
void test2() {
|
|
constexpr auto x = foo(zero(), []() { return true; });
|
|
static_assert(x);
|
|
}
|
|
|
|
// Reduced 2 ========================================
|
|
template <typename F>
|
|
consteval auto bar(F f) { return f;}
|
|
|
|
void test3() {
|
|
constexpr auto t1 = bar(bar(bar(bar([]() { return true; }))))();
|
|
static_assert(t1);
|
|
|
|
int a = 1; // expected-note {{declared here}}
|
|
auto t2 = bar(bar(bar(bar([=]() { return a; }))))(); // expected-error-re {{call to consteval function 'GH51695::bar<(lambda at {{.*}})>' is not a constant expression}}
|
|
// expected-note@-1 {{read of non-const variable 'a' is not allowed in a constant expression}}
|
|
|
|
constexpr auto t3 = bar(bar([x=bar(42)]() { return x; }))();
|
|
static_assert(t3==42);
|
|
constexpr auto t4 = bar(bar([x=bar(42)]() consteval { return x; }))();
|
|
static_assert(t4==42);
|
|
}
|
|
|
|
} // namespace GH51695
|
|
|
|
// https://github.com/llvm/llvm-project/issues/50455
|
|
namespace GH50455 {
|
|
void f() {
|
|
[]() consteval { int i{}; }();
|
|
[]() consteval { int i{}; ++i; }();
|
|
}
|
|
void g() {
|
|
(void)[](int i) consteval { return i; }(0);
|
|
(void)[](int i) consteval { return i; }(0);
|
|
}
|
|
} // namespace GH50455
|