Skip to content

Commit 57b22de

Browse files
authored
merge main into amd-staging (llvm#3929)
2 parents 99b26cf + a8b01da commit 57b22de

File tree

65 files changed

+1568
-1072
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1568
-1072
lines changed

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

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,53 @@ AST_MATCHER(clang::ParmVarDecl, isArgvOfMain) {
3939
return FD ? FD->isMain() : false;
4040
}
4141

42+
template <typename TargetType, typename NodeType>
43+
const TargetType *getAs(const NodeType *Node) {
44+
if constexpr (std::is_same_v<NodeType, clang::DynTypedNode>)
45+
return Node->template get<TargetType>();
46+
else
47+
return llvm::dyn_cast<TargetType>(Node);
48+
}
49+
50+
AST_MATCHER(clang::TypeLoc, isWithinImplicitTemplateInstantiation) {
51+
const auto IsImplicitTemplateInstantiation = [](const auto *Node) {
52+
const auto IsImplicitInstantiation = [](const auto *Node) {
53+
return (Node != nullptr) && (Node->getTemplateSpecializationKind() ==
54+
TSK_ImplicitInstantiation);
55+
};
56+
return (IsImplicitInstantiation(getAs<clang::CXXRecordDecl>(Node)) ||
57+
IsImplicitInstantiation(getAs<clang::FunctionDecl>(Node)) ||
58+
IsImplicitInstantiation(getAs<clang::VarDecl>(Node)));
59+
};
60+
61+
DynTypedNodeList ParentNodes = Finder->getASTContext().getParents(Node);
62+
const clang::NamedDecl *ParentDecl = nullptr;
63+
while (!ParentNodes.empty()) {
64+
const DynTypedNode &ParentNode = ParentNodes[0];
65+
if (IsImplicitTemplateInstantiation(&ParentNode))
66+
return true;
67+
68+
// in case of a `NamedDecl` as parent node, it is more efficient to proceed
69+
// with the upward traversal via DeclContexts (see below) instead of via
70+
// parent nodes
71+
if ((ParentDecl = ParentNode.template get<clang::NamedDecl>()))
72+
break;
73+
74+
ParentNodes = Finder->getASTContext().getParents(ParentNode);
75+
}
76+
77+
if (ParentDecl != nullptr) {
78+
const clang::DeclContext *DeclContext = ParentDecl->getDeclContext();
79+
while (DeclContext != nullptr) {
80+
if (IsImplicitTemplateInstantiation(DeclContext))
81+
return true;
82+
DeclContext = DeclContext->getParent();
83+
}
84+
}
85+
86+
return false;
87+
}
88+
4289
} // namespace
4390

4491
AvoidCArraysCheck::AvoidCArraysCheck(StringRef Name, ClangTidyContext *Context)
@@ -66,22 +113,38 @@ void AvoidCArraysCheck::registerMatchers(MatchFinder *Finder) {
66113
hasParent(varDecl(isExternC())),
67114
hasParent(fieldDecl(
68115
hasParent(recordDecl(isExternCContext())))),
69-
hasAncestor(functionDecl(isExternC())))),
116+
hasAncestor(functionDecl(isExternC())),
117+
isWithinImplicitTemplateInstantiation())),
70118
IgnoreStringArrayIfNeededMatcher)
71119
.bind("typeloc"),
72120
this);
121+
122+
Finder->addMatcher(
123+
templateArgumentLoc(hasTypeLoc(
124+
typeLoc(hasType(arrayType())).bind("template_arg_array_typeloc"))),
125+
this);
73126
}
74127

75128
void AvoidCArraysCheck::check(const MatchFinder::MatchResult &Result) {
76-
const auto *ArrayType = Result.Nodes.getNodeAs<TypeLoc>("typeloc");
129+
TypeLoc ArrayTypeLoc{};
130+
131+
if (const auto *MatchedTypeLoc = Result.Nodes.getNodeAs<TypeLoc>("typeloc"))
132+
ArrayTypeLoc = *MatchedTypeLoc;
133+
134+
if (const auto *TemplateArgArrayTypeLoc =
135+
Result.Nodes.getNodeAs<TypeLoc>("template_arg_array_typeloc"))
136+
ArrayTypeLoc = *TemplateArgArrayTypeLoc;
137+
138+
assert(!ArrayTypeLoc.isNull());
139+
77140
const bool IsInParam =
78141
Result.Nodes.getNodeAs<ParmVarDecl>("param_decl") != nullptr;
79-
const bool IsVLA = ArrayType->getTypePtr()->isVariableArrayType();
142+
const bool IsVLA = ArrayTypeLoc.getTypePtr()->isVariableArrayType();
80143
enum class RecommendType { Array, Vector, Span };
81144
llvm::SmallVector<const char *> RecommendTypes{};
82145
if (IsVLA) {
83146
RecommendTypes.push_back("'std::vector'");
84-
} else if (ArrayType->getTypePtr()->isIncompleteArrayType() && IsInParam) {
147+
} else if (ArrayTypeLoc.getTypePtr()->isIncompleteArrayType() && IsInParam) {
85148
// in function parameter, we also don't know the size of
86149
// IncompleteArrayType.
87150
if (Result.Context->getLangOpts().CPlusPlus20)
@@ -93,9 +156,11 @@ void AvoidCArraysCheck::check(const MatchFinder::MatchResult &Result) {
93156
} else {
94157
RecommendTypes.push_back("'std::array'");
95158
}
96-
diag(ArrayType->getBeginLoc(),
159+
160+
diag(ArrayTypeLoc.getBeginLoc(),
97161
"do not declare %select{C-style|C VLA}0 arrays, use %1 instead")
98-
<< IsVLA << llvm::join(RecommendTypes, " or ");
162+
<< IsVLA << llvm::join(RecommendTypes, " or ")
163+
<< ArrayTypeLoc.getSourceRange();
99164
}
100165

101166
} // namespace clang::tidy::modernize

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ Changes in existing checks
218218
- Improved :doc:`misc-header-include-cycle
219219
<clang-tidy/checks/misc/header-include-cycle>` check performance.
220220

221+
- Improved :doc:`modernize-avoid-c-arrays
222+
<clang-tidy/checks/modernize/avoid-c-arrays>` to not diagnose array types
223+
which are part of an implicit instantiation of a template.
224+
221225
- Improved :doc:`modernize-use-constraints
222226
<clang-tidy/checks/modernize/use-constraints>` check by fixing a crash on
223227
uses of non-standard ``enable_if`` with a signature different from

clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-ignores-strings.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,15 @@ const char array[] = {'n', 'a', 'm', 'e', '\0'};
77

88
void takeCharArray(const char name[]);
99
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use 'std::array' or 'std::vector' instead [modernize-avoid-c-arrays]
10+
11+
template <typename T = const char[10], typename U = char[10], char[10]>
12+
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
13+
// CHECK-MESSAGES: :[[@LINE-2]]:53: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
14+
// CHECK-MESSAGES: :[[@LINE-3]]:63: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
15+
void func() {}
16+
17+
template <typename T = const char[], typename U = char[], char[]>
18+
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
19+
// CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
20+
// CHECK-MESSAGES: :[[@LINE-3]]:59: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
21+
void fun() {}

clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays.cpp

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,14 @@ array<int[4], 2> d;
3232
using k = int[4];
3333
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not declare C-style arrays, use 'std::array' instead
3434

35+
k ak;
36+
// no diagnostic expected here since no concrete C-style array type is written here
37+
3538
array<k, 2> dk;
39+
// no diagnostic expected here since no concrete C-style array type is written here
40+
41+
array<decltype(ak), 3> ek;
42+
// no diagnostic expected here since no concrete C-style array type is written here
3643

3744
template <typename T>
3845
class unique_ptr {
@@ -92,3 +99,188 @@ const char name[] = "Some string";
9299

93100
void takeCharArray(const char name[]);
94101
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use 'std::array' or 'std::vector' instead [modernize-avoid-c-arrays]
102+
103+
namespace std {
104+
template<class T, class U>
105+
struct is_same { constexpr static bool value{false}; };
106+
107+
template<class T>
108+
struct is_same<T, T> { constexpr static bool value{true}; };
109+
110+
template<class T, class U>
111+
constexpr bool is_same_v = is_same<T, U>::value;
112+
113+
template<class T> struct remove_const { typedef T type; };
114+
template<class T> struct remove_const<const T> { typedef T type; };
115+
116+
template<class T>
117+
using remove_const_t = typename remove_const<T>::type;
118+
119+
template<bool B, class T = void> struct enable_if {};
120+
template<class T> struct enable_if<true, T> { typedef T type; };
121+
122+
template< bool B, class T = void >
123+
using enable_if_t = typename enable_if<B, T>::type;
124+
}
125+
126+
// within below template decl, no array type findings are expected within the template parameter declarations since not a single C-style array type got written explicitly
127+
template <typename T,
128+
bool = std::is_same_v<T, int>,
129+
bool = std::is_same<T, int>::value,
130+
bool = std::is_same_v<std::remove_const_t<T>, int>,
131+
bool = std::is_same<std::remove_const_t<T>, int>::value,
132+
bool = std::is_same_v<typename std::remove_const<T>::type, int>,
133+
bool = std::is_same<typename std::remove_const<T>::type, int>::value,
134+
std::enable_if_t<not(std::is_same_v<std::remove_const_t<T>, int>) && not(std::is_same_v<typename std::remove_const<T>::type, char>), bool> = true,
135+
typename std::enable_if<not(std::is_same_v<std::remove_const_t<T>, int>) && not(std::is_same_v<typename std::remove_const<T>::type, char>), bool>::type = true,
136+
typename = std::enable_if_t<not(std::is_same_v<std::remove_const_t<T>, int>) && not(std::is_same_v<typename std::remove_const<T>::type, char>)>,
137+
typename = typename std::remove_const<T>::type,
138+
typename = std::remove_const_t<T>>
139+
class MyClassTemplate {
140+
public:
141+
// here, however, plenty of array type findings are expected for below template parameter declarations since C-style array types are written explicitly
142+
template <typename U = T,
143+
bool = std::is_same_v<U, int[]>,
144+
// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
145+
bool = std::is_same<U, int[10]>::value,
146+
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
147+
std::enable_if_t<not(std::is_same_v<std::remove_const_t<U>, int[]>) && not(std::is_same_v<typename std::remove_const<U>::type, char[10]>), bool> = true,
148+
// CHECK-MESSAGES: :[[@LINE-1]]:73: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
149+
// CHECK-MESSAGES: :[[@LINE-2]]:140: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
150+
typename = typename std::remove_const<int[10]>::type,
151+
// CHECK-MESSAGES: :[[@LINE-1]]:51: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
152+
typename = std::remove_const_t<int[]>>
153+
// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
154+
class MyInnerClassTemplate {
155+
public:
156+
MyInnerClassTemplate(const U&) {}
157+
private:
158+
U field[3];
159+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
160+
};
161+
162+
MyClassTemplate(const T&) {}
163+
164+
private:
165+
T field[7];
166+
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
167+
};
168+
169+
// an explicit instantiation
170+
template
171+
class MyClassTemplate<int[2]>;
172+
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
173+
174+
using MyArrayType = int[3];
175+
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
176+
177+
// another explicit instantiation
178+
template
179+
class MyClassTemplate<MyArrayType>;
180+
// no diagnostic is expected here since no C-style array type got written here
181+
182+
// within below template decl, no array type findings are expected within the template parameter declarations since not a single C-style array type got written explicitly
183+
template <typename T,
184+
bool = std::is_same_v<T, int>,
185+
bool = std::is_same<T, int>::value,
186+
bool = std::is_same_v<std::remove_const_t<T>, int>,
187+
bool = std::is_same<std::remove_const_t<T>, int>::value,
188+
bool = std::is_same_v<typename std::remove_const<T>::type, int>,
189+
bool = std::is_same<typename std::remove_const<T>::type, int>::value,
190+
std::enable_if_t<not(std::is_same_v<std::remove_const_t<T>, int>) && not(std::is_same_v<typename std::remove_const<T>::type, char>), bool> = true,
191+
typename std::enable_if<not(std::is_same_v<std::remove_const_t<T>, int>) && not(std::is_same_v<typename std::remove_const<T>::type, char>), bool>::type = true,
192+
typename = std::enable_if_t<not(std::is_same_v<std::remove_const_t<T>, int>) && not(std::is_same_v<typename std::remove_const<T>::type, char>)>,
193+
typename = typename std::remove_const<T>::type,
194+
typename = std::remove_const_t<T>>
195+
void func(const T& param) {
196+
int array1[1];
197+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
198+
199+
T array2[2];
200+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
201+
202+
T value;
203+
}
204+
205+
// here, however, plenty of array type findings are expected for below template parameter declarations since C-style array types are written explicitly
206+
template <typename T = int[],
207+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
208+
bool = std::is_same_v<T, int[]>,
209+
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
210+
bool = std::is_same<T, int[10]>::value,
211+
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
212+
std::enable_if_t<not(std::is_same_v<std::remove_const_t<T>, int[]>) && not(std::is_same_v<typename std::remove_const<T>::type, char[10]>), bool> = true,
213+
// CHECK-MESSAGES: :[[@LINE-1]]:71: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
214+
// CHECK-MESSAGES: :[[@LINE-2]]:138: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
215+
typename = typename std::remove_const<int[10]>::type,
216+
// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
217+
typename = std::remove_const_t<int[]>>
218+
// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
219+
void fun(const T& param) {
220+
int array3[3];
221+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
222+
223+
T array4[4];
224+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
225+
226+
T value;
227+
}
228+
229+
template<typename T>
230+
T some_constant{};
231+
232+
// explicit instantiations
233+
template
234+
int some_constant<int[5]>[5];
235+
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
236+
237+
template
238+
int some_constant<decltype(ak)>[4];
239+
// no diagnostic is expected here since explicit instantiations aren't represented as `TypeLoc` in the AST and we hence cannot match them as such
240+
241+
MyArrayType mk;
242+
// no diagnostic is expected here since no C-style array type got written here
243+
244+
// explicit specializations
245+
template<>
246+
int some_constant<int[7]>[7]{};
247+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
248+
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
249+
250+
template<>
251+
int some_constant<decltype(mk)>[3]{};
252+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
253+
254+
void testArrayInTemplateType() {
255+
int t[10];
256+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
257+
258+
func(t);
259+
fun(t);
260+
261+
func<decltype(t)>({});
262+
fun<decltype(t)>({});
263+
264+
func<int[1]>({});
265+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
266+
fun<int[1]>({});
267+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
268+
269+
MyClassTemplate var{t};
270+
MyClassTemplate<decltype(t)> var1{{}};
271+
MyClassTemplate<int[2]> var2{{}};
272+
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
273+
274+
decltype(var1)::MyInnerClassTemplate var3{t};
275+
decltype(var1)::MyInnerClassTemplate<decltype(t)> var4{{}};
276+
decltype(var1)::MyInnerClassTemplate<char[5]> var5{{}};
277+
// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
278+
279+
MyClassTemplate<decltype(t)>::MyInnerClassTemplate var6{t};
280+
MyClassTemplate<decltype(t)>::MyInnerClassTemplate<decltype(t)> var7{{}};
281+
MyClassTemplate<decltype(t)>::MyInnerClassTemplate<char[8]> var8{{}};
282+
// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
283+
MyClassTemplate<int[9]>::MyInnerClassTemplate<char[9]> var9{{}};
284+
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
285+
// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
286+
}

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,8 @@ Bug Fixes to C++ Support
593593
unknown bound during constant evaluation. (#GH151716)
594594
- Support the dynamic_cast to final class optimization with pointer
595595
authentication enabled. (#GH152601)
596+
- Fix the check for narrowing int-to-float conversions, so that they are detected in
597+
cases where converting the float back to an integer is undefined behaviour (#GH157067).
596598

597599
Bug Fixes to AST Handling
598600
^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)