823 lines · cpp
1// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing2 3// NOLINTBEGIN4namespace 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 std13// NOLINTEND14 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 function25////////////////////////////////26 27////////////////////////////////28// General tests29////////////////////////////////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 decls70 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_std173 174 175////////////////////////////////176// Negative tests - incorrect uses of enable_if177////////////////////////////////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 tests208////////////////////////////////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_tests255 256 257////////////////////////////////258// Functions with specifier259////////////////////////////////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>276static277typename std::enable_if<T::some_value, int>::type278static_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: static283// CHECK-FIXES-NEXT: int284// 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 tests296////////////////////////////////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 tests350////////////////////////////////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 // comment407 > 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 // comment412// CHECK-FIXES-NEXT: {413 414} // namespace enable_if_in_return_type415 416 417namespace enable_if_trailing_non_type_parameter {418 419////////////////////////////////420// Section 2: enable_if as final template non-type parameter421////////////////////////////////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: void no_other_template_params() requires T::some_value {461 462 template <typename U, std::enable_if_t<U::some_value, int> = 0>463 AClass() {}464 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]465 // CHECK-FIXES: template <typename U>466 // CHECK-FIXES-NEXT: AClass() requires U::some_value {}467 468 template <typename U, std::enable_if_t<U::some_value, int> = 0>469 AClass(int) : data(0) {}470 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]471 // CHECK-FIXES: template <typename U>472 // CHECK-FIXES-NEXT: AClass(int) requires U::some_value : data(0) {}473 474 template <typename U, std::enable_if_t<U::some_value, int> = 0>475 AClass(int, int) : AClass(0) {}476 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]477 // CHECK-FIXES: template <typename U>478 // CHECK-FIXES-NEXT: AClass(int, int) requires U::some_value : AClass(0) {}479 480 template <typename U, std::enable_if_t<U::some_value, int> = 0>481 AClass(int, int, int) : ABaseClass(0) {}482 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]483 // CHECK-FIXES: template <typename U>484 // CHECK-FIXES-NEXT: AClass(int, int, int) requires U::some_value : ABaseClass(0) {}485 486 template <typename U, std::enable_if_t<U::some_value, int> = 0>487 AClass(int, int, int, int) : data2(), data() {}488 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]489 // CHECK-FIXES: template <typename U>490 // CHECK-FIXES-NEXT: AClass(int, int, int, int) requires U::some_value : data2(), data() {}491 492 int data;493 int data2;494};495 496template <typename T>497struct AClass2 : ABaseClass {498 499 template <typename U, std::enable_if_t<U::some_value, int> = 0>500 AClass2() {}501 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]502 // CHECK-FIXES: template <typename U>503 // CHECK-FIXES-NEXT: AClass2() requires U::some_value {}504 505 template <typename U, std::enable_if_t<U::some_value, int> = 0>506 AClass2(int) : data2(0) {}507 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]508 // CHECK-FIXES: template <typename U>509 // CHECK-FIXES-NEXT: AClass2(int) requires U::some_value : data2(0) {}510 511 int data = 10;512 int data2;513 int data3;514};515 516template <typename T, std::enable_if_t<T::some_value, T>* = 0>517void pointer_type() {518}519// CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]520// CHECK-FIXES: template <typename T>521// CHECK-FIXES-NEXT: void pointer_type() requires T::some_value {522 523template <typename T,524 std::enable_if_t<T::some_value, T>* = nullptr>525void param_on_newline() {526}527// CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]528// CHECK-FIXES: template <typename T>529// CHECK-FIXES-NEXT: void param_on_newline() requires T::some_value {530 531template <typename T,532 typename U,533 std::enable_if_t<534 ConsumeVariadic<T,535 U>::value, T>* = nullptr>536void param_split_on_two_lines() {537}538// CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]539// CHECK-FIXES: template <typename T,540// CHECK-FIXES-NEXT: typename U>541// CHECK-FIXES-NEXT: void param_split_on_two_lines() requires ConsumeVariadic<T,542// CHECK-FIXES-NEXT: U>::value {543 544template <typename T, std::enable_if_t<T::some_value // comment545 >* = nullptr>546void trailing_slash_slash_comment() {547}548// CHECK-MESSAGES: :[[@LINE-4]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]549// CHECK-FIXES: template <typename T>550// CHECK-FIXES-NEXT: void trailing_slash_slash_comment() requires T::some_value // comment551// CHECK-FIXES-NEXT: {552 553template <typename T, std::enable_if_t<T::some_value>* = nullptr, std::enable_if_t<T::another_value>* = nullptr>554void two_enable_ifs() {555}556// CHECK-MESSAGES: :[[@LINE-3]]:67: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]557// CHECK-FIXES: template <typename T, std::enable_if_t<T::some_value>* = nullptr>558// CHECK-FIXES-NEXT: void two_enable_ifs() requires T::another_value {559 560////////////////////////////////561// Negative tests562////////////////////////////////563 564template <typename U, std::enable_if_t<U::some_value, int> V = 0>565void non_type_param_has_name() {566}567template <typename U, std::enable_if_t<U::some_value, int>>568void non_type_param_has_no_default() {569}570template <typename U, std::enable_if_t<U::some_value, int> V>571void non_type_param_has_name_and_no_default() {572}573template <typename U, std::enable_if_t<U::some_value, int>...>574void non_type_variadic() {575}576template <typename U, std::enable_if_t<U::some_value, int> = 0, int = 0>577void non_type_not_last() {578}579 580#define TEMPLATE_REQUIRES(U, IF) template <typename U, std::enable_if_t<IF, int> = 0>581TEMPLATE_REQUIRES(U, U::some_value)582void macro_entire_enable_if() {583}584// CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]585// CHECK-MESSAGES: :[[@LINE-5]]:56: note: expanded from macro 'TEMPLATE_REQUIRES'586// CHECK-FIXES: TEMPLATE_REQUIRES(U, U::some_value)587// CHECK-FIXES-NEXT: void macro_entire_enable_if() {588 589#define CONDITION U::some_value590template <typename U, std::enable_if_t<CONDITION, int> = 0>591void macro_condition() {592}593// CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]594// CHECK-FIXES: template <typename U>595// CHECK-FIXES-NEXT: void macro_condition() requires CONDITION {596 597#undef CONDITION598#define CONDITION !U::some_value599template <typename U, std::enable_if_t<CONDITION, int> = 0>600void macro_condition_not_primary() {601}602// CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]603// CHECK-FIXES: template <typename U>604// CHECK-FIXES-NEXT: void macro_condition_not_primary() requires (CONDITION) {605 606} // namespace enable_if_trailing_non_type_parameter607 608 609namespace enable_if_trailing_type_parameter {610 611////////////////////////////////612// Section 3: enable_if as final template nameless defaulted type parameter613////////////////////////////////614 615template <typename T, typename = std::enable_if<T::some_value>::type>616void basic() {617}618// CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]619// CHECK-FIXES: template <typename T>620// CHECK-FIXES-NEXT: void basic() requires T::some_value {621 622template <typename T, typename = std::enable_if_t<T::some_value>>623void basic_t() {624}625// CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]626// CHECK-FIXES: template <typename T>627// CHECK-FIXES-NEXT: void basic_t() requires T::some_value {628 629template <typename T, template <typename> class U, class V, typename = std::enable_if_t<T::some_value>>630void basic_many_template_params() {631}632// CHECK-MESSAGES: :[[@LINE-3]]:61: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]633// CHECK-FIXES: template <typename T, template <typename> class U, class V>634// CHECK-FIXES-NEXT: void basic_many_template_params() requires T::some_value {635 636struct ABaseClass {637 ABaseClass();638 ABaseClass(int);639};640 641template <typename T>642struct AClass : ABaseClass {643 template <typename = std::enable_if_t<T::some_value>>644 void no_other_template_params() {645 }646 // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]647 // CHECK-FIXES: void no_other_template_params() requires T::some_value {648 649 template <typename U, typename = std::enable_if_t<U::some_value>>650 AClass() {}651 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]652 // CHECK-FIXES: template <typename U>653 // CHECK-FIXES-NEXT: AClass() requires U::some_value {}654 655 template <typename U, typename = std::enable_if_t<U::some_value>>656 AClass(int) : data(0) {}657 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]658 // CHECK-FIXES: template <typename U>659 // CHECK-FIXES-NEXT: AClass(int) requires U::some_value : data(0) {}660 661 template <typename U, typename = std::enable_if_t<U::some_value>>662 AClass(int, int) : AClass(0) {}663 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]664 // CHECK-FIXES: template <typename U>665 // CHECK-FIXES-NEXT: AClass(int, int) requires U::some_value : AClass(0) {}666 667 template <typename U, typename = std::enable_if_t<U::some_value>>668 AClass(int, int, int) : ABaseClass(0) {}669 // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]670 // CHECK-FIXES: template <typename U>671 // CHECK-FIXES-NEXT: AClass(int, int, int) requires U::some_value : ABaseClass(0) {}672 673 int data;674};675 676template <typename T, typename = std::enable_if_t<T::some_value>*>677void pointer_type() {678}679// CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]680// CHECK-FIXES: template <typename T>681// CHECK-FIXES-NEXT: void pointer_type() requires T::some_value {682 683template <typename T, typename = std::enable_if_t<T::some_value>&>684void reference_type() {685}686// CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]687// CHECK-FIXES: template <typename T>688// CHECK-FIXES-NEXT: void reference_type() requires T::some_value {689 690template <typename T,691 typename = std::enable_if_t<T::some_value>*>692void param_on_newline() {693}694// CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]695// CHECK-FIXES: template <typename T>696// CHECK-FIXES-NEXT: void param_on_newline() requires T::some_value {697 698template <typename T,699 typename U,700 typename = std::enable_if_t<701 ConsumeVariadic<T,702 U>::value>>703void param_split_on_two_lines() {704}705// CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]706// CHECK-FIXES: template <typename T,707// CHECK-FIXES-NEXT: typename U>708// CHECK-FIXES-NEXT: void param_split_on_two_lines() requires ConsumeVariadic<T,709// CHECK-FIXES-NEXT: U>::value {710 711 712////////////////////////////////713// Negative tests714////////////////////////////////715 716template <typename U, typename Named = std::enable_if_t<U::some_value>>717void param_has_name() {718}719 720template <typename U, typename = std::enable_if_t<U::some_value>, typename = int>721void not_last_param() {722}723 724} // namespace enable_if_trailing_type_parameter725 726 727// Issue fixes:728 729namespace PR91872 {730 731enum expression_template_option { value1, value2 };732 733template <typename T> struct number_category {734 static const int value = 0;735};736 737constexpr int number_kind_complex = 1;738 739template <typename T, expression_template_option ExpressionTemplates>740struct number {741 using type = T;742};743 744template <typename T> struct component_type {745 using type = T;746};747 748template <class T, expression_template_option ExpressionTemplates>749inline typename std::enable_if<750 number_category<T>::value == number_kind_complex,751 component_type<number<T, ExpressionTemplates>>>::type::type752abs(const number<T, ExpressionTemplates> &v) {753 return {};754}755 756}757 758template <typename T>759struct some_type_trait {760 static constexpr bool value = true;761};762 763// Fix-its are offered even for a non-standard enable_if.764namespace nonstd {765 766template <bool Condition, typename T = void>767struct enable_if : std::enable_if<Condition, T> {};768 769template <bool Condition, typename T = void>770using enable_if_t = typename enable_if<Condition, T>::type;771 772}773 774template <typename T>775typename nonstd::enable_if<some_type_trait<T>::value, void>::type nonstd_enable_if() {}776// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]777// CHECK-FIXES: void nonstd_enable_if() requires some_type_trait<T>::value {}778 779template <typename T>780nonstd::enable_if_t<some_type_trait<T>::value, void> nonstd_enable_if_t() {}781// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]782// CHECK-FIXES: void nonstd_enable_if_t() requires some_type_trait<T>::value {}783 784template <>785nonstd::enable_if_t<some_type_trait<int>::value, void> nonstd_enable_if_t<int>() {}786// FIXME - Support non-dependent enable_ifs.787 788template <typename T>789typename nonstd::enable_if<some_type_trait<T>::value>::type nonstd_enable_if_one_param() {}790// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]791// CHECK-FIXES: void nonstd_enable_if_one_param() requires some_type_trait<T>::value {}792 793template <typename T>794nonstd::enable_if_t<some_type_trait<T>::value> nonstd_enable_if_t_one_param() {}795// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]796// CHECK-FIXES: void nonstd_enable_if_t_one_param() requires some_type_trait<T>::value {}797 798// No fix-its are offered for an enable_if with a different signature from the standard one.799namespace boost {800 801template <typename Condition, typename T = void>802struct enable_if : std::enable_if<Condition::value, T> {};803 804template <typename Condition, typename T = void>805using enable_if_t = typename enable_if<Condition, T>::type;806 807}808 809template <typename T>810typename boost::enable_if<some_type_trait<T>, void>::type boost_enable_if() {}811 812template <typename T>813boost::enable_if_t<some_type_trait<T>, void> boost_enable_if_t() {}814 815template <>816boost::enable_if_t<some_type_trait<int>, void> boost_enable_if_t<int>() {}817 818template <typename T>819typename boost::enable_if<some_type_trait<T>>::type boost_enable_if_one_param() {}820 821template <typename T>822boost::enable_if_t<some_type_trait<T>> boost_enable_if_t_one_param() {}823