// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing // NOLINTBEGIN namespace std { template struct enable_if { }; template struct enable_if { typedef T type; }; template using enable_if_t = typename enable_if::type; } // namespace std // NOLINTEND template struct ConsumeVariadic; struct Obj { }; namespace enable_if_in_return_type { //////////////////////////////// // Section 1: enable_if in return type of function //////////////////////////////// //////////////////////////////// // General tests //////////////////////////////// template typename std::enable_if::type basic() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj basic() requires T::some_value { template std::enable_if_t basic_t() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj basic_t() requires T::some_value { template auto basic_trailing() -> typename std::enable_if::type { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: auto basic_trailing() -> Obj requires T::some_value { template typename std::enable_if::type existing_constraint() requires (T::another_value) { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: typename std::enable_if::type existing_constraint() requires (T::another_value) { template typename std::enable_if::type decl_without_def(); template typename std::enable_if::type decl_with_separate_def(); template typename std::enable_if::type decl_with_separate_def() { return Obj{}; } // FIXME - Support definitions with separate decls template std::enable_if_t no_dependent_type(U) { return Obj{}; } // FIXME - Support non-dependent enable_ifs. Low priority though... template typename std::enable_if::type* pointer_of_enable_if() { return nullptr; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: int* pointer_of_enable_if() requires T::some_value { template std::enable_if_t* pointer_of_enable_if_t() { return nullptr; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: int* pointer_of_enable_if_t() requires T::some_value { template const std::enable_if_t* const_pointer_of_enable_if_t() { return nullptr; } // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: const int* const_pointer_of_enable_if_t() requires T::some_value { template std::enable_if_t const * const_pointer_of_enable_if_t2() { return nullptr; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: int const * const_pointer_of_enable_if_t2() requires T::some_value { template std::enable_if_t& reference_of_enable_if_t() { static int x; return x; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: int& reference_of_enable_if_t() requires T::some_value { template const std::enable_if_t& const_reference_of_enable_if_t() { static int x; return x; } // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: const int& const_reference_of_enable_if_t() requires T::some_value { template typename std::enable_if::type enable_if_default_void() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void enable_if_default_void() requires T::some_value { template std::enable_if_t enable_if_t_default_void() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void enable_if_t_default_void() requires T::some_value { template std::enable_if_t* enable_if_t_default_void_pointer() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void* enable_if_t_default_void_pointer() requires T::some_value { namespace using_namespace_std { using namespace std; template typename enable_if::type with_typename() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void with_typename() requires T::some_value { template enable_if_t with_t() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void with_t() requires T::some_value { template typename enable_if::type with_typename_and_type() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: int with_typename_and_type() requires T::some_value { template enable_if_t with_t_and_type() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: int with_t_and_type() requires T::some_value { } // namespace using_namespace_std //////////////////////////////// // Negative tests - incorrect uses of enable_if //////////////////////////////// template std::enable_if not_enable_if() { return {}; } template typename std::enable_if::type123 not_enable_if_wrong_type() { return {}; } template typename std::enable_if_t::type not_enable_if_t() { return {}; } template typename std::enable_if_t::type123 not_enable_if_t_again() { return {}; } template std::enable_if* not_pointer_of_enable_if() { return nullptr; } template typename std::enable_if::type123 * not_pointer_of_enable_if_t() { return nullptr; } namespace primary_expression_tests { //////////////////////////////// // Primary/non-primary expression tests //////////////////////////////// template struct Traits; template std::enable_if_t::value> type_trait_value() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void type_trait_value() requires Traits::value { template std::enable_if_t::member()> type_trait_member_call() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void type_trait_member_call() requires (Traits::member()) { template std::enable_if_t::value> negate() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void negate() requires (!Traits::value) { template std::enable_if_t::value1 && Traits::value2> conjunction() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void conjunction() requires (Traits::value1 && Traits::value2) { template std::enable_if_t::value1 || Traits::value2> disjunction() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void disjunction() requires (Traits::value1 || Traits::value2) { template std::enable_if_t::value1 && !Traits::value2> conjunction_with_negate() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void conjunction_with_negate() requires (Traits::value1 && !Traits::value2) { template std::enable_if_t::value1 == (Traits::value2 + 5)> complex_operators() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void complex_operators() requires (Traits::value1 == (Traits::value2 + 5)) { } // namespace primary_expression_tests //////////////////////////////// // Functions with specifier //////////////////////////////// template constexpr typename std::enable_if::type constexpr_decl() { return 10; } // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: constexpr int constexpr_decl() requires T::some_value { template static inline constexpr typename std::enable_if::type static_inline_constexpr_decl() { return 10; } // CHECK-MESSAGES: :[[@LINE-3]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: static inline constexpr int static_inline_constexpr_decl() requires T::some_value { template static typename std::enable_if::type static_decl() { return 10; } // CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: static // CHECK-FIXES-NEXT: int // CHECK-FIXES-NEXT: static_decl() requires T::some_value { template constexpr /* comment */ typename std::enable_if::type constexpr_comment_decl() { return 10; } // CHECK-MESSAGES: :[[@LINE-3]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: constexpr /* comment */ int constexpr_comment_decl() requires T::some_value { //////////////////////////////// // Class definition tests //////////////////////////////// struct AClass { template static typename std::enable_if::type static_method() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:10: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: static Obj static_method() requires T::some_value { template typename std::enable_if::type member() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj member() requires T::some_value { template typename std::enable_if::type const_qualifier() const { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj const_qualifier() const requires T::some_value { template typename std::enable_if::type rvalue_ref_qualifier() && { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj rvalue_ref_qualifier() && requires T::some_value { template typename std::enable_if::type rvalue_ref_qualifier_comment() /* c1 */ && /* c2 */ { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj rvalue_ref_qualifier_comment() /* c1 */ && /* c2 */ requires T::some_value { template std::enable_if_t operator=(T&&) = delete; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: AClass& operator=(T&&) requires T::some_value = delete; template std::enable_if_t operator=(ConsumeVariadic) noexcept(requires (T t) { t = 4; }) = delete; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: AClass& operator=(ConsumeVariadic) noexcept(requires (T t) { t = 4; }) requires T::some_value = delete; }; //////////////////////////////// // Comments and whitespace tests //////////////////////////////// template typename std::enable_if::type leading_comment() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj leading_comment() requires /* check1 */ T::some_value { template typename std::enable_if::type body_on_next_line() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj body_on_next_line() // CHECK-FIXES-NEXT: requires T::some_value { template typename std::enable_if< /* check1 */ T::some_value, Obj>::type leading_comment_whitespace() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj leading_comment_whitespace() requires /* check1 */ T::some_value { template typename std::enable_if::type leading_and_trailing_comment() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj leading_and_trailing_comment() requires /* check1 */ T::some_value /* check2 */ { template typename std::enable_if::type condition_on_two_lines() { return Obj{}; } // CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: Obj condition_on_two_lines() requires (T::some_value && // CHECK-FIXES-NEXT: U::another_value) { template typename std::enable_if :: type* pointer_of_enable_if_t_with_spaces() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: int* pointer_of_enable_if_t_with_spaces() requires T::some_value { template typename std::enable_if :: /*c*/ type* pointer_of_enable_if_t_with_comment() { } // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: int* pointer_of_enable_if_t_with_comment() requires T::some_value { template std::enable_if_t trailing_slash_slash_comment() { } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void trailing_slash_slash_comment() requires T::some_value // comment // CHECK-FIXES-NEXT: { } // namespace enable_if_in_return_type namespace enable_if_trailing_non_type_parameter { //////////////////////////////// // Section 2: enable_if as final template non-type parameter //////////////////////////////// template ::type = 0> void basic() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void basic() requires T::some_value { template = 0> void basic_t() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void basic_t() requires T::some_value { template class U, class V, std::enable_if_t = 0> void basic_many_template_params() { } // CHECK-MESSAGES: :[[@LINE-3]]:61: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template class U, class V> // CHECK-FIXES-NEXT: void basic_many_template_params() requires T::some_value { template = 0> void no_dependent_type() { } // FIXME - Support non-dependent enable_ifs. Low priority though... struct ABaseClass { ABaseClass(); ABaseClass(int); }; template struct AClass : ABaseClass { template = 0> void no_other_template_params() { } // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void no_other_template_params() requires T::some_value { template = 0> AClass() {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass() requires U::some_value {} template = 0> AClass(int) : data(0) {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass(int) requires U::some_value : data(0) {} template = 0> AClass(int, int) : AClass(0) {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass(int, int) requires U::some_value : AClass(0) {} template = 0> AClass(int, int, int) : ABaseClass(0) {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass(int, int, int) requires U::some_value : ABaseClass(0) {} template = 0> AClass(int, int, int, int) : data2(), data() {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass(int, int, int, int) requires U::some_value : data2(), data() {} int data; int data2; }; template struct AClass2 : ABaseClass { template = 0> AClass2() {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass2() requires U::some_value {} template = 0> AClass2(int) : data2(0) {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass2(int) requires U::some_value : data2(0) {} int data = 10; int data2; int data3; }; template * = 0> void pointer_type() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void pointer_type() requires T::some_value { template * = nullptr> void param_on_newline() { } // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void param_on_newline() requires T::some_value { template ::value, T>* = nullptr> void param_split_on_two_lines() { } // CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void param_split_on_two_lines() requires ConsumeVariadic::value { template * = nullptr> void trailing_slash_slash_comment() { } // CHECK-MESSAGES: :[[@LINE-4]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void trailing_slash_slash_comment() requires T::some_value // comment // CHECK-FIXES-NEXT: { template * = nullptr, std::enable_if_t* = nullptr> void two_enable_ifs() { } // CHECK-MESSAGES: :[[@LINE-3]]:67: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template * = nullptr> // CHECK-FIXES-NEXT: void two_enable_ifs() requires T::another_value { //////////////////////////////// // Negative tests //////////////////////////////// template V = 0> void non_type_param_has_name() { } template > void non_type_param_has_no_default() { } template V> void non_type_param_has_name_and_no_default() { } template ...> void non_type_variadic() { } template = 0, int = 0> void non_type_not_last() { } #define TEMPLATE_REQUIRES(U, IF) template = 0> TEMPLATE_REQUIRES(U, U::some_value) void macro_entire_enable_if() { } // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-MESSAGES: :[[@LINE-5]]:56: note: expanded from macro 'TEMPLATE_REQUIRES' // CHECK-FIXES: TEMPLATE_REQUIRES(U, U::some_value) // CHECK-FIXES-NEXT: void macro_entire_enable_if() { #define CONDITION U::some_value template = 0> void macro_condition() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void macro_condition() requires CONDITION { #undef CONDITION #define CONDITION !U::some_value template = 0> void macro_condition_not_primary() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void macro_condition_not_primary() requires (CONDITION) { } // namespace enable_if_trailing_non_type_parameter namespace enable_if_trailing_type_parameter { //////////////////////////////// // Section 3: enable_if as final template nameless defaulted type parameter //////////////////////////////// template ::type> void basic() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void basic() requires T::some_value { template > void basic_t() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void basic_t() requires T::some_value { template class U, class V, typename = std::enable_if_t> void basic_many_template_params() { } // CHECK-MESSAGES: :[[@LINE-3]]:61: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template class U, class V> // CHECK-FIXES-NEXT: void basic_many_template_params() requires T::some_value { struct ABaseClass { ABaseClass(); ABaseClass(int); }; template struct AClass : ABaseClass { template > void no_other_template_params() { } // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void no_other_template_params() requires T::some_value { template > AClass() {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass() requires U::some_value {} template > AClass(int) : data(0) {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass(int) requires U::some_value : data(0) {} template > AClass(int, int) : AClass(0) {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass(int, int) requires U::some_value : AClass(0) {} template > AClass(int, int, int) : ABaseClass(0) {} // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: AClass(int, int, int) requires U::some_value : ABaseClass(0) {} int data; }; template *> void pointer_type() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void pointer_type() requires T::some_value { template &> void reference_type() { } // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void reference_type() requires T::some_value { template *> void param_on_newline() { } // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void param_on_newline() requires T::some_value { template ::value>> void param_split_on_two_lines() { } // CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: template // CHECK-FIXES-NEXT: void param_split_on_two_lines() requires ConsumeVariadic::value { //////////////////////////////// // Negative tests //////////////////////////////// template > void param_has_name() { } template , typename = int> void not_last_param() { } } // namespace enable_if_trailing_type_parameter // Issue fixes: namespace PR91872 { enum expression_template_option { value1, value2 }; template struct number_category { static const int value = 0; }; constexpr int number_kind_complex = 1; template struct number { using type = T; }; template struct component_type { using type = T; }; template inline typename std::enable_if< number_category::value == number_kind_complex, component_type>>::type::type abs(const number &v) { return {}; } } template struct some_type_trait { static constexpr bool value = true; }; // Fix-its are offered even for a non-standard enable_if. namespace nonstd { template struct enable_if : std::enable_if {}; template using enable_if_t = typename enable_if::type; } template typename nonstd::enable_if::value, void>::type nonstd_enable_if() {} // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void nonstd_enable_if() requires some_type_trait::value {} template nonstd::enable_if_t::value, void> nonstd_enable_if_t() {} // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void nonstd_enable_if_t() requires some_type_trait::value {} template <> nonstd::enable_if_t::value, void> nonstd_enable_if_t() {} // FIXME - Support non-dependent enable_ifs. template typename nonstd::enable_if::value>::type nonstd_enable_if_one_param() {} // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void nonstd_enable_if_one_param() requires some_type_trait::value {} template nonstd::enable_if_t::value> nonstd_enable_if_t_one_param() {} // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] // CHECK-FIXES: void nonstd_enable_if_t_one_param() requires some_type_trait::value {} // No fix-its are offered for an enable_if with a different signature from the standard one. namespace boost { template struct enable_if : std::enable_if {}; template using enable_if_t = typename enable_if::type; } template typename boost::enable_if, void>::type boost_enable_if() {} template boost::enable_if_t, void> boost_enable_if_t() {} template <> boost::enable_if_t, void> boost_enable_if_t() {} template typename boost::enable_if>::type boost_enable_if_one_param() {} template boost::enable_if_t> boost_enable_if_t_one_param() {}