blob: a3e5a0931491b58dfcbf283ed9dfb32b8a162fb1 [file] [log] [blame]
// RUN: %clang_cc1 -std=c++2c -verify %s
struct NotAPack;
template <typename T, auto V, template<typename> typename Tp>
void not_pack() {
int i = 0;
i...[0]; // expected-error {{i does not refer to the name of a parameter pack}}
V...[0]; // expected-error {{V does not refer to the name of a parameter pack}}
NotAPack...[0] a; // expected-error{{'NotAPack' does not refer to the name of a parameter pack}}
T...[0] b; // expected-error{{'T' does not refer to the name of a parameter pack}}
Tp...[0] c; // expected-error{{'Tp' does not refer to the name of a parameter pack}}
}
template <typename T, auto V, template<typename> typename Tp>
void not_pack_arrays() {
NotAPack...[0] a[1]; // expected-error{{'NotAPack' does not refer to the name of a parameter pack}}
T...[0] b[1]; // expected-error{{'T' does not refer to the name of a parameter pack}}
Tp...[0] c[1]; // expected-error{{'Tp' does not refer to the name of a parameter pack}}
}
template <typename T>
struct TTP;
void test_errors() {
not_pack<int, 0, TTP>();
not_pack_arrays<int, 0, TTP>();
}
namespace invalid_indexes {
int non_constant_index(); // expected-note 2{{declared here}}
template <int idx>
int params(auto... p) {
return p...[idx]; // #error-param-size
}
template <auto N, typename...T>
int test_types() {
T...[N] a; // #error-type-size
}
void test() {
params<0>(); // expected-note{{here}} \
// expected-error@#error-param-size {{invalid index 0 for pack p of size 0}}
params<1>(0); // expected-note{{here}} \
// expected-error@#error-param-size {{invalid index 1 for pack p of size 1}}
params<-1>(0); // expected-note{{here}} \
// expected-error@#error-param-size {{invalid index -1 for pack p of size 1}}
test_types<-1>(); //expected-note {{in instantiation}} \
// expected-error@#error-type-size {{invalid index -1 for pack 'T' of size 0}}
test_types<-1, int>(); //expected-note {{in instantiation}} \
// expected-error@#error-type-size {{invalid index -1 for pack 'T' of size 1}}
test_types<0>(); //expected-note {{in instantiation}} \
// expected-error@#error-type-size {{invalid index 0 for pack 'T' of size 0}}
test_types<1, int>(); //expected-note {{in instantiation}} \
// expected-error@#error-type-size {{invalid index 1 for pack 'T' of size 1}}
}
void invalid_indexes(auto... p) {
p...[non_constant_index()]; // expected-error {{array size is not a constant expression}}\
// expected-note {{cannot be used in a constant expression}}
const char* no_index = "";
p...[no_index]; // expected-error {{value of type 'const char *' is not implicitly convertible}}
}
void invalid_index_types() {
[]<typename... T> {
T...[non_constant_index()] a; // expected-error {{array size is not a constant expression}}\
// expected-note {{cannot be used in a constant expression}}
}(); //expected-note {{in instantiation}}
}
}
template <typename T, typename U>
constexpr bool is_same = false;
template <typename T>
constexpr bool is_same<T, T> = true;
template <typename T>
constexpr bool f(auto&&... p) {
return is_same<T, decltype(p...[0])>;
}
void g() {
int a = 0;
const int b = 0;
static_assert(f<int&&>(0));
static_assert(f<int&>(a));
static_assert(f<const int&>(b));
}
template <auto... p>
struct check_ice {
enum e {
x = p...[0]
};
};
static_assert(check_ice<42>::x == 42);
struct S{};
template <auto... p>
constexpr auto constant_initializer = p...[0];
constexpr auto InitOk = constant_initializer<S{}>;
consteval int evaluate(auto... p) {
return p...[0];
}
constexpr int x = evaluate(42, S{});
static_assert(x == 42);
namespace splice {
template <auto ... Is>
struct IL{};
template <typename ... Ts>
struct TL{};
template <typename Tl, typename Il>
struct SpliceImpl;
template <typename ... Ts, auto ...Is>
struct SpliceImpl<TL<Ts...>, IL<Is...>>{
using type = TL<Ts...[Is]...>;
};
template <typename Tl, typename Il>
using Splice = typename SpliceImpl<Tl, Il>::type;
using type = Splice<TL<char, short, long, double>, IL<1, 2>>;
static_assert(is_same<type, TL<short, long>>);
}
namespace GH81697 {
template<class... Ts> struct tuple {
int __x0;
};
template<auto I, class... Ts>
Ts...[I]& get(tuple<Ts...>& t) {
return t.__x0;
}
void f() {
tuple<int> x;
get<0>(x);
}
}
namespace GH88929 {
bool b = a...[0]; // expected-error {{use of undeclared identifier 'a'}}
using E = P...[0]; // expected-error {{unknown type name 'P'}} \
// expected-error {{expected ';' after alias declaration}}
}
namespace GH88925 {
template <typename...> struct S {};
template <auto...> struct W {};
template <int...> struct sequence {};
template <typename... args, int... indices> auto f(sequence<indices...>) {
return S<args...[indices]...>(); // #use
}
template <auto... args, int... indices> auto g(sequence<indices...>) {
return W<args...[indices]...>(); // #nttp-use
}
void h() {
static_assert(__is_same(decltype(f<int>(sequence<0, 0>())), S<int, int>));
static_assert(__is_same(decltype(f<int, long>(sequence<0, 0>())), S<int, int>));
static_assert(__is_same(decltype(f<int, long>(sequence<0, 1>())), S<int, long>));
f<int, long>(sequence<3>());
// expected-error@#use {{invalid index 3 for pack 'args' of size 2}}}
// expected-note-re@-2 {{function template specialization '{{.*}}' requested here}}
struct foo {};
struct bar {};
struct baz {};
static_assert(__is_same(decltype(g<foo{}, bar{}, baz{}>(sequence<0, 2, 1>())), W<foo{}, baz{}, bar{}>));
g<foo{}>(sequence<4>());
// expected-error@#nttp-use {{invalid index 4 for pack args of size 1}}
// expected-note-re@-2 {{function template specialization '{{.*}}' requested here}}
}
}