| // RUN: %check_clang_tidy -std=c++20 %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing |
| |
| // NOLINTBEGIN |
| namespace std { |
| template <bool B, class T = void> struct enable_if { }; |
| |
| template <class T> struct enable_if<true, T> { typedef T type; }; |
| |
| template <bool B, class T = void> |
| using enable_if_t = typename enable_if<B, T>::type; |
| |
| } // namespace std |
| // NOLINTEND |
| |
| template <typename...> |
| struct ConsumeVariadic; |
| |
| struct Obj { |
| }; |
| |
| namespace enable_if_in_return_type { |
| |
| //////////////////////////////// |
| // Section 1: enable_if in return type of function |
| //////////////////////////////// |
| |
| //////////////////////////////// |
| // General tests |
| //////////////////////////////// |
| |
| template <typename T> |
| typename std::enable_if<T::some_value, Obj>::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 <typename T> |
| std::enable_if_t<T::some_value, Obj> 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 <typename T> |
| auto basic_trailing() -> typename std::enable_if<T::some_value, Obj>::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 T> |
| typename std::enable_if<T::some_value, Obj>::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<T::some_value, Obj>::type existing_constraint() requires (T::another_value) {{{$}} |
| |
| template <typename U> |
| typename std::enable_if<U::some_value, Obj>::type decl_without_def(); |
| |
| template <typename U> |
| typename std::enable_if<U::some_value, Obj>::type decl_with_separate_def(); |
| |
| template <typename U> |
| typename std::enable_if<U::some_value, Obj>::type decl_with_separate_def() { |
| return Obj{}; |
| } |
| // FIXME - Support definitions with separate decls |
| |
| template <typename U> |
| std::enable_if_t<true, Obj> no_dependent_type(U) { |
| return Obj{}; |
| } |
| // FIXME - Support non-dependent enable_ifs. Low priority though... |
| |
| template <typename T> |
| typename std::enable_if<T::some_value, int>::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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if() requires T::some_value {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<T::some_value, int>* 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if_t() requires T::some_value {{{$}} |
| |
| template <typename T> |
| const std::enable_if_t<T::some_value, int>* 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}const int* const_pointer_of_enable_if_t() requires T::some_value {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<T::some_value, int> 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}int const * const_pointer_of_enable_if_t2() requires T::some_value {{{$}} |
| |
| |
| template <typename T> |
| std::enable_if_t<T::some_value, int>& 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}int& reference_of_enable_if_t() requires T::some_value {{{$}} |
| |
| template <typename T> |
| const std::enable_if_t<T::some_value, int>& 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}const int& const_reference_of_enable_if_t() requires T::some_value {{{$}} |
| |
| template <typename T> |
| typename std::enable_if<T::some_value>::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 <typename T> |
| std::enable_if_t<T::some_value> 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 <typename T> |
| std::enable_if_t<T::some_value>* 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 T> |
| typename enable_if<T::some_value>::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 <typename T> |
| enable_if_t<T::some_value> 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 T> |
| typename enable_if<T::some_value, int>::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 <typename T> |
| enable_if_t<T::some_value, int> 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 <typename U> |
| std::enable_if<U::some_value, Obj> not_enable_if() { |
| return {}; |
| } |
| template <typename U> |
| typename std::enable_if<U::some_value, Obj>::type123 not_enable_if_wrong_type() { |
| return {}; |
| } |
| template <typename U> |
| typename std::enable_if_t<U::some_value, Obj>::type not_enable_if_t() { |
| return {}; |
| } |
| template <typename U> |
| typename std::enable_if_t<U::some_value, Obj>::type123 not_enable_if_t_again() { |
| return {}; |
| } |
| template <typename U> |
| std::enable_if<U::some_value, int>* not_pointer_of_enable_if() { |
| return nullptr; |
| } |
| template <typename U> |
| typename std::enable_if<U::some_value, int>::type123 * not_pointer_of_enable_if_t() { |
| return nullptr; |
| } |
| |
| |
| namespace primary_expression_tests { |
| |
| //////////////////////////////// |
| // Primary/non-primary expression tests |
| //////////////////////////////// |
| |
| template <typename T> struct Traits; |
| |
| template <typename T> |
| std::enable_if_t<Traits<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<T>::value {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<Traits<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<T>::member()) {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<!Traits<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<T>::value) {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<Traits<T>::value1 && Traits<T>::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<T>::value1 && Traits<T>::value2) {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<Traits<T>::value1 || Traits<T>::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<T>::value1 || Traits<T>::value2) {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<Traits<T>::value1 && !Traits<T>::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<T>::value1 && !Traits<T>::value2) {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<Traits<T>::value1 == (Traits<T>::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<T>::value1 == (Traits<T>::value2 + 5)) {{{$}} |
| |
| } // namespace primary_expression_tests |
| |
| |
| //////////////////////////////// |
| // Functions with specifier |
| //////////////////////////////// |
| |
| template <typename T> |
| constexpr typename std::enable_if<T::some_value, int>::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 <typename T> |
| static inline constexpr typename std::enable_if<T::some_value, int>::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 <typename T> |
| static |
| typename std::enable_if<T::some_value, int>::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 <typename T> |
| constexpr /* comment */ typename std::enable_if<T::some_value, int>::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 <typename T> |
| static typename std::enable_if<T::some_value, Obj>::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 T> |
| typename std::enable_if<T::some_value, Obj>::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 T> |
| typename std::enable_if<T::some_value, Obj>::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 T> |
| typename std::enable_if<T::some_value, Obj>::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 T> |
| typename std::enable_if<T::some_value, Obj>::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 <typename T> |
| std::enable_if_t<T::some_value, AClass&> 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<typename T> |
| std::enable_if_t<T::some_value, AClass&> operator=(ConsumeVariadic<T>) 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<T>) noexcept(requires (T t) { t = 4; }) requires T::some_value = delete; |
| |
| }; |
| |
| |
| //////////////////////////////// |
| // Comments and whitespace tests |
| //////////////////////////////// |
| |
| template <typename T> |
| typename std::enable_if</* check1 */ T::some_value, Obj>::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 T> |
| typename std::enable_if<T::some_value, Obj>::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 T> |
| 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 T> |
| typename std::enable_if</* check1 */ T::some_value /* check2 */, Obj>::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 T, typename U> |
| typename std::enable_if<T::some_value && |
| U::another_value, Obj>::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 T> |
| typename std::enable_if<T::some_value, int> :: 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if_t_with_spaces() requires T::some_value {{{$}} |
| |
| template <typename T> |
| typename std::enable_if<T::some_value, int> :: /*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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}int* pointer_of_enable_if_t_with_comment() requires T::some_value {{{$}} |
| |
| template <typename T> |
| std::enable_if_t<T::some_value // comment |
| > 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 <typename T>{{$}} |
| // 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 <typename T, typename std::enable_if<T::some_value, int>::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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void basic() requires T::some_value {{{$}} |
| |
| template <typename T, std::enable_if_t<T::some_value, int> = 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void basic_t() requires T::some_value {{{$}} |
| |
| template <typename T, template <typename> class U, class V, std::enable_if_t<T::some_value, int> = 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 <typename T, template <typename> class U, class V>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void basic_many_template_params() requires T::some_value {{{$}} |
| |
| template <std::enable_if_t<true, int> = 0> |
| void no_dependent_type() { |
| } |
| // FIXME - Support non-dependent enable_ifs. Low priority though... |
| |
| struct ABaseClass { |
| ABaseClass(); |
| ABaseClass(int); |
| }; |
| |
| template <typename T> |
| struct AClass : ABaseClass { |
| template <std::enable_if_t<T::some_value, int> = 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: {{^}} {{$}} |
| // CHECK-FIXES-NEXT: {{^}} void no_other_template_params() requires T::some_value {{{$}} |
| |
| template <typename U, std::enable_if_t<U::some_value, int> = 0> |
| AClass() {} |
| // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
| // CHECK-FIXES: {{^}} template <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass() requires U::some_value {}{{$}} |
| |
| template <typename U, std::enable_if_t<U::some_value, int> = 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass(int) requires U::some_value : data(0) {}{{$}} |
| |
| template <typename U, std::enable_if_t<U::some_value, int> = 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass(int, int) requires U::some_value : AClass(0) {}{{$}} |
| |
| template <typename U, std::enable_if_t<U::some_value, int> = 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass(int, int, int) requires U::some_value : ABaseClass(0) {}{{$}} |
| |
| template <typename U, std::enable_if_t<U::some_value, int> = 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass(int, int, int, int) requires U::some_value : data2(), data() {}{{$}} |
| |
| int data; |
| int data2; |
| }; |
| |
| template <typename T> |
| struct AClass2 : ABaseClass { |
| |
| template <typename U, std::enable_if_t<U::some_value, int> = 0> |
| AClass2() {} |
| // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
| // CHECK-FIXES: {{^}} template <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass2() requires U::some_value {}{{$}} |
| |
| template <typename U, std::enable_if_t<U::some_value, int> = 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass2(int) requires U::some_value : data2(0) {}{{$}} |
| |
| int data = 10; |
| int data2; |
| int data3; |
| }; |
| |
| template <typename T, std::enable_if_t<T::some_value, T>* = 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void pointer_type() requires T::some_value {{{$}} |
| |
| template <typename T, |
| std::enable_if_t<T::some_value, T>* = 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void param_on_newline() requires T::some_value {{{$}} |
| |
| template <typename T, |
| typename U, |
| std::enable_if_t< |
| ConsumeVariadic<T, |
| U>::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 <typename T,{{$}} |
| // CHECK-FIXES-NEXT: {{^}} typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void param_split_on_two_lines() requires ConsumeVariadic<T,{{$}} |
| // CHECK-FIXES-NEXT: {{^}} U>::value {{{$}} |
| |
| template <typename T, std::enable_if_t<T::some_value // comment |
| >* = 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void trailing_slash_slash_comment() requires T::some_value // comment{{$}} |
| // CHECK-FIXES-NEXT: {{^}} {{{$}} |
| |
| template <typename T, std::enable_if_t<T::some_value>* = nullptr, std::enable_if_t<T::another_value>* = 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 <typename T, std::enable_if_t<T::some_value>* = nullptr>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void two_enable_ifs() requires T::another_value {{{$}} |
| |
| //////////////////////////////// |
| // Negative tests |
| //////////////////////////////// |
| |
| template <typename U, std::enable_if_t<U::some_value, int> V = 0> |
| void non_type_param_has_name() { |
| } |
| template <typename U, std::enable_if_t<U::some_value, int>> |
| void non_type_param_has_no_default() { |
| } |
| template <typename U, std::enable_if_t<U::some_value, int> V> |
| void non_type_param_has_name_and_no_default() { |
| } |
| template <typename U, std::enable_if_t<U::some_value, int>...> |
| void non_type_variadic() { |
| } |
| template <typename U, std::enable_if_t<U::some_value, int> = 0, int = 0> |
| void non_type_not_last() { |
| } |
| |
| #define TEMPLATE_REQUIRES(U, IF) template <typename U, std::enable_if_t<IF, int> = 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 <typename U, std::enable_if_t<CONDITION, int> = 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void macro_condition() requires CONDITION {{{$}} |
| |
| #undef CONDITION |
| #define CONDITION !U::some_value |
| template <typename U, std::enable_if_t<CONDITION, int> = 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 <typename U>{{$}} |
| // 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 <typename T, typename = std::enable_if<T::some_value>::type> |
| void basic() { |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
| // CHECK-FIXES: {{^}}template <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void basic() requires T::some_value {{{$}} |
| |
| template <typename T, typename = std::enable_if_t<T::some_value>> |
| void basic_t() { |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
| // CHECK-FIXES: {{^}}template <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void basic_t() requires T::some_value {{{$}} |
| |
| template <typename T, template <typename> class U, class V, typename = std::enable_if_t<T::some_value>> |
| 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 <typename T, template <typename> class U, class V>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void basic_many_template_params() requires T::some_value {{{$}} |
| |
| struct ABaseClass { |
| ABaseClass(); |
| ABaseClass(int); |
| }; |
| |
| template <typename T> |
| struct AClass : ABaseClass { |
| template <typename = std::enable_if_t<T::some_value>> |
| 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: {{^}} {{$}} |
| // CHECK-FIXES-NEXT: {{^}} void no_other_template_params() requires T::some_value {{{$}} |
| |
| template <typename U, typename = std::enable_if_t<U::some_value>> |
| AClass() {} |
| // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
| // CHECK-FIXES: {{^}} template <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass() requires U::some_value {}{{$}} |
| |
| template <typename U, typename = std::enable_if_t<U::some_value>> |
| 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass(int) requires U::some_value : data(0) {}{{$}} |
| |
| template <typename U, typename = std::enable_if_t<U::some_value>> |
| 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass(int, int) requires U::some_value : AClass(0) {}{{$}} |
| |
| template <typename U, typename = std::enable_if_t<U::some_value>> |
| 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 <typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}} AClass(int, int, int) requires U::some_value : ABaseClass(0) {}{{$}} |
| |
| int data; |
| }; |
| |
| template <typename T, typename = std::enable_if_t<T::some_value>*> |
| void pointer_type() { |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
| // CHECK-FIXES: {{^}}template <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void pointer_type() requires T::some_value {{{$}} |
| |
| template <typename T, typename = std::enable_if_t<T::some_value>&> |
| void reference_type() { |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:23: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints] |
| // CHECK-FIXES: {{^}}template <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void reference_type() requires T::some_value {{{$}} |
| |
| template <typename T, |
| typename = std::enable_if_t<T::some_value>*> |
| 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 <typename T>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void param_on_newline() requires T::some_value {{{$}} |
| |
| template <typename T, |
| typename U, |
| typename = std::enable_if_t< |
| ConsumeVariadic<T, |
| U>::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 <typename T,{{$}} |
| // CHECK-FIXES-NEXT: {{^}} typename U>{{$}} |
| // CHECK-FIXES-NEXT: {{^}}void param_split_on_two_lines() requires ConsumeVariadic<T,{{$}} |
| // CHECK-FIXES-NEXT: {{^}} U>::value {{{$}} |
| |
| |
| //////////////////////////////// |
| // Negative tests |
| //////////////////////////////// |
| |
| template <typename U, typename Named = std::enable_if_t<U::some_value>> |
| void param_has_name() { |
| } |
| |
| template <typename U, typename = std::enable_if_t<U::some_value>, typename = int> |
| void not_last_param() { |
| } |
| |
| } // namespace enable_if_trailing_type_parameter |
| |
| |
| // Issue fixes: |
| |
| namespace PR91872 { |
| |
| enum expression_template_option { value1, value2 }; |
| |
| template <typename T> struct number_category { |
| static const int value = 0; |
| }; |
| |
| constexpr int number_kind_complex = 1; |
| |
| template <typename T, expression_template_option ExpressionTemplates> |
| struct number { |
| using type = T; |
| }; |
| |
| template <typename T> struct component_type { |
| using type = T; |
| }; |
| |
| template <class T, expression_template_option ExpressionTemplates> |
| inline typename std::enable_if< |
| number_category<T>::value == number_kind_complex, |
| component_type<number<T, ExpressionTemplates>>>::type::type |
| abs(const number<T, ExpressionTemplates> &v) { |
| return {}; |
| } |
| |
| } |