callee in constant evaluation. We previously made a deep copy of function parameters of class type when passing them, resulting in the destructor for the parameter applying to the original argument value, ignoring any modifications made in the function body. This also meant that the 'this' pointer of the function parameter could be observed changing between the caller and the callee. This change completely reimplements how we model function parameters during constant evaluation. We now model them roughly as if they were variables living in the caller, albeit with an artificially reduced scope that covers only the duration of the function call, instead of modeling them as temporaries in the caller that we partially "reparent" into the callee at the point of the call. This brings some minor diagnostic improvements, as well as significantly reduced stack usage during constant evaluation.
597 lines
17 KiB
C++
597 lines
17 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 {{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
|