1 | // RUN: %check_clang_tidy -std=c++20 %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing |
2 | |
3 | // NOLINTBEGIN |
4 | namespace std { |
5 | template <bool B, class T = void> struct enable_if { }; |
6 | |
7 | template <class T> struct enable_if<true, T> { typedef T type; }; |
8 | |
9 | template <bool B, class T = void> |
10 | using enable_if_t = typename enable_if<B, T>::type; |
11 | |
12 | } // namespace std |
13 | // NOLINTEND |
14 | |
15 | template <typename...> |
16 | struct ConsumeVariadic; |
17 | |
18 | struct Obj { |
19 | }; |
20 | |
21 | namespace enable_if_in_return_type { |
22 | |
23 | //////////////////////////////// |
24 | // Section 1: enable_if in return type of function |
25 | //////////////////////////////// |
26 | |
27 | //////////////////////////////// |
28 | // General tests |
29 | //////////////////////////////// |
30 | |
31 | template <typename T> |
32 | typename std::enable_if<T::some_value, Obj>::type basic() { |
33 | return Obj{}; |
34 | } |
35 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
36 | // CHECK-FIXES: {{^}}Obj basic() requires T::some_value {{{$}} |
37 | |
38 | template <typename T> |
39 | std::enable_if_t<T::some_value, Obj> basic_t() { |
40 | return Obj{}; |
41 | } |
42 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
43 | // CHECK-FIXES: {{^}}Obj basic_t() requires T::some_value {{{$}} |
44 | |
45 | template <typename T> |
46 | auto basic_trailing() -> typename std::enable_if<T::some_value, Obj>::type { |
47 | return Obj{}; |
48 | } |
49 | // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
50 | // CHECK-FIXES: {{^}}auto basic_trailing() -> Obj requires T::some_value {{{$}} |
51 | |
52 | template <typename T> |
53 | typename std::enable_if<T::some_value, Obj>::type existing_constraint() requires (T::another_value) { |
54 | return Obj{}; |
55 | } |
56 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
57 | // CHECK-FIXES: {{^}}typename std::enable_if<T::some_value, Obj>::type existing_constraint() requires (T::another_value) {{{$}} |
58 | |
59 | template <typename U> |
60 | typename std::enable_if<U::some_value, Obj>::type decl_without_def(); |
61 | |
62 | template <typename U> |
63 | typename std::enable_if<U::some_value, Obj>::type decl_with_separate_def(); |
64 | |
65 | template <typename U> |
66 | typename std::enable_if<U::some_value, Obj>::type decl_with_separate_def() { |
67 | return Obj{}; |
68 | } |
69 | // FIXME - Support definitions with separate decls |
70 | |
71 | template <typename U> |
72 | std::enable_if_t<true, Obj> no_dependent_type(U) { |
73 | return Obj{}; |
74 | } |
75 | // FIXME - Support non-dependent enable_ifs. Low priority though... |
76 | |
77 | template <typename T> |
78 | typename std::enable_if<T::some_value, int>::type* pointer_of_enable_if() { |
79 | return nullptr; |
80 | } |
81 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
82 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
83 | // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if() requires T::some_value {{{$}} |
84 | |
85 | template <typename T> |
86 | std::enable_if_t<T::some_value, int>* pointer_of_enable_if_t() { |
87 | return nullptr; |
88 | } |
89 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
90 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
91 | // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if_t() requires T::some_value {{{$}} |
92 | |
93 | template <typename T> |
94 | const std::enable_if_t<T::some_value, int>* const_pointer_of_enable_if_t() { |
95 | return nullptr; |
96 | } |
97 | // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
98 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
99 | // CHECK-FIXES-NEXT: {{^}}const int* const_pointer_of_enable_if_t() requires T::some_value {{{$}} |
100 | |
101 | template <typename T> |
102 | std::enable_if_t<T::some_value, int> const * const_pointer_of_enable_if_t2() { |
103 | return nullptr; |
104 | } |
105 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
106 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
107 | // CHECK-FIXES-NEXT: {{^}}int const * const_pointer_of_enable_if_t2() requires T::some_value {{{$}} |
108 | |
109 | |
110 | template <typename T> |
111 | std::enable_if_t<T::some_value, int>& reference_of_enable_if_t() { |
112 | static int x; return x; |
113 | } |
114 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
115 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
116 | // CHECK-FIXES-NEXT: {{^}}int& reference_of_enable_if_t() requires T::some_value {{{$}} |
117 | |
118 | template <typename T> |
119 | const std::enable_if_t<T::some_value, int>& const_reference_of_enable_if_t() { |
120 | static int x; return x; |
121 | } |
122 | // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
123 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
124 | // CHECK-FIXES-NEXT: {{^}}const int& const_reference_of_enable_if_t() requires T::some_value {{{$}} |
125 | |
126 | template <typename T> |
127 | typename std::enable_if<T::some_value>::type enable_if_default_void() { |
128 | } |
129 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
130 | // CHECK-FIXES: {{^}}void enable_if_default_void() requires T::some_value {{{$}} |
131 | |
132 | template <typename T> |
133 | std::enable_if_t<T::some_value> enable_if_t_default_void() { |
134 | } |
135 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
136 | // CHECK-FIXES: {{^}}void enable_if_t_default_void() requires T::some_value {{{$}} |
137 | |
138 | template <typename T> |
139 | std::enable_if_t<T::some_value>* enable_if_t_default_void_pointer() { |
140 | } |
141 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
142 | // CHECK-FIXES: {{^}}void* enable_if_t_default_void_pointer() requires T::some_value {{{$}} |
143 | |
144 | namespace using_namespace_std { |
145 | |
146 | using namespace std; |
147 | |
148 | template <typename T> |
149 | typename enable_if<T::some_value>::type with_typename() { |
150 | } |
151 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
152 | // CHECK-FIXES: {{^}}void with_typename() requires T::some_value {{{$}} |
153 | |
154 | template <typename T> |
155 | enable_if_t<T::some_value> with_t() { |
156 | } |
157 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
158 | // CHECK-FIXES: {{^}}void with_t() requires T::some_value {{{$}} |
159 | |
160 | template <typename T> |
161 | typename enable_if<T::some_value, int>::type with_typename_and_type() { |
162 | } |
163 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
164 | // CHECK-FIXES: {{^}}int with_typename_and_type() requires T::some_value {{{$}} |
165 | |
166 | template <typename T> |
167 | enable_if_t<T::some_value, int> with_t_and_type() { |
168 | } |
169 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
170 | // CHECK-FIXES: {{^}}int with_t_and_type() requires T::some_value {{{$}} |
171 | |
172 | } // namespace using_namespace_std |
173 | |
174 | |
175 | //////////////////////////////// |
176 | // Negative tests - incorrect uses of enable_if |
177 | //////////////////////////////// |
178 | template <typename U> |
179 | std::enable_if<U::some_value, Obj> not_enable_if() { |
180 | return {}; |
181 | } |
182 | template <typename U> |
183 | typename std::enable_if<U::some_value, Obj>::type123 not_enable_if_wrong_type() { |
184 | return {}; |
185 | } |
186 | template <typename U> |
187 | typename std::enable_if_t<U::some_value, Obj>::type not_enable_if_t() { |
188 | return {}; |
189 | } |
190 | template <typename U> |
191 | typename std::enable_if_t<U::some_value, Obj>::type123 not_enable_if_t_again() { |
192 | return {}; |
193 | } |
194 | template <typename U> |
195 | std::enable_if<U::some_value, int>* not_pointer_of_enable_if() { |
196 | return nullptr; |
197 | } |
198 | template <typename U> |
199 | typename std::enable_if<U::some_value, int>::type123 * not_pointer_of_enable_if_t() { |
200 | return nullptr; |
201 | } |
202 | |
203 | |
204 | namespace primary_expression_tests { |
205 | |
206 | //////////////////////////////// |
207 | // Primary/non-primary expression tests |
208 | //////////////////////////////// |
209 | |
210 | template <typename T> struct Traits; |
211 | |
212 | template <typename T> |
213 | std::enable_if_t<Traits<T>::value> type_trait_value() { |
214 | } |
215 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
216 | // CHECK-FIXES: {{^}}void type_trait_value() requires Traits<T>::value {{{$}} |
217 | |
218 | template <typename T> |
219 | std::enable_if_t<Traits<T>::member()> type_trait_member_call() { |
220 | } |
221 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
222 | // CHECK-FIXES: {{^}}void type_trait_member_call() requires (Traits<T>::member()) {{{$}} |
223 | |
224 | template <typename T> |
225 | std::enable_if_t<!Traits<T>::value> negate() { |
226 | } |
227 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
228 | // CHECK-FIXES: {{^}}void negate() requires (!Traits<T>::value) {{{$}} |
229 | |
230 | template <typename T> |
231 | std::enable_if_t<Traits<T>::value1 && Traits<T>::value2> conjunction() { |
232 | } |
233 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
234 | // CHECK-FIXES: {{^}}void conjunction() requires (Traits<T>::value1 && Traits<T>::value2) {{{$}} |
235 | |
236 | template <typename T> |
237 | std::enable_if_t<Traits<T>::value1 || Traits<T>::value2> disjunction() { |
238 | } |
239 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
240 | // CHECK-FIXES: {{^}}void disjunction() requires (Traits<T>::value1 || Traits<T>::value2) {{{$}} |
241 | |
242 | template <typename T> |
243 | std::enable_if_t<Traits<T>::value1 && !Traits<T>::value2> conjunction_with_negate() { |
244 | } |
245 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
246 | // CHECK-FIXES: {{^}}void conjunction_with_negate() requires (Traits<T>::value1 && !Traits<T>::value2) {{{$}} |
247 | |
248 | template <typename T> |
249 | std::enable_if_t<Traits<T>::value1 == (Traits<T>::value2 + 5)> complex_operators() { |
250 | } |
251 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
252 | // CHECK-FIXES: {{^}}void complex_operators() requires (Traits<T>::value1 == (Traits<T>::value2 + 5)) {{{$}} |
253 | |
254 | } // namespace primary_expression_tests |
255 | |
256 | |
257 | //////////////////////////////// |
258 | // Functions with specifier |
259 | //////////////////////////////// |
260 | |
261 | template <typename T> |
262 | constexpr typename std::enable_if<T::some_value, int>::type constexpr_decl() { |
263 | return 10; |
264 | } |
265 | // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
266 | // CHECK-FIXES: {{^}}constexpr int constexpr_decl() requires T::some_value {{{$}} |
267 | |
268 | template <typename T> |
269 | static inline constexpr typename std::enable_if<T::some_value, int>::type static_inline_constexpr_decl() { |
270 | return 10; |
271 | } |
272 | // CHECK-MESSAGES: :[[@LINE-3]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
273 | // CHECK-FIXES: {{^}}static inline constexpr int static_inline_constexpr_decl() requires T::some_value {{{$}} |
274 | |
275 | template <typename T> |
276 | static |
277 | typename std::enable_if<T::some_value, int>::type |
278 | static_decl() { |
279 | return 10; |
280 | } |
281 | // CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
282 | // CHECK-FIXES: {{^}}static{{$}} |
283 | // CHECK-FIXES-NEXT: {{^}}int{{$}} |
284 | // CHECK-FIXES-NEXT: {{^}}static_decl() requires T::some_value {{{$}} |
285 | |
286 | template <typename T> |
287 | constexpr /* comment */ typename std::enable_if<T::some_value, int>::type () { |
288 | return 10; |
289 | } |
290 | // CHECK-MESSAGES: :[[@LINE-3]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
291 | // CHECK-FIXES: {{^}}constexpr /* comment */ int constexpr_comment_decl() requires T::some_value {{{$}} |
292 | |
293 | |
294 | //////////////////////////////// |
295 | // Class definition tests |
296 | //////////////////////////////// |
297 | |
298 | struct AClass { |
299 | |
300 | template <typename T> |
301 | static typename std::enable_if<T::some_value, Obj>::type static_method() { |
302 | return Obj{}; |
303 | } |
304 | // CHECK-MESSAGES: :[[@LINE-3]]:10: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
305 | // CHECK-FIXES: {{^}} static Obj static_method() requires T::some_value {{{$}} |
306 | |
307 | template <typename T> |
308 | typename std::enable_if<T::some_value, Obj>::type member() { |
309 | return Obj{}; |
310 | } |
311 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
312 | // CHECK-FIXES: {{^}} Obj member() requires T::some_value {{{$}} |
313 | |
314 | template <typename T> |
315 | typename std::enable_if<T::some_value, Obj>::type const_qualifier() const { |
316 | return Obj{}; |
317 | } |
318 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
319 | // CHECK-FIXES: {{^}} Obj const_qualifier() const requires T::some_value {{{$}} |
320 | |
321 | template <typename T> |
322 | typename std::enable_if<T::some_value, Obj>::type rvalue_ref_qualifier() && { |
323 | return Obj{}; |
324 | } |
325 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
326 | // CHECK-FIXES: {{^}} Obj rvalue_ref_qualifier() && requires T::some_value {{{$}} |
327 | |
328 | template <typename T> |
329 | typename std::enable_if<T::some_value, Obj>::type () /* c1 */ && /* c2 */ { |
330 | return Obj{}; |
331 | } |
332 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
333 | // CHECK-FIXES: {{^}} Obj rvalue_ref_qualifier_comment() /* c1 */ && /* c2 */ requires T::some_value {{{$}} |
334 | |
335 | template <typename T> |
336 | std::enable_if_t<T::some_value, AClass&> operator=(T&&) = delete; |
337 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
338 | // CHECK-FIXES: {{^}} AClass& operator=(T&&) requires T::some_value = delete; |
339 | |
340 | template<typename T> |
341 | std::enable_if_t<T::some_value, AClass&> operator=(ConsumeVariadic<T>) noexcept(requires (T t) { t = 4; }) = delete; |
342 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
343 | // CHECK-FIXES: {{^}} AClass& operator=(ConsumeVariadic<T>) noexcept(requires (T t) { t = 4; }) requires T::some_value = delete; |
344 | |
345 | }; |
346 | |
347 | |
348 | //////////////////////////////// |
349 | // Comments and whitespace tests |
350 | //////////////////////////////// |
351 | |
352 | template <typename T> |
353 | typename std::enable_if</* check1 */ T::some_value, Obj>::type () { |
354 | return Obj{}; |
355 | } |
356 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
357 | // CHECK-FIXES: {{^}}Obj leading_comment() requires /* check1 */ T::some_value {{{$}} |
358 | |
359 | template <typename T> |
360 | typename std::enable_if<T::some_value, Obj>::type body_on_next_line() |
361 | { |
362 | return Obj{}; |
363 | } |
364 | // CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
365 | // CHECK-FIXES: {{^}}Obj body_on_next_line(){{$}} |
366 | // CHECK-FIXES-NEXT: {{^}}requires T::some_value {{{$}} |
367 | |
368 | template <typename T> |
369 | typename std::enable_if< /* check1 */ T::some_value, Obj>::type () { |
370 | return Obj{}; |
371 | } |
372 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
373 | // CHECK-FIXES: {{^}}Obj leading_comment_whitespace() requires /* check1 */ T::some_value {{{$}} |
374 | |
375 | template <typename T> |
376 | typename std::enable_if</* check1 */ T::some_value /* check2 */, Obj>::type leading_and_trailing_comment() { |
377 | return Obj{}; |
378 | } |
379 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
380 | // CHECK-FIXES: {{^}}Obj leading_and_trailing_comment() requires /* check1 */ T::some_value /* check2 */ {{{$}} |
381 | |
382 | template <typename T, typename U> |
383 | typename std::enable_if<T::some_value && |
384 | U::another_value, Obj>::type condition_on_two_lines() { |
385 | return Obj{}; |
386 | } |
387 | // CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
388 | // CHECK-FIXES: {{^}}Obj condition_on_two_lines() requires (T::some_value &&{{$}} |
389 | // CHECK-FIXES-NEXT: U::another_value) {{{$}} |
390 | |
391 | template <typename T> |
392 | typename std::enable_if<T::some_value, int> :: type* pointer_of_enable_if_t_with_spaces() { |
393 | } |
394 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
395 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
396 | // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if_t_with_spaces() requires T::some_value {{{$}} |
397 | |
398 | template <typename T> |
399 | typename std::enable_if<T::some_value, int> :: /*c*/ type* () { |
400 | } |
401 | // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
402 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
403 | // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if_t_with_comment() requires T::some_value {{{$}} |
404 | |
405 | template <typename T> |
406 | std::enable_if_t<T::some_value // comment |
407 | > () { |
408 | } |
409 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
410 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
411 | // CHECK-FIXES-NEXT: {{^}}void trailing_slash_slash_comment() requires T::some_value // comment{{$}} |
412 | // CHECK-FIXES-NEXT: {{^}} {{{$}} |
413 | |
414 | } // namespace enable_if_in_return_type |
415 | |
416 | |
417 | namespace enable_if_trailing_non_type_parameter { |
418 | |
419 | //////////////////////////////// |
420 | // Section 2: enable_if as final template non-type parameter |
421 | //////////////////////////////// |
422 | |
423 | template <typename T, typename std::enable_if<T::some_value, int>::type = 0> |
424 | void basic() { |
425 | } |
426 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
427 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
428 | // CHECK-FIXES-NEXT: {{^}}void basic() requires T::some_value {{{$}} |
429 | |
430 | template <typename T, std::enable_if_t<T::some_value, int> = 0> |
431 | void basic_t() { |
432 | } |
433 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
434 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
435 | // CHECK-FIXES-NEXT: {{^}}void basic_t() requires T::some_value {{{$}} |
436 | |
437 | template <typename T, template <typename> class U, class V, std::enable_if_t<T::some_value, int> = 0> |
438 | void basic_many_template_params() { |
439 | } |
440 | // CHECK-MESSAGES: :[[@LINE-3]]:61: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
441 | // CHECK-FIXES: {{^}}template <typename T, template <typename> class U, class V>{{$}} |
442 | // CHECK-FIXES-NEXT: {{^}}void basic_many_template_params() requires T::some_value {{{$}} |
443 | |
444 | template <std::enable_if_t<true, int> = 0> |
445 | void no_dependent_type() { |
446 | } |
447 | // FIXME - Support non-dependent enable_ifs. Low priority though... |
448 | |
449 | struct ABaseClass { |
450 | ABaseClass(); |
451 | ABaseClass(int); |
452 | }; |
453 | |
454 | template <typename T> |
455 | struct AClass : ABaseClass { |
456 | template <std::enable_if_t<T::some_value, int> = 0> |
457 | void no_other_template_params() { |
458 | } |
459 | // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
460 | // CHECK-FIXES: {{^}} {{$}} |
461 | // CHECK-FIXES-NEXT: {{^}} void no_other_template_params() requires T::some_value {{{$}} |
462 | |
463 | template <typename U, std::enable_if_t<U::some_value, int> = 0> |
464 | AClass() {} |
465 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
466 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
467 | // CHECK-FIXES-NEXT: {{^}} AClass() requires U::some_value {}{{$}} |
468 | |
469 | template <typename U, std::enable_if_t<U::some_value, int> = 0> |
470 | AClass(int) : data(0) {} |
471 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
472 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
473 | // CHECK-FIXES-NEXT: {{^}} AClass(int) requires U::some_value : data(0) {}{{$}} |
474 | |
475 | template <typename U, std::enable_if_t<U::some_value, int> = 0> |
476 | AClass(int, int) : AClass(0) {} |
477 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
478 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
479 | // CHECK-FIXES-NEXT: {{^}} AClass(int, int) requires U::some_value : AClass(0) {}{{$}} |
480 | |
481 | template <typename U, std::enable_if_t<U::some_value, int> = 0> |
482 | AClass(int, int, int) : ABaseClass(0) {} |
483 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
484 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
485 | // CHECK-FIXES-NEXT: {{^}} AClass(int, int, int) requires U::some_value : ABaseClass(0) {}{{$}} |
486 | |
487 | template <typename U, std::enable_if_t<U::some_value, int> = 0> |
488 | AClass(int, int, int, int) : data2(), data() {} |
489 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
490 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
491 | // CHECK-FIXES-NEXT: {{^}} AClass(int, int, int, int) requires U::some_value : data2(), data() {}{{$}} |
492 | |
493 | int data; |
494 | int data2; |
495 | }; |
496 | |
497 | template <typename T> |
498 | struct AClass2 : ABaseClass { |
499 | |
500 | template <typename U, std::enable_if_t<U::some_value, int> = 0> |
501 | AClass2() {} |
502 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
503 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
504 | // CHECK-FIXES-NEXT: {{^}} AClass2() requires U::some_value {}{{$}} |
505 | |
506 | template <typename U, std::enable_if_t<U::some_value, int> = 0> |
507 | AClass2(int) : data2(0) {} |
508 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
509 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
510 | // CHECK-FIXES-NEXT: {{^}} AClass2(int) requires U::some_value : data2(0) {}{{$}} |
511 | |
512 | int data = 10; |
513 | int data2; |
514 | int data3; |
515 | }; |
516 | |
517 | template <typename T, std::enable_if_t<T::some_value, T>* = 0> |
518 | void pointer_type() { |
519 | } |
520 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
521 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
522 | // CHECK-FIXES-NEXT: {{^}}void pointer_type() requires T::some_value {{{$}} |
523 | |
524 | template <typename T, |
525 | std::enable_if_t<T::some_value, T>* = nullptr> |
526 | void param_on_newline() { |
527 | } |
528 | // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
529 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
530 | // CHECK-FIXES-NEXT: {{^}}void param_on_newline() requires T::some_value {{{$}} |
531 | |
532 | template <typename T, |
533 | typename U, |
534 | std::enable_if_t< |
535 | ConsumeVariadic<T, |
536 | U>::value, T>* = nullptr> |
537 | void param_split_on_two_lines() { |
538 | } |
539 | // CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
540 | // CHECK-FIXES: {{^}}template <typename T,{{$}} |
541 | // CHECK-FIXES-NEXT: {{^}} typename U>{{$}} |
542 | // CHECK-FIXES-NEXT: {{^}}void param_split_on_two_lines() requires ConsumeVariadic<T,{{$}} |
543 | // CHECK-FIXES-NEXT: {{^}} U>::value {{{$}} |
544 | |
545 | template <typename T, std::enable_if_t<T::some_value // comment |
546 | >* = nullptr> |
547 | void () { |
548 | } |
549 | // CHECK-MESSAGES: :[[@LINE-4]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
550 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
551 | // CHECK-FIXES-NEXT: {{^}}void trailing_slash_slash_comment() requires T::some_value // comment{{$}} |
552 | // CHECK-FIXES-NEXT: {{^}} {{{$}} |
553 | |
554 | template <typename T, std::enable_if_t<T::some_value>* = nullptr, std::enable_if_t<T::another_value>* = nullptr> |
555 | void two_enable_ifs() { |
556 | } |
557 | // CHECK-MESSAGES: :[[@LINE-3]]:67: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
558 | // CHECK-FIXES: {{^}}template <typename T, std::enable_if_t<T::some_value>* = nullptr>{{$}} |
559 | // CHECK-FIXES-NEXT: {{^}}void two_enable_ifs() requires T::another_value {{{$}} |
560 | |
561 | //////////////////////////////// |
562 | // Negative tests |
563 | //////////////////////////////// |
564 | |
565 | template <typename U, std::enable_if_t<U::some_value, int> V = 0> |
566 | void non_type_param_has_name() { |
567 | } |
568 | template <typename U, std::enable_if_t<U::some_value, int>> |
569 | void non_type_param_has_no_default() { |
570 | } |
571 | template <typename U, std::enable_if_t<U::some_value, int> V> |
572 | void non_type_param_has_name_and_no_default() { |
573 | } |
574 | template <typename U, std::enable_if_t<U::some_value, int>...> |
575 | void non_type_variadic() { |
576 | } |
577 | template <typename U, std::enable_if_t<U::some_value, int> = 0, int = 0> |
578 | void non_type_not_last() { |
579 | } |
580 | |
581 | #define TEMPLATE_REQUIRES(U, IF) template <typename U, std::enable_if_t<IF, int> = 0> |
582 | TEMPLATE_REQUIRES(U, U::some_value) |
583 | void macro_entire_enable_if() { |
584 | } |
585 | // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
586 | // CHECK-MESSAGES: :[[@LINE-5]]:56: note: expanded from macro 'TEMPLATE_REQUIRES' |
587 | // CHECK-FIXES: {{^}}TEMPLATE_REQUIRES(U, U::some_value) |
588 | // CHECK-FIXES-NEXT: {{^}}void macro_entire_enable_if() {{{$}} |
589 | |
590 | #define CONDITION U::some_value |
591 | template <typename U, std::enable_if_t<CONDITION, int> = 0> |
592 | void macro_condition() { |
593 | } |
594 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
595 | // CHECK-FIXES: {{^}}template <typename U>{{$}} |
596 | // CHECK-FIXES-NEXT: {{^}}void macro_condition() requires CONDITION {{{$}} |
597 | |
598 | #undef CONDITION |
599 | #define CONDITION !U::some_value |
600 | template <typename U, std::enable_if_t<CONDITION, int> = 0> |
601 | void macro_condition_not_primary() { |
602 | } |
603 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
604 | // CHECK-FIXES: {{^}}template <typename U>{{$}} |
605 | // CHECK-FIXES-NEXT: {{^}}void macro_condition_not_primary() requires (CONDITION) {{{$}} |
606 | |
607 | } // namespace enable_if_trailing_non_type_parameter |
608 | |
609 | |
610 | namespace enable_if_trailing_type_parameter { |
611 | |
612 | //////////////////////////////// |
613 | // Section 3: enable_if as final template nameless defaulted type parameter |
614 | //////////////////////////////// |
615 | |
616 | template <typename T, typename = std::enable_if<T::some_value>::type> |
617 | void basic() { |
618 | } |
619 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
620 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
621 | // CHECK-FIXES-NEXT: {{^}}void basic() requires T::some_value {{{$}} |
622 | |
623 | template <typename T, typename = std::enable_if_t<T::some_value>> |
624 | void basic_t() { |
625 | } |
626 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
627 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
628 | // CHECK-FIXES-NEXT: {{^}}void basic_t() requires T::some_value {{{$}} |
629 | |
630 | template <typename T, template <typename> class U, class V, typename = std::enable_if_t<T::some_value>> |
631 | void basic_many_template_params() { |
632 | } |
633 | // CHECK-MESSAGES: :[[@LINE-3]]:61: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
634 | // CHECK-FIXES: {{^}}template <typename T, template <typename> class U, class V>{{$}} |
635 | // CHECK-FIXES-NEXT: {{^}}void basic_many_template_params() requires T::some_value {{{$}} |
636 | |
637 | struct ABaseClass { |
638 | ABaseClass(); |
639 | ABaseClass(int); |
640 | }; |
641 | |
642 | template <typename T> |
643 | struct AClass : ABaseClass { |
644 | template <typename = std::enable_if_t<T::some_value>> |
645 | void no_other_template_params() { |
646 | } |
647 | // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
648 | // CHECK-FIXES: {{^}} {{$}} |
649 | // CHECK-FIXES-NEXT: {{^}} void no_other_template_params() requires T::some_value {{{$}} |
650 | |
651 | template <typename U, typename = std::enable_if_t<U::some_value>> |
652 | AClass() {} |
653 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
654 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
655 | // CHECK-FIXES-NEXT: {{^}} AClass() requires U::some_value {}{{$}} |
656 | |
657 | template <typename U, typename = std::enable_if_t<U::some_value>> |
658 | AClass(int) : data(0) {} |
659 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
660 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
661 | // CHECK-FIXES-NEXT: {{^}} AClass(int) requires U::some_value : data(0) {}{{$}} |
662 | |
663 | template <typename U, typename = std::enable_if_t<U::some_value>> |
664 | AClass(int, int) : AClass(0) {} |
665 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
666 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
667 | // CHECK-FIXES-NEXT: {{^}} AClass(int, int) requires U::some_value : AClass(0) {}{{$}} |
668 | |
669 | template <typename U, typename = std::enable_if_t<U::some_value>> |
670 | AClass(int, int, int) : ABaseClass(0) {} |
671 | // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
672 | // CHECK-FIXES: {{^}} template <typename U>{{$}} |
673 | // CHECK-FIXES-NEXT: {{^}} AClass(int, int, int) requires U::some_value : ABaseClass(0) {}{{$}} |
674 | |
675 | int data; |
676 | }; |
677 | |
678 | template <typename T, typename = std::enable_if_t<T::some_value>*> |
679 | void pointer_type() { |
680 | } |
681 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
682 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
683 | // CHECK-FIXES-NEXT: {{^}}void pointer_type() requires T::some_value {{{$}} |
684 | |
685 | template <typename T, typename = std::enable_if_t<T::some_value>&> |
686 | void reference_type() { |
687 | } |
688 | // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
689 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
690 | // CHECK-FIXES-NEXT: {{^}}void reference_type() requires T::some_value {{{$}} |
691 | |
692 | template <typename T, |
693 | typename = std::enable_if_t<T::some_value>*> |
694 | void param_on_newline() { |
695 | } |
696 | // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
697 | // CHECK-FIXES: {{^}}template <typename T>{{$}} |
698 | // CHECK-FIXES-NEXT: {{^}}void param_on_newline() requires T::some_value {{{$}} |
699 | |
700 | template <typename T, |
701 | typename U, |
702 | typename = std::enable_if_t< |
703 | ConsumeVariadic<T, |
704 | U>::value>> |
705 | void param_split_on_two_lines() { |
706 | } |
707 | // CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
708 | // CHECK-FIXES: {{^}}template <typename T,{{$}} |
709 | // CHECK-FIXES-NEXT: {{^}} typename U>{{$}} |
710 | // CHECK-FIXES-NEXT: {{^}}void param_split_on_two_lines() requires ConsumeVariadic<T,{{$}} |
711 | // CHECK-FIXES-NEXT: {{^}} U>::value {{{$}} |
712 | |
713 | |
714 | //////////////////////////////// |
715 | // Negative tests |
716 | //////////////////////////////// |
717 | |
718 | template <typename U, typename Named = std::enable_if_t<U::some_value>> |
719 | void param_has_name() { |
720 | } |
721 | |
722 | template <typename U, typename = std::enable_if_t<U::some_value>, typename = int> |
723 | void not_last_param() { |
724 | } |
725 | |
726 | } // namespace enable_if_trailing_type_parameter |
727 | |