It would be nice to see what our users think about this change, as this is something that WG21/EWG quite wants to fix a handful of questionable issues with UB. Depending on the outcome of this after being committed, we might instead suggest EWG undeprecate this, and require a bit of 'magic' from the lexer. Additionally, this patch makes it so we emit this diagnostic ALSO in cases where the literal name is reserved. It doesn't make sense to limit that. --------- Co-authored-by: Vlad Serebrennikov <serebrennikov.vladislav@gmail.com>
1275 lines
40 KiB
C++
1275 lines
40 KiB
C++
// RUN: %clang_cc1 -std=c++2a -emit-llvm-only -Wno-unused-value -Wno-vla %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 marked 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-error{{cannot take address of immediate call operator}} \
|
|
// expected-note {{declared here}}
|
|
int t = f(i);
|
|
return f(0);
|
|
};
|
|
|
|
int(*test)(int) = l1;
|
|
|
|
}
|
|
|
|
namespace consteval_lambda_in_template {
|
|
struct S {
|
|
int *value;
|
|
constexpr S(int v) : value(new int {v}) {}
|
|
constexpr ~S() { delete value; }
|
|
};
|
|
consteval S fn() { return S(5); }
|
|
|
|
template <typename T>
|
|
void fn2() {
|
|
(void)[]() consteval -> int {
|
|
return *(fn().value); // OK, immediate context
|
|
};
|
|
}
|
|
|
|
void caller() {
|
|
fn2<int>();
|
|
}
|
|
}
|
|
|
|
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-note@-1 {{reference to temporary is not a constant expression}}
|
|
// expected-error@-2 {{'alloc::to_lvalue_ref' is not a constant expression}}
|
|
// expected-note@-3 {{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()); }
|
|
{ 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
|
|
|
|
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 'Val' 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 'Val' 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() {
|
|
// Explicitly defaulted constructor.
|
|
S<Foo, 1> s1;
|
|
S<Bar, 1> s2;
|
|
// User provided constructor.
|
|
S<Foo, 2> s3;
|
|
S<Bar, 2> s4;
|
|
// Consteval explicitly 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-note@-1 {{integer value -1 is outside the valid range of values [0, 1] for the enumeration type 'E'}}
|
|
return (int)eParam;
|
|
}
|
|
|
|
int test() {
|
|
return testDefaultArgForParam() + testDefaultArgForParam((E)1);
|
|
// expected-error@-1 {{call to consteval function 'GH50055::testDefaultArgForParam' is not a constant expression}}
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
namespace GH58302 {
|
|
struct A {
|
|
consteval A(){}
|
|
consteval operator int() { return 1;}
|
|
};
|
|
|
|
int f() {
|
|
int x = A{};
|
|
}
|
|
}
|
|
|
|
namespace GH57682 {
|
|
void test() {
|
|
constexpr auto l1 = []() consteval { // expected-error {{cannot take address of consteval call operator of '(lambda at}} \
|
|
// expected-note 2{{declared here}}
|
|
return 3;
|
|
};
|
|
constexpr int (*f1)(void) = l1; // expected-error {{constexpr variable 'f1' must be initialized by a constant expression}} \
|
|
// expected-note {{pointer to a consteval declaration is not a constant expression}}
|
|
|
|
|
|
constexpr auto lstatic = []() static consteval { // expected-error {{cannot take address of consteval call operator of '(lambda at}} \
|
|
// expected-note 2{{declared here}} \
|
|
// expected-warning {{extension}}
|
|
return 3;
|
|
};
|
|
constexpr int (*f2)(void) = lstatic; // expected-error {{constexpr variable 'f2' must be initialized by a constant expression}} \
|
|
// expected-note {{pointer to a consteval declaration is not a constant expression}}
|
|
|
|
int (*f3)(void) = []() consteval { return 3; }; // expected-error {{cannot take address of consteval call operator of '(lambda at}} \
|
|
// expected-note {{declared here}}
|
|
}
|
|
|
|
consteval void consteval_test() {
|
|
constexpr auto l1 = []() consteval { return 3; };
|
|
|
|
int (*f1)(void) = l1; // ok
|
|
}
|
|
}
|
|
|
|
namespace GH60286 {
|
|
|
|
struct A {
|
|
int i = 0;
|
|
|
|
consteval A() {}
|
|
A(const A&) { i = 1; }
|
|
consteval int f() { return i; }
|
|
};
|
|
|
|
constexpr auto B = A{A{}}.f();
|
|
static_assert(B == 0);
|
|
|
|
}
|
|
|
|
namespace GH58207 {
|
|
struct tester {
|
|
consteval tester(const char* name) noexcept { }
|
|
};
|
|
consteval const char* make_name(const char* name) { return name;}
|
|
consteval const char* pad(int P) { return "thestring"; }
|
|
|
|
int bad = 10; // expected-note 6{{declared here}}
|
|
|
|
tester glob1(make_name("glob1"));
|
|
tester glob2(make_name("glob2"));
|
|
constexpr tester cglob(make_name("cglob"));
|
|
tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
|
|
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
|
|
|
constexpr tester glob3 = { make_name("glob3") };
|
|
constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
|
|
// expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \
|
|
// expected-note 2{{read of non-const variable 'bad' is not allowed in a constant expression}}
|
|
|
|
auto V = make_name(pad(3));
|
|
auto V1 = make_name(pad(bad)); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
|
|
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
|
|
|
|
|
void foo() {
|
|
static tester loc1(make_name("loc1"));
|
|
static constexpr tester loc2(make_name("loc2"));
|
|
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
|
|
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
|
}
|
|
|
|
void bar() {
|
|
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
|
|
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
|
}
|
|
}
|
|
|
|
namespace GH64949 {
|
|
struct f {
|
|
int g; // expected-note 2{{subobject declared here}}
|
|
constexpr ~f() {}
|
|
};
|
|
class h {
|
|
|
|
public:
|
|
consteval h(char *) {}
|
|
consteval operator int() const { return 1; }
|
|
f i;
|
|
};
|
|
|
|
void test() { (int)h{nullptr}; }
|
|
// expected-error@-1 {{call to consteval function 'GH64949::h::h' is not a constant expression}}
|
|
// expected-note@-2 {{subobject 'g' is not initialized}}
|
|
|
|
int test2() { return h{nullptr}; }
|
|
// expected-error@-1 {{call to consteval function 'GH64949::h::h' is not a constant expression}}
|
|
// expected-note@-2 {{subobject 'g' is not initialized}}
|
|
|
|
|
|
}
|
|
|
|
namespace GH65985 {
|
|
|
|
int consteval operator""_foo(unsigned long long V) {
|
|
return 0;
|
|
}
|
|
int consteval operator""_bar(unsigned long long V); // expected-note 3{{here}}
|
|
|
|
int consteval f() {
|
|
return 0;
|
|
}
|
|
|
|
int consteval g(); // expected-note {{here}}
|
|
|
|
|
|
struct C {
|
|
static const int a = 1_foo;
|
|
static constexpr int b = 1_foo;
|
|
static const int c = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \
|
|
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
|
|
// expected-error {{in-class initializer for static data member is not a constant expression}}
|
|
|
|
// FIXME: remove duplicate diagnostics
|
|
static constexpr int d = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \
|
|
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
|
|
// expected-error {{constexpr variable 'd' must be initialized by a constant expression}} \
|
|
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}}
|
|
|
|
static const int e = f();
|
|
static const int f = g(); // expected-error {{call to consteval function 'GH65985::g' is not a constant expression}} \
|
|
// expected-error {{in-class initializer for static data member is not a constant expression}} \
|
|
// expected-note {{undefined function 'g' cannot be used in a constant expression}}
|
|
};
|
|
|
|
}
|
|
|
|
namespace GH66562 {
|
|
|
|
namespace ns
|
|
{
|
|
consteval int foo(int x) { return 1; } // expected-note {{declared here}} \
|
|
// expected-note {{passing argument to parameter 'x' here}}
|
|
}
|
|
|
|
template <class A>
|
|
struct T {
|
|
static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}} \
|
|
// expected-error {{cannot initialize a parameter of type 'int' with an rvalue of type 'char *'}}
|
|
};
|
|
|
|
template class T<char*>; // expected-note {{in instantiation}}
|
|
|
|
}
|
|
|
|
namespace GH65520 {
|
|
|
|
consteval int bar (int i) { if (i != 1) return 1/0; return 0; }
|
|
// expected-note@-1{{division by zero}}
|
|
|
|
void
|
|
g ()
|
|
{
|
|
int a_ok[bar(1)];
|
|
int a_err[bar(3)]; // expected-error {{call to consteval function 'GH65520::bar' is not a constant expression}} \
|
|
// expected-note {{in call to 'bar(3)'}}
|
|
}
|
|
|
|
consteval int undefined(); // expected-note {{declared here}}
|
|
|
|
consteval void immediate() {
|
|
int a [undefined()]; // expected-note {{undefined function 'undefined' cannot be used in a constant expression}} \
|
|
// expected-error {{call to consteval function 'GH65520::undefined' is not a constant expression}} \
|
|
// expected-error {{variable of non-literal type 'int[undefined()]' cannot be defined in a constexpr function before C++23}}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
namespace GH105558 {
|
|
|
|
consteval int* alloc() { return new int(0); }
|
|
consteval void f(int* p) { delete p; }
|
|
consteval void g1(int*&& p) { delete p; }
|
|
consteval void g2(const int* p) { delete p; }
|
|
consteval void g3(int*const& p) { delete p; }
|
|
struct X {
|
|
int* p;
|
|
explicit(false) constexpr X(int* p) : p(p) {}
|
|
};
|
|
consteval void g4(X x) { delete x.p; }
|
|
|
|
void test() {
|
|
f(alloc());
|
|
g1(alloc());
|
|
g2(alloc());
|
|
g3(alloc());
|
|
g4(alloc());
|
|
}
|
|
|
|
}
|
|
|
|
// Test that we don't redundantly instantiate the friend declaration in
|
|
// RemoveNestedImmediateInvocation(). Otherwise, we would end up with spurious
|
|
// redefinition errors.
|
|
namespace GH107175 {
|
|
|
|
consteval void consteval_func() {}
|
|
|
|
template <auto> struct define_f {
|
|
friend void foo() {}
|
|
};
|
|
|
|
template <auto = [] {}> struct A {};
|
|
|
|
struct B {
|
|
template <auto T> consteval void func() { (void)define_f<T>{}; }
|
|
};
|
|
|
|
int main() {
|
|
B{}.func<A{}>();
|
|
consteval_func();
|
|
}
|
|
|
|
} // namespace GH107175
|