1// RUN: %check_clang_tidy -std=c++20 %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing
2
3// NOLINTBEGIN
4namespace std {
5template <bool B, class T = void> struct enable_if { };
6
7template <class T> struct enable_if<true, T> { typedef T type; };
8
9template <bool B, class T = void>
10using enable_if_t = typename enable_if<B, T>::type;
11
12} // namespace std
13// NOLINTEND
14
15template <typename...>
16struct ConsumeVariadic;
17
18struct Obj {
19};
20
21namespace 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
31template <typename T>
32typename 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
38template <typename T>
39std::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
45template <typename T>
46auto 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
52template <typename T>
53typename 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
59template <typename U>
60typename std::enable_if<U::some_value, Obj>::type decl_without_def();
61
62template <typename U>
63typename std::enable_if<U::some_value, Obj>::type decl_with_separate_def();
64
65template <typename U>
66typename std::enable_if<U::some_value, Obj>::type decl_with_separate_def() {
67 return Obj{};
68}
69// FIXME - Support definitions with separate decls
70
71template <typename U>
72std::enable_if_t<true, Obj> no_dependent_type(U) {
73 return Obj{};
74}
75// FIXME - Support non-dependent enable_ifs. Low priority though...
76
77template <typename T>
78typename 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
85template <typename T>
86std::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
93template <typename T>
94const 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
101template <typename T>
102std::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
110template <typename T>
111std::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
118template <typename T>
119const 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
126template <typename T>
127typename 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
132template <typename T>
133std::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
138template <typename T>
139std::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
144namespace using_namespace_std {
145
146using namespace std;
147
148template <typename T>
149typename 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
154template <typename T>
155enable_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
160template <typename T>
161typename 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
166template <typename T>
167enable_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////////////////////////////////
178template <typename U>
179std::enable_if<U::some_value, Obj> not_enable_if() {
180 return {};
181}
182template <typename U>
183typename std::enable_if<U::some_value, Obj>::type123 not_enable_if_wrong_type() {
184 return {};
185}
186template <typename U>
187typename std::enable_if_t<U::some_value, Obj>::type not_enable_if_t() {
188 return {};
189}
190template <typename U>
191typename std::enable_if_t<U::some_value, Obj>::type123 not_enable_if_t_again() {
192 return {};
193}
194template <typename U>
195std::enable_if<U::some_value, int>* not_pointer_of_enable_if() {
196 return nullptr;
197}
198template <typename U>
199typename std::enable_if<U::some_value, int>::type123 * not_pointer_of_enable_if_t() {
200 return nullptr;
201}
202
203
204namespace primary_expression_tests {
205
206////////////////////////////////
207// Primary/non-primary expression tests
208////////////////////////////////
209
210template <typename T> struct Traits;
211
212template <typename T>
213std::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
218template <typename T>
219std::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
224template <typename T>
225std::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
230template <typename T>
231std::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
236template <typename T>
237std::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
242template <typename T>
243std::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
248template <typename T>
249std::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
261template <typename T>
262constexpr 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
268template <typename T>
269static 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
275template <typename T>
276static
277typename std::enable_if<T::some_value, int>::type
278static_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
286template <typename T>
287constexpr /* comment */ typename std::enable_if<T::some_value, int>::type constexpr_comment_decl() {
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
298struct 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 rvalue_ref_qualifier_comment() /* 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
352template <typename T>
353typename std::enable_if</* check1 */ T::some_value, Obj>::type leading_comment() {
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
359template <typename T>
360typename 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
368template <typename T>
369typename std::enable_if< /* check1 */ T::some_value, Obj>::type leading_comment_whitespace() {
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
375template <typename T>
376typename 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
382template <typename T, typename U>
383typename 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
391template <typename T>
392typename 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
398template <typename T>
399typename std::enable_if<T::some_value, int> :: /*c*/ type* pointer_of_enable_if_t_with_comment() {
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
405template <typename T>
406std::enable_if_t<T::some_value // comment
407 > trailing_slash_slash_comment() {
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
417namespace enable_if_trailing_non_type_parameter {
418
419////////////////////////////////
420// Section 2: enable_if as final template non-type parameter
421////////////////////////////////
422
423template <typename T, typename std::enable_if<T::some_value, int>::type = 0>
424void 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
430template <typename T, std::enable_if_t<T::some_value, int> = 0>
431void 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
437template <typename T, template <typename> class U, class V, std::enable_if_t<T::some_value, int> = 0>
438void 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
444template <std::enable_if_t<true, int> = 0>
445void no_dependent_type() {
446}
447// FIXME - Support non-dependent enable_ifs. Low priority though...
448
449struct ABaseClass {
450 ABaseClass();
451 ABaseClass(int);
452};
453
454template <typename T>
455struct 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
497template <typename T>
498struct 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
517template <typename T, std::enable_if_t<T::some_value, T>* = 0>
518void 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
524template <typename T,
525 std::enable_if_t<T::some_value, T>* = nullptr>
526void 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
532template <typename T,
533 typename U,
534 std::enable_if_t<
535 ConsumeVariadic<T,
536 U>::value, T>* = nullptr>
537void 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
545template <typename T, std::enable_if_t<T::some_value // comment
546 >* = nullptr>
547void trailing_slash_slash_comment() {
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
554template <typename T, std::enable_if_t<T::some_value>* = nullptr, std::enable_if_t<T::another_value>* = nullptr>
555void 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
565template <typename U, std::enable_if_t<U::some_value, int> V = 0>
566void non_type_param_has_name() {
567}
568template <typename U, std::enable_if_t<U::some_value, int>>
569void non_type_param_has_no_default() {
570}
571template <typename U, std::enable_if_t<U::some_value, int> V>
572void non_type_param_has_name_and_no_default() {
573}
574template <typename U, std::enable_if_t<U::some_value, int>...>
575void non_type_variadic() {
576}
577template <typename U, std::enable_if_t<U::some_value, int> = 0, int = 0>
578void non_type_not_last() {
579}
580
581#define TEMPLATE_REQUIRES(U, IF) template <typename U, std::enable_if_t<IF, int> = 0>
582TEMPLATE_REQUIRES(U, U::some_value)
583void 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
591template <typename U, std::enable_if_t<CONDITION, int> = 0>
592void 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
600template <typename U, std::enable_if_t<CONDITION, int> = 0>
601void 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
610namespace enable_if_trailing_type_parameter {
611
612////////////////////////////////
613// Section 3: enable_if as final template nameless defaulted type parameter
614////////////////////////////////
615
616template <typename T, typename = std::enable_if<T::some_value>::type>
617void 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
623template <typename T, typename = std::enable_if_t<T::some_value>>
624void 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
630template <typename T, template <typename> class U, class V, typename = std::enable_if_t<T::some_value>>
631void 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
637struct ABaseClass {
638 ABaseClass();
639 ABaseClass(int);
640};
641
642template <typename T>
643struct 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
678template <typename T, typename = std::enable_if_t<T::some_value>*>
679void 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
685template <typename T, typename = std::enable_if_t<T::some_value>&>
686void 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
692template <typename T,
693 typename = std::enable_if_t<T::some_value>*>
694void 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
700template <typename T,
701 typename U,
702 typename = std::enable_if_t<
703 ConsumeVariadic<T,
704 U>::value>>
705void 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
718template <typename U, typename Named = std::enable_if_t<U::some_value>>
719void param_has_name() {
720}
721
722template <typename U, typename = std::enable_if_t<U::some_value>, typename = int>
723void not_last_param() {
724}
725
726} // namespace enable_if_trailing_type_parameter
727

source code of clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp