blob: 5e149dd6ec5a67b0dc9ae5ad89f66e42e3959a80 [file] [log] [blame]
// RUN: %clang_cc1 -std=c++2a -emit-llvm-only -Wno-unused-value %s -verify
// RUN: %clang_cc1 -std=c++2b -emit-llvm-only -Wno-unused-value %s -verify
consteval int id(int i) { return i; }
constexpr char id(char c) { return c; }
template <typename T>
constexpr int f(T t) { // expected-note {{declared here}}
return t + id(t); // expected-note 2{{'f<int>' is an immediate function because its body contains a call to a consteval function 'id' and that call is not a constant expression}}
}
namespace examples {
auto a = &f<char>; // ok, f<char> is not an immediate function
auto b = &f<int>; // expected-error {{cannot take address of immediate function 'f<int>' outside of an immediate invocation}}
static_assert(f(3) == 6); // ok
template <typename T>
constexpr int g(T t) { // g<int> is not an immediate function
return t + id(42); // because id(42) is already a constant
}
template <typename T, typename F>
constexpr bool is_not(T t, F f) {
return not f(t);
}
consteval bool is_even(int i) { return i % 2 == 0; }
static_assert(is_not(5, is_even));
int x = 0; // expected-note {{declared here}}
template <typename T>
constexpr T h(T t = id(x)) { // expected-note {{read of non-const variable 'x' is not allowed in a constant expression}} \
// expected-note 2{{'hh<int>' is an immediate function because its body contains a call to a consteval function 'id' and that call is not a constant expression}}
return t;
}
template <typename T>
constexpr T hh() { // hh<int> is an immediate function
[[maybe_unused]] auto x = h<T>();
return h<T>();
}
int i = hh<int>(); // expected-error {{call to immediate function 'examples::hh<int>' is not a constant expression}} \
// expected-note {{in call to 'hh()'}}
struct A {
int x;
int y = id(x);
};
template <typename T>
constexpr int k(int) {
return A(42).y;
}
}
namespace nested {
template <typename T>
constexpr int fdupe(T t) {
return id(t);
}
struct a {
constexpr a(int) { }
};
a aa(fdupe<int>((f<int>(7))));
template <typename T>
constexpr int foo(T t); // expected-note {{declared here}}
a bb(f<int>(foo<int>(7))); // expected-error{{call to immediate function 'f<int>' is not a constant expression}} \
// expected-note{{undefined function 'foo<int>' cannot be used in a constant expression}}
}
namespace e2{
template <typename T>
constexpr int f(T t);
auto a = &f<char>;
auto b = &f<int>;
}
namespace forward_declare_constexpr{
template <typename T>
constexpr int f(T t);
auto a = &f<char>;
auto b = &f<int>;
template <typename T>
constexpr int f(T t) {
return id(0);
}
}
namespace forward_declare_consteval{
template <typename T>
constexpr int f(T t); // expected-note {{'f<int>' defined here}}
auto a = &f<char>;
auto b = &f<int>; // expected-error {{immediate function 'f<int>' used before it is defined}} \
// expected-note {{in instantiation of function template specialization}}
template <typename T>
constexpr int f(T t) {
return id(t); // expected-note {{'f<int>' is an immediate function because its body contains a call to a consteval function 'id' and that call is not a constant expression}}
}
}
namespace constructors {
consteval int f(int) {
return 0;
}
struct S {
constexpr S(auto i) {
f(i);
}
};
constexpr void g(auto i) {
[[maybe_unused]] S s{i};
}
void test() {
g(0);
}
}
namespace aggregate {
consteval int f(int);
struct S{
int a = 0;
int b = f(a);
};
constexpr bool test(auto i) {
S s{i};
return s.b == 2 *i;
}
consteval int f(int i) {
return 2 * i;
}
void test() {
static_assert(test(42));
}
}
namespace ConstevalConstructor{
int x = 0; // expected-note {{declared here}}
struct S {
consteval S(int) {};
};
constexpr int g(auto t) {
S s(t); // expected-note {{'g<int>' is an immediate function because its body contains a call to a consteval constructor 'S' and that call is not a constant expression}}
return 0;
}
int i = g(x); // expected-error {{call to immediate function 'ConstevalConstructor::g<int>' is not a constant expression}} \
// expected-note {{read of non-const variable 'x' is not allowed in a constant expression}}
}