-
Notifications
You must be signed in to change notification settings - Fork 10.8k
/
type-requirement.cpp
220 lines (164 loc) · 11.1 KB
/
type-requirement.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
using A = int;
template<typename T> using identity_t = T; // expected-note 4{{template is declared here}}}
template<typename T> struct identity { using type = T; };
// expected-note@-1 2{{template is declared here}}
struct C {};
struct D { static int type; }; // expected-note{{referenced member 'type' is declared here}}
// Basic unqualified and global-qualified lookups
static_assert(requires { typename A; typename ::A; });
static_assert(requires { typename identity_t<A>; typename ::identity_t<A>; });
static_assert(!requires { typename identity_t<A, A>; }); // expected-error{{too many template arguments for alias template 'identity_t'}}
static_assert(!requires { typename ::identity_t<A, A>; }); // expected-error{{too many template arguments for alias template 'identity_t'}}
static_assert(requires { typename identity<A>; });
static_assert(!requires { typename identity; });
// expected-error@-1 {{typename specifier refers to class template; argument deduction not allowed here}}
static_assert(!requires { typename ::identity; });
// expected-error@-1 {{typename specifier refers to class template; argument deduction not allowed here}}
static_assert(!requires { typename identity_t; });
// expected-error@-1 {{typename specifier refers to alias template; argument deduction not allowed here}}
static_assert(!requires { typename ::identity_t; });
// expected-error@-1 {{typename specifier refers to alias template; argument deduction not allowed here}}
namespace ns {
using B = int;
int C = 0;
// expected-note@-1 {{referenced 'C' is declared here}}
static_assert(requires { typename A; typename B; typename ::A; });
static_assert(!requires { typename ns::A; }); // expected-error{{no type named 'A' in namespace 'ns'}}
static_assert(!requires { typename ::B; }); // expected-error{{no type named 'B' in the global namespace}}
static_assert(requires { typename C; });
// expected-error@-1 {{typename specifier refers to non-type 'C'}}
}
// member type lookups
static_assert(requires { typename identity<int>::type; typename ::identity<int>::type; });
static_assert(!requires { typename identity<int>::typr; }); // expected-error{{no type named 'typr' in 'identity<int>'}}
static_assert(!requires { typename ::identity<int>::typr; }); // expected-error{{no type named 'typr' in 'identity<int>'}}
template<typename T> requires requires { typename T::type; }
// expected-note@-1 {{because 'typename T::type' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
// expected-note@-2 {{because 'typename T::type' would be invalid: no type named 'type' in 'C'}}
// expected-note@-3 {{because 'typename T::type' would be invalid: typename specifier refers to non-type member 'type' in 'D'}}
// expected-note@-4 {{in instantiation of template class 'invalid<D>' requested here}}
// expected-note@-5 {{in instantiation of requirement here}}
// expected-note@-6 {{while substituting template arguments into constraint expression here}}
// expected-note@-7 {{because 'typename T::type' would be invalid}}
struct r1 {};
using r1i1 = r1<identity<int>>;
using r1i2 = r1<int>; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}}
using r1i3 = r1<C>; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}}
using r1i4 = r1<D>; // expected-error{{constraints not satisfied for class template 'r1' [with T = D]}}
template<typename T> struct invalid { typename T::type x; };
// expected-error@-1 {{typename specifier refers to non-type member 'type' in 'D'}}
using r1i5 = r1<invalid<D>>;
// expected-error@-1 {{constraints not satisfied for class template 'r1' [with T = invalid<D>]}}
// expected-note@-2 {{while checking constraint satisfaction for template 'r1<invalid<D>>' required here}}
// mismatching template arguments
template<typename... Ts> requires requires { typename identity<Ts...>; } // expected-note{{because 'typename identity<Ts...>' would be invalid: too many template arguments for class template 'identity'}}
struct r2 {};
using r2i1 = r2<int>;
using r2i2 = r2<void>;
using r2i3 = r2<int, int>; // expected-error{{constraints not satisfied for class template 'r2' [with Ts = <int, int>]}}
namespace ns2 {
template<typename T, typename U> struct identity {};
template<typename... Ts> requires requires { typename identity<Ts...>; } // expected-note 2{{because 'typename identity<Ts...>' would be invalid: too few template arguments for class template 'identity'}}
struct r4 {};
using r4i1 = r4<int>; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = <int>]}}
}
using r4i2 = ns2::r4<int>; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = <int>]}}
using E = int;
template<typename T> requires requires { typename E<T>; } // expected-error{{expected ';' at end of requirement}}
struct r5v1 {};
template<typename T> requires requires { typename ::E<T>; } // expected-error{{expected ';' at end of requirement}}
struct r5v2 {};
template<typename T> requires (sizeof(T) == 1)
struct chars_only {};
template<typename T> requires requires { typename chars_only<T>; } // expected-note{{because 'typename chars_only<T>' would be invalid: constraints not satisfied for class template 'chars_only' [with T = int]}}
struct r6 {};
using r6i = r6<int>; // expected-error{{constraints not satisfied for class template 'r6' [with T = int]}}
template<typename T> int F = 0; // expected-note 2{{variable template 'F' declared here}}
static_assert(!requires { typename F<int>; });
// expected-error@-1{{template name refers to non-type template 'F'}}
static_assert(!requires { typename ::F<int>; });
// expected-error@-1{{template name refers to non-type template '::F'}}
struct G { template<typename T> static T temp; };
template<typename T> requires requires { typename T::template temp<int>; }
// expected-note@-1{{because 'typename T::template temp<int>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
// expected-note@-2{{because 'typename T::template temp<int>' would be invalid: no member named 'temp' in 'D'}}
// expected-note@-3{{because 'typename T::template temp<int>' would be invalid: template name refers to non-type template 'G::template temp'}}
struct r7 {};
using r7i1 = r7<int>; // expected-error{{constraints not satisfied for class template 'r7' [with T = int]}}
using r7i2 = r7<D>; // expected-error{{constraints not satisfied for class template 'r7' [with T = D]}}
using r7i3 = r7<G>; // expected-error{{constraints not satisfied for class template 'r7' [with T = G]}}
template<typename T> struct H;
template<typename T> requires requires { typename H<T>; }
struct r8 {};
using r8i = r8<int>;
template<typename T> struct I { struct incomplete; }; // expected-note{{member is declared here}}
static_assert(!requires { I<int>::incomplete::inner; }); // expected-error{{implicit instantiation of undefined member 'I<int>::incomplete'}}
template<typename T> requires requires { typename I<T>::incomplete::inner; } // expected-note{{because 'typename I<T>::incomplete::inner' would be invalid: implicit instantiation of undefined member 'I<int>::incomplete'}}
struct r9 {};
using r9i = r9<int>; // expected-error{{constraints not satisfied for class template 'r9' [with T = int]}}
namespace ns3 {
struct X { }; // expected-note 2{{candidate found by name lookup is 'ns3::X'}}
}
struct X { using inner = int; }; // expected-note 2{{candidate found by name lookup is 'X'}}
using namespace ns3;
static_assert(requires { typename X; }); // expected-error{{reference to 'X' is ambiguous}}
static_assert(requires { typename X::inner; }); // expected-error{{reference to 'X' is ambiguous}}
// expected-error@-1{{unknown type name 'inner'}}
// naming a type template specialization in a type requirement does not require
// it to be complete and should not care about partial specializations.
template<typename T>
struct Z;
template<typename T> requires (sizeof(T) >= 1)
struct Z<T> {}; // expected-note{{partial specialization matches [with T = int]}}
template<typename T> requires (sizeof(T) <= 4)
struct Z<T> {}; // expected-note{{partial specialization matches [with T = int]}}
Z<int> x; // expected-error{{ambiguous partial specializations of 'Z<int>'}}
static_assert(requires { typename Z<int>; });
// C++ [expr.prim.req.type] Example
namespace std_example {
template<typename T, typename T::type = 0> struct S;
// expected-note@-1 {{because 'typename S<T>' would be invalid: no type named 'type' in 'std_example::has_inner}}
template<typename T> using Ref = T&; // expected-note{{because 'typename Ref<T>' would be invalid: cannot form a reference to 'void'}}
template<typename T> concept C1 =
requires {
typename T::inner;
// expected-note@-1 {{because 'typename T::inner' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
// expected-note@-2 {{because 'typename T::inner' would be invalid: no type named 'inner' in 'std_example::has_type'}}
};
template<typename T> concept C2 = requires { typename S<T>; };
template<typename T> concept C3 = requires { typename Ref<T>; };
struct has_inner { using inner = int;};
struct has_type { using type = int; };
struct has_inner_and_type { using inner = int; using type = int; };
static_assert(C1<has_inner_and_type> && C2<has_inner_and_type> && C3<has_inner_and_type>);
template<C1 T> struct C1_check {};
// expected-note@-1 {{because 'int' does not satisfy 'C1'}}
// expected-note@-2 {{because 'std_example::has_type' does not satisfy 'C1'}}
template<C2 T> struct C2_check {};
// expected-note@-1 {{because 'std_example::has_inner' does not satisfy 'C2'}}
template<C3 T> struct C3_check {};
// expected-note@-1 {{because 'void' does not satisfy 'C3'}}
using c1 = C1_check<int>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}}
using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}}
using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}}
using c4 = C3_check<void>; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}}
}
namespace PR48656 {
template <typename T> concept C = requires { requires requires { T::a; }; };
// expected-note@-1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}}
template <C...> struct A {};
// expected-note@-1 {{because 'PR48656::T1' does not satisfy 'C'}}
struct T1 {};
template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <PR48656::T1>]}}
struct T2 { static constexpr bool a = false; };
template struct A<T2>;
template <typename T> struct T3 {
static void m(auto) requires requires { T::fail; } {}
// expected-note@-1 {{constraints not satisfied}}
// expected-note@-2 {{type 'int' cannot be used prior to '::'}}
};
template <typename... Args> void t3(Args... args) { (..., T3<int>::m(args)); }
// expected-error@-1 {{no matching function for call to 'm'}}
template void t3<int>(int); // expected-note {{requested here}}
} // namespace PR48656