xref: /llvm-project/clang/test/SemaTemplate/concepts-out-of-line-def.cpp (revision fbd8f8985e36581487371e9ff4ac7d99655b51e7)
1 // RUN: %clang_cc1 -std=c++20 -verify %s
2 // expected-no-diagnostics
3 
4 static constexpr int PRIMARY = 0;
5 static constexpr int SPECIALIZATION_CONCEPT = 1;
6 static constexpr int SPECIALIZATION_REQUIRES = 2;
7 
8 template <class T>
9 concept Concept = (sizeof(T) >= 2 * sizeof(int));
10 
11 struct XY {
12   int x;
13   int y;
14 };
15 
16 namespace members {
17 
18 template <class T, class U> struct S {
19   static constexpr int primary();
20 };
21 
22 template <class T, class U> constexpr int S<T, U>::primary() {
23   return PRIMARY;
24 };
25 
26 template <Concept C, class U> struct S<C, U> {
27   static constexpr int specialization();
28 };
29 
30 template <class T, class U>
31   requires(sizeof(T) == sizeof(int))
32 struct S<T, U> {
33   static constexpr int specialization();
34 };
35 
36 template <Concept C, class U> constexpr int S<C, U>::specialization() {
37   return SPECIALIZATION_CONCEPT;
38 }
39 
40 template <class T, class U>
41   requires(sizeof(T) == sizeof(int))
42 constexpr int S<T, U>::specialization() {
43   return SPECIALIZATION_REQUIRES;
44 }
45 
46 static_assert(S<char, double>::primary() == PRIMARY);
47 static_assert(S<XY, double>::specialization() == SPECIALIZATION_CONCEPT);
48 static_assert(S<int, double>::specialization() == SPECIALIZATION_REQUIRES);
49 
50 } // namespace members
51 
52 namespace enumerations {
53 
54 template <class T, class U> struct S {
55   enum class E : int;
56 };
57 
58 template <class T, class U> enum class S<T, U>::E { Value = PRIMARY };
59 
60 template <Concept C, class U> struct S<C, U> {
61   enum class E : int;
62 };
63 
64 template <Concept C, class U>
65 enum class S<C, U>::E {
66   Value = SPECIALIZATION_CONCEPT
67 };
68 
69 template <class T, class U>
70   requires(sizeof(T) == sizeof(int))
71 struct S<T, U> {
72   enum class E : int;
73 };
74 
75 template <class T, class U>
76   requires(sizeof(T) == sizeof(int))
77 enum class S<T, U>::E {
78   Value = SPECIALIZATION_REQUIRES
79 };
80 
81 static_assert(static_cast<int>(S<char, double>::E::Value) == PRIMARY);
82 static_assert(static_cast<int>(S<XY, double>::E::Value) ==
83               SPECIALIZATION_CONCEPT);
84 static_assert(static_cast<int>(S<int, double>::E::Value) ==
85               SPECIALIZATION_REQUIRES);
86 
87 } // namespace  enumerations
88 
89 namespace multiple_template_parameter_lists {
90 
91 template <class Outer>
92 struct S {
93   template <class Inner>
94   static constexpr int primary(Inner);
95 };
96 
97 template <class Outer>
98 template <class Inner>
99 constexpr int S<Outer>::primary(Inner) {
100   return PRIMARY;
101 };
102 
103 template <Concept Outer>
104 struct S<Outer> {
105   template <class Inner>
106   static constexpr int specialization(Inner);
107 };
108 
109 template <Concept Outer>
110 template <class Inner>
111 constexpr int S<Outer>::specialization(Inner) { return SPECIALIZATION_CONCEPT; }
112 
113 template <class Outer>
114   requires(sizeof(Outer) == sizeof(int))
115 struct S<Outer> {
116   template <class Inner>
117   static constexpr int specialization(Inner);
118 };
119 
120 template <class Outer>
121   requires(sizeof(Outer) == sizeof(int))
122 template <class Inner>
123 constexpr int S<Outer>::specialization(Inner) { return SPECIALIZATION_REQUIRES; }
124 
125 static_assert(S<char>::primary("str") == PRIMARY);
126 static_assert(S<XY>::specialization("str") == SPECIALIZATION_CONCEPT);
127 static_assert(S<int>::specialization("str") == SPECIALIZATION_REQUIRES);
128 
129 } // namespace multiple_template_parameter_lists
130 
131 static constexpr int CONSTRAINED_METHOD_1 = 1;
132 static constexpr int CONSTRAINED_METHOD_2 = 2;
133 
134 namespace constrained_members {
135 
136 template <int>
137 struct S {
138   template <Concept C>
139   static constexpr int constrained_method();
140 };
141 
142 template <>
143 template <Concept C>
144 constexpr int S<1>::constrained_method() { return CONSTRAINED_METHOD_1; }
145 
146 template <>
147 template <Concept C>
148 constexpr int S<2>::constrained_method() { return CONSTRAINED_METHOD_2; }
149 
150 static_assert(S<1>::constrained_method<XY>() == CONSTRAINED_METHOD_1);
151 static_assert(S<2>::constrained_method<XY>() == CONSTRAINED_METHOD_2);
152 
153 
154 template <class T1, class T2>
155 concept ConceptT1T2 = true;
156 
157 template<typename T3>
158 struct S12 {
159   template<ConceptT1T2<T3> T4>
160   static constexpr int constrained_method();
161 };
162 
163 template<>
164 template<ConceptT1T2<int> T5>
165 constexpr int S12<int>::constrained_method() { return CONSTRAINED_METHOD_1; }
166 
167 template<>
168 template<ConceptT1T2<double> T5>
169 constexpr int S12<double>::constrained_method() { return CONSTRAINED_METHOD_2; }
170 
171 static_assert(S12<int>::constrained_method<XY>() == CONSTRAINED_METHOD_1);
172 static_assert(S12<double>::constrained_method<XY>() == CONSTRAINED_METHOD_2);
173 
174 } // namespace constrained members
175 
176 namespace constrained_members_of_nested_types {
177 
178 template <int>
179 struct S {
180   struct Inner0 {
181     struct Inner1 {
182       template <Concept C>
183       static constexpr int constrained_method();
184     };
185   };
186 };
187 
188 template <>
189 template <Concept C>
190 constexpr int S<1>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; }
191 
192 template <>
193 template <Concept C>
194 constexpr int S<2>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; }
195 
196 static_assert(S<1>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1);
197 static_assert(S<2>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2);
198 
199 
200 template <class T1, class T2>
201 concept ConceptT1T2 = true;
202 
203 template<typename T3>
204 struct S12 {
205   struct Inner0 {
206     struct Inner1 {
207       template<ConceptT1T2<T3> T4>
208       static constexpr int constrained_method();
209     };
210   };
211 };
212 
213 template<>
214 template<ConceptT1T2<int> T5>
215 constexpr int S12<int>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; }
216 
217 template<>
218 template<ConceptT1T2<double> T5>
219 constexpr int S12<double>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; }
220 
221 static_assert(S12<int>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1);
222 static_assert(S12<double>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2);
223 
224 } // namespace constrained_members_of_nested_types
225 
226 namespace constrained_member_sfinae {
227 
228 template<int N> struct S {
229   template<class T>
230   static constexpr int constrained_method() requires (sizeof(int[N * 1073741824 + 4]) == 16) {
231     return CONSTRAINED_METHOD_1;
232   }
233 
234   template<class T>
235   static constexpr int constrained_method() requires (sizeof(int[N]) == 16);
236 };
237 
238 template<>
239 template<typename T>
240 constexpr int S<4>::constrained_method() requires (sizeof(int[4]) == 16) {
241   return CONSTRAINED_METHOD_2;
242 }
243 
244 // Verify that there is no amiguity in this case.
245 static_assert(S<4>::constrained_method<double>() == CONSTRAINED_METHOD_2);
246 
247 } // namespace constrained_member_sfinae
248 
249 namespace requires_expression_references_members {
250 
251 void accept1(int x);
252 void accept2(XY xy);
253 
254 template <class T> struct S {
255   T Field = T();
256 
257   constexpr int constrained_method()
258       requires requires { accept1(Field); };
259 
260   constexpr int constrained_method()
261       requires requires { accept2(Field); };
262 };
263 
264 template <class T>
265 constexpr int S<T>::constrained_method()
266   requires requires { accept1(Field); } {
267   return CONSTRAINED_METHOD_1;
268 }
269 
270 template <class T>
271 constexpr int S<T>::constrained_method()
272   requires requires { accept2(Field); } {
273   return CONSTRAINED_METHOD_2;
274 }
275 
276 static_assert(S<int>().constrained_method() == CONSTRAINED_METHOD_1);
277 static_assert(S<XY>().constrained_method() == CONSTRAINED_METHOD_2);
278 
279 } // namespace requires_expression_references_members
280 
281 namespace GH60231 {
282 
283 template<typename T0> concept C = true;
284 
285 template <typename T1>
286 struct S {
287   template <typename F1> requires C<S<T1>>
288   void foo1(F1 f);
289 
290   template <typename F2>
291   void foo2(F2 f) requires C<S<T1>>;
292 
293   template <typename F3> requires C<F3>
294   void foo3(F3 f);
295 };
296 
297 template <typename T2>
298 template <typename F4> requires C<S<T2>>
299 void S<T2>::foo1(F4 f) {}
300 
301 template <typename T3>
302 template <typename F5>
303 void S<T3>::foo2(F5 f) requires C<S<T3>> {}
304 
305 template <typename T4>
306 template <typename F6> requires C<F6>
307 void S<T4>::foo3(F6 f) {}
308 
309 } // namespace GH60231
310 
311 namespace GH62003 {
312 
313 template <typename T0> concept Concept = true;
314 
315 template <class T1>
316 struct S1 {
317   template <Concept C1>
318   static constexpr int foo();
319 };
320 template <class T2>
321 template <Concept C2>
322 constexpr int S1<T2>::foo() { return 1; }
323 
324 template <Concept C3>
325 struct S2 {
326   template <class T3>
327   static constexpr int foo();
328 };
329 template <Concept C4>
330 template <class T4>
331 constexpr int S2<C4>::foo() { return 2; }
332 
333 template <Concept C5>
334 struct S3 {
335   template <Concept C6>
336   static constexpr int foo();
337 };
338 template <Concept C7>
339 template <Concept C8>
340 constexpr int S3<C7>::foo() { return 3; }
341 
342 static_assert(S1<int>::foo<int>() == 1);
343 static_assert(S2<int>::foo<int>() == 2);
344 static_assert(S3<int>::foo<int>() == 3);
345 
346 } // namespace GH62003
347 
348 namespace MultilevelTemplateWithPartialSpecialization {
349 template <typename>
350 concept Concept = true;
351 
352 namespace two_level {
353 template <typename T1, int>
354 struct W0 {
355   template <typename T2>
356   requires (Concept<T2>)
357   void f(const T2 &);
358 };
359 
360 template <typename T3>
361 struct W0<T3, 0> {
362   template <typename T4>
363   requires (Concept<T4>)
364   void f(const T4 &);
365 };
366 
367 template <typename T3>
368 template <typename T4>
369 requires (Concept<T4>)
370 inline void W0<T3, 0>::f(const T4 &) {}
371 } // namespace two_level
372 
373 namespace three_level {
374 template <typename T1, int>
375 struct W0 {
376   template <typename T2>
377   struct W1 {
378     template <typename T3>
379     requires (Concept<T3>)
380     void f(const T3 &);
381   };
382 };
383 
384 template <typename T4>
385 struct W0<T4, 0> {
386   template <typename T5>
387   struct W1 {
388     template <typename T6>
389     requires (Concept<T6>)
390     void f(const T6 &);
391   };
392 };
393 
394 template <typename T7>
395 template <typename T8>
396 template <typename T9>
397 requires (Concept<T9>)
398 inline void W0<T7, 0>::W1<T8>::f(const T9 &) {}
399 } // namespace three_level
400 
401 } // namespace MultilevelTemplateWithPartialSpecialization
402 
403 namespace PR62697 {
404 template<typename>
405 concept c = true;
406 
407 template<typename T>
408 struct s {
409     void f() requires c<void(T)>;
410 };
411 
412 template<typename T>
413 void s<T>::f() requires c<void(T)> { }
414 }
415