xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp (revision ba3447601c435bb2b24ad9e3c8d146c578f00568)
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>
basic()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>
basic_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>
basic_trailing()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>
existing_constraint()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>
decl_with_separate_def()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>
no_dependent_type(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>
pointer_of_enable_if()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>
pointer_of_enable_if_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>
const_pointer_of_enable_if_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>
const_pointer_of_enable_if_t2()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>
reference_of_enable_if_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>
const_reference_of_enable_if_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>
enable_if_default_void()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>
enable_if_t_default_void()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>
enable_if_t_default_void_pointer()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>
with_typename()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>
with_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>
with_typename_and_type()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>
with_t_and_type()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>
not_enable_if()179 std::enable_if<U::some_value, Obj> not_enable_if() {
180   return {};
181 }
182 template <typename U>
not_enable_if_wrong_type()183 typename std::enable_if<U::some_value, Obj>::type123 not_enable_if_wrong_type() {
184   return {};
185 }
186 template <typename U>
not_enable_if_t()187 typename std::enable_if_t<U::some_value, Obj>::type not_enable_if_t() {
188   return {};
189 }
190 template <typename U>
not_enable_if_t_again()191 typename std::enable_if_t<U::some_value, Obj>::type123 not_enable_if_t_again() {
192   return {};
193 }
194 template <typename U>
not_pointer_of_enable_if()195 std::enable_if<U::some_value, int>* not_pointer_of_enable_if() {
196   return nullptr;
197 }
198 template <typename U>
not_pointer_of_enable_if_t()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>
type_trait_value()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>
type_trait_member_call()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>
negate()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>
conjunction()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>
disjunction()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>
conjunction_with_negate()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>
complex_operators()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>
constexpr_decl()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>
static_inline_constexpr_decl()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
static_decl()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>
constexpr_comment_decl()287 constexpr /* 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 
298 struct AClass {
299 
300   template <typename T>
static_methodenable_if_in_return_type::AClass301   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>
memberenable_if_in_return_type::AClass308   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>
const_qualifierenable_if_in_return_type::AClass315   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>
rvalue_ref_qualifierenable_if_in_return_type::AClass322   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>
rvalue_ref_qualifier_commentenable_if_in_return_type::AClass329   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 
352 template <typename T>
leading_comment()353 typename 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 
359 template <typename T>
body_on_next_line()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>
leading_comment_whitespace()369 typename 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 
375 template <typename T>
leading_and_trailing_comment()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 &&
condition_on_two_lines()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>
pointer_of_enable_if_t_with_spaces()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>
pointer_of_enable_if_t_with_comment()399 typename 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 
405 template <typename T>
406 std::enable_if_t<T::some_value // comment
trailing_slash_slash_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 
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>
basic()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>
basic_t()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>
basic_many_template_params()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>
no_dependent_type()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>
no_other_template_paramsenable_if_trailing_non_type_parameter::AClass457   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>
AClassenable_if_trailing_non_type_parameter::AClass464   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>
AClassenable_if_trailing_non_type_parameter::AClass470   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>
AClassenable_if_trailing_non_type_parameter::AClass476   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>
AClassenable_if_trailing_non_type_parameter::AClass482   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>
AClassenable_if_trailing_non_type_parameter::AClass488   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>
AClass2enable_if_trailing_non_type_parameter::AClass2501   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>
AClass2enable_if_trailing_non_type_parameter::AClass2507   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>
pointer_type()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>
param_on_newline()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>
param_split_on_two_lines()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>
trailing_slash_slash_comment()547 void 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 
554 template <typename T, std::enable_if_t<T::some_value>* = nullptr, std::enable_if_t<T::another_value>* = nullptr>
two_enable_ifs()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>
non_type_param_has_name()566 void non_type_param_has_name() {
567 }
568 template <typename U, std::enable_if_t<U::some_value, int>>
non_type_param_has_no_default()569 void non_type_param_has_no_default() {
570 }
571 template <typename U, std::enable_if_t<U::some_value, int> V>
non_type_param_has_name_and_no_default()572 void non_type_param_has_name_and_no_default() {
573 }
574 template <typename U, std::enable_if_t<U::some_value, int>...>
non_type_variadic()575 void non_type_variadic() {
576 }
577 template <typename U, std::enable_if_t<U::some_value, int> = 0, int = 0>
non_type_not_last()578 void non_type_not_last() {
579 }
580 
581 #define TEMPLATE_REQUIRES(U, IF) template <typename U, std::enable_if_t<IF, int> = 0>
TEMPLATE_REQUIRES(U,U::some_value)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>
macro_condition()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>
macro_condition_not_primary()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>
basic()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>>
basic_t()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>>
basic_many_template_params()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>>
no_other_template_paramsenable_if_trailing_type_parameter::AClass645   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>>
AClassenable_if_trailing_type_parameter::AClass652   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>>
AClassenable_if_trailing_type_parameter::AClass658   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>>
AClassenable_if_trailing_type_parameter::AClass664   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>>
AClassenable_if_trailing_type_parameter::AClass670   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>*>
pointer_type()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>&>
reference_type()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>*>
param_on_newline()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>>
param_split_on_two_lines()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>>
param_has_name()719 void param_has_name() {
720 }
721 
722 template <typename U, typename = std::enable_if_t<U::some_value>, typename = int>
not_last_param()723 void not_last_param() {
724 }
725 
726 } // namespace enable_if_trailing_type_parameter
727 
728 
729 // Issue fixes:
730 
731 namespace PR91872 {
732 
733 enum expression_template_option { value1, value2 };
734 
735 template <typename T> struct number_category {
736   static const int value = 0;
737 };
738 
739 constexpr int number_kind_complex = 1;
740 
741 template <typename T, expression_template_option ExpressionTemplates>
742 struct number {
743   using type = T;
744 };
745 
746 template <typename T> struct component_type {
747   using type = T;
748 };
749 
750 template <class T, expression_template_option ExpressionTemplates>
751 inline typename std::enable_if<
752     number_category<T>::value == number_kind_complex,
753     component_type<number<T, ExpressionTemplates>>>::type::type
abs(const number<T,ExpressionTemplates> & v)754 abs(const number<T, ExpressionTemplates> &v) {
755   return {};
756 }
757 
758 }
759