Skip to content

Commit 5b5a8cd

Browse files
authored
[clang-tidy] Fix modernize-use-constraints crash on uses of nonstandard enable_ifs (#152938)
Fixes #152868. See that issue for details. Fixes #123726.
1 parent d9a192c commit 5b5a8cd

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "UseConstraintsCheck.h"
1010
#include "clang/AST/ASTContext.h"
11+
#include "clang/AST/DeclTemplate.h"
1112
#include "clang/ASTMatchers/ASTMatchFinder.h"
1213
#include "clang/Lex/Lexer.h"
1314

@@ -80,6 +81,13 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) {
8081
if (!TD || TD->getName() != "enable_if")
8182
return std::nullopt;
8283

84+
assert(!TD->getTemplateParameters()->empty() &&
85+
"found template with no template parameters?");
86+
const auto *FirstParam = dyn_cast<NonTypeTemplateParmDecl>(
87+
TD->getTemplateParameters()->getParam(0));
88+
if (!FirstParam || !FirstParam->getType()->isBooleanType())
89+
return std::nullopt;
90+
8391
int NumArgs = SpecializationLoc.getNumArgs();
8492
if (NumArgs != 1 && NumArgs != 2)
8593
return std::nullopt;
@@ -107,6 +115,13 @@ matchEnableIfSpecializationImplTrait(TypeLoc TheType) {
107115
if (!Specialization->isTypeAlias())
108116
return std::nullopt;
109117

118+
assert(!TD->getTemplateParameters()->empty() &&
119+
"found template with no template parameters?");
120+
const auto *FirstParam = dyn_cast<NonTypeTemplateParmDecl>(
121+
TD->getTemplateParameters()->getParam(0));
122+
if (!FirstParam || !FirstParam->getType()->isBooleanType())
123+
return std::nullopt;
124+
110125
if (const auto *AliasedType =
111126
dyn_cast<DependentNameType>(Specialization->getAliasedType())) {
112127
ElaboratedTypeKeyword Keyword = AliasedType->getKeyword();

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ Changes in existing checks
188188
- Improved :doc:`misc-header-include-cycle
189189
<clang-tidy/checks/misc/header-include-cycle>` check performance.
190190

191+
- Improved :doc:`modernize-use-constraints
192+
<clang-tidy/checks/modernize/use-constraints>` check by fixing a crash on
193+
uses of non-standard ``enable_if`` with a signature different from
194+
``std::enable_if`` (such as ``boost::enable_if``).
195+
191196
- Improved :doc:`modernize-use-designated-initializers
192197
<clang-tidy/checks/modernize/use-designated-initializers>` check to
193198
suggest using designated initializers for aliased aggregate types.

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

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %check_clang_tidy -std=c++20 %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing
1+
// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-constraints %t -- -- -fno-delayed-template-parsing
22

33
// NOLINTBEGIN
44
namespace std {
@@ -756,3 +756,69 @@ abs(const number<T, ExpressionTemplates> &v) {
756756
}
757757

758758
}
759+
760+
template <typename T>
761+
struct some_type_trait {
762+
static constexpr bool value = true;
763+
};
764+
765+
// Fix-its are offered even for a non-standard enable_if.
766+
namespace nonstd {
767+
768+
template <bool Condition, typename T = void>
769+
struct enable_if : std::enable_if<Condition, T> {};
770+
771+
template <bool Condition, typename T = void>
772+
using enable_if_t = typename enable_if<Condition, T>::type;
773+
774+
}
775+
776+
template <typename T>
777+
typename nonstd::enable_if<some_type_trait<T>::value, void>::type nonstd_enable_if() {}
778+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
779+
// CHECK-FIXES: {{^}}void nonstd_enable_if() requires some_type_trait<T>::value {}{{$}}
780+
781+
template <typename T>
782+
nonstd::enable_if_t<some_type_trait<T>::value, void> nonstd_enable_if_t() {}
783+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
784+
// CHECK-FIXES: {{^}}void nonstd_enable_if_t() requires some_type_trait<T>::value {}{{$}}
785+
786+
template <>
787+
nonstd::enable_if_t<some_type_trait<int>::value, void> nonstd_enable_if_t<int>() {}
788+
// FIXME - Support non-dependent enable_ifs.
789+
790+
template <typename T>
791+
typename nonstd::enable_if<some_type_trait<T>::value>::type nonstd_enable_if_one_param() {}
792+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
793+
// CHECK-FIXES: {{^}}void nonstd_enable_if_one_param() requires some_type_trait<T>::value {}{{$}}
794+
795+
template <typename T>
796+
nonstd::enable_if_t<some_type_trait<T>::value> nonstd_enable_if_t_one_param() {}
797+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use C++20 requires constraints instead of enable_if [modernize-use-constraints]
798+
// CHECK-FIXES: {{^}}void nonstd_enable_if_t_one_param() requires some_type_trait<T>::value {}{{$}}
799+
800+
// No fix-its are offered for an enable_if with a different signature from the standard one.
801+
namespace boost {
802+
803+
template <typename Condition, typename T = void>
804+
struct enable_if : std::enable_if<Condition::value, T> {};
805+
806+
template <typename Condition, typename T = void>
807+
using enable_if_t = typename enable_if<Condition, T>::type;
808+
809+
}
810+
811+
template <typename T>
812+
typename boost::enable_if<some_type_trait<T>, void>::type boost_enable_if() {}
813+
814+
template <typename T>
815+
boost::enable_if_t<some_type_trait<T>, void> boost_enable_if_t() {}
816+
817+
template <>
818+
boost::enable_if_t<some_type_trait<int>, void> boost_enable_if_t<int>() {}
819+
820+
template <typename T>
821+
typename boost::enable_if<some_type_trait<T>>::type boost_enable_if_one_param() {}
822+
823+
template <typename T>
824+
boost::enable_if_t<some_type_trait<T>> boost_enable_if_t_one_param() {}

0 commit comments

Comments
 (0)