189a1d03eSRichard // RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t
289a1d03eSRichard
389a1d03eSRichard typedef __SIZE_TYPE__ size_t;
489a1d03eSRichard
589a1d03eSRichard namespace std {
689a1d03eSRichard template<typename T, size_t N>
789a1d03eSRichard struct array {
889a1d03eSRichard T& operator[](size_t n);
989a1d03eSRichard T& at(size_t n);
1089a1d03eSRichard };
1189a1d03eSRichard }
1289a1d03eSRichard
1389a1d03eSRichard
1489a1d03eSRichard namespace gsl {
1589a1d03eSRichard template<class T, size_t N>
1689a1d03eSRichard T& at( T(&a)[N], size_t index );
1789a1d03eSRichard
1889a1d03eSRichard template<class T, size_t N>
1989a1d03eSRichard T& at( std::array<T, N> &a, size_t index );
2089a1d03eSRichard }
2189a1d03eSRichard
const_index(int base)2289a1d03eSRichard constexpr int const_index(int base) {
2389a1d03eSRichard return base + 3;
2489a1d03eSRichard }
2589a1d03eSRichard
26*41818ce1SJorge Pinto Sousa template<class T, size_t N>
27*41818ce1SJorge Pinto Sousa class DerivedArray : public std::array<T, N> {};
28*41818ce1SJorge Pinto Sousa
f(std::array<int,10> a,int pos)2989a1d03eSRichard void f(std::array<int, 10> a, int pos) {
3089a1d03eSRichard a [ pos / 2 /*comment*/] = 1;
3189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
3289a1d03eSRichard int j = a[pos - 1];
3389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression
3489a1d03eSRichard
3589a1d03eSRichard a.at(pos-1) = 2; // OK, at() instead of []
3689a1d03eSRichard gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
3789a1d03eSRichard
3889a1d03eSRichard a[-1] = 3;
3989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
4089a1d03eSRichard a[10] = 4;
4189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
4289a1d03eSRichard
4389a1d03eSRichard a[const_index(7)] = 3;
4489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
4589a1d03eSRichard
4689a1d03eSRichard a[0] = 3; // OK, constant index and inside bounds
4789a1d03eSRichard a[1] = 3; // OK, constant index and inside bounds
4889a1d03eSRichard a[9] = 3; // OK, constant index and inside bounds
4989a1d03eSRichard a[const_index(6)] = 3; // OK, constant index and inside bounds
50ce2d44b0SJorge Pinto Sousa
51ce2d44b0SJorge Pinto Sousa using MyArray = std::array<int, 10>;
52ce2d44b0SJorge Pinto Sousa MyArray m{};
53ce2d44b0SJorge Pinto Sousa m [ pos / 2 /*comment*/] = 1;
54ce2d44b0SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
55ce2d44b0SJorge Pinto Sousa int jj = m[pos - 1];
56ce2d44b0SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use array subscript when the index is not an integer constant expression
57ce2d44b0SJorge Pinto Sousa
58ce2d44b0SJorge Pinto Sousa m.at(pos-1) = 2; // OK, at() instead of []
59ce2d44b0SJorge Pinto Sousa gsl::at(m, pos-1) = 2; // OK, gsl::at() instead of []
60ce2d44b0SJorge Pinto Sousa m[-1] = 3;
61ce2d44b0SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
62ce2d44b0SJorge Pinto Sousa m[10] = 4;
63ce2d44b0SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
64ce2d44b0SJorge Pinto Sousa
65ce2d44b0SJorge Pinto Sousa m[const_index(7)] = 3;
66ce2d44b0SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
67ce2d44b0SJorge Pinto Sousa
68ce2d44b0SJorge Pinto Sousa m[0] = 3; // OK, constant index and inside bounds
69ce2d44b0SJorge Pinto Sousa m[1] = 3; // OK, constant index and inside bounds
70ce2d44b0SJorge Pinto Sousa m[9] = 3; // OK, constant index and inside bounds
71ce2d44b0SJorge Pinto Sousa m[const_index(6)] = 3; // OK, constant index and inside bounds
7289a1d03eSRichard }
7389a1d03eSRichard
74*41818ce1SJorge Pinto Sousa template<class T, size_t N>
75*41818ce1SJorge Pinto Sousa class PrivateDerivedArray : std::array<T, N> {
76*41818ce1SJorge Pinto Sousa public:
operator [](size_t n)77*41818ce1SJorge Pinto Sousa T& operator[](size_t n){
78*41818ce1SJorge Pinto Sousa return std::array<T, N>::operator[](static_cast<int>(n));
79*41818ce1SJorge Pinto Sousa };
at(size_t n)80*41818ce1SJorge Pinto Sousa T& at(size_t n) {
81*41818ce1SJorge Pinto Sousa return std::array<T, N>::at(static_cast<int>(n));
82*41818ce1SJorge Pinto Sousa };
83*41818ce1SJorge Pinto Sousa };
84*41818ce1SJorge Pinto Sousa
f_derived(DerivedArray<int,10> a,int pos)85*41818ce1SJorge Pinto Sousa void f_derived(DerivedArray<int, 10> a, int pos) {
86*41818ce1SJorge Pinto Sousa a [ pos / 2 /*comment*/] = 1;
87*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
88*41818ce1SJorge Pinto Sousa int j = a[pos - 1];
89*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression
90*41818ce1SJorge Pinto Sousa
91*41818ce1SJorge Pinto Sousa a.at(pos-1) = 2; // OK, at() instead of []
92*41818ce1SJorge Pinto Sousa gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
93*41818ce1SJorge Pinto Sousa
94*41818ce1SJorge Pinto Sousa a[-1] = 3;
95*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
96*41818ce1SJorge Pinto Sousa a[10] = 4;
97*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
98*41818ce1SJorge Pinto Sousa
99*41818ce1SJorge Pinto Sousa a[const_index(7)] = 3;
100*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
101*41818ce1SJorge Pinto Sousa
102*41818ce1SJorge Pinto Sousa a[0] = 3; // OK, constant index and inside bounds
103*41818ce1SJorge Pinto Sousa a[1] = 3; // OK, constant index and inside bounds
104*41818ce1SJorge Pinto Sousa a[9] = 3; // OK, constant index and inside bounds
105*41818ce1SJorge Pinto Sousa a[const_index(6)] = 3; // OK, constant index and inside bounds
106*41818ce1SJorge Pinto Sousa
107*41818ce1SJorge Pinto Sousa using MyArray = DerivedArray<int, 10>;
108*41818ce1SJorge Pinto Sousa MyArray m{};
109*41818ce1SJorge Pinto Sousa m [ pos / 2 /*comment*/] = 1;
110*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
111*41818ce1SJorge Pinto Sousa int jj = m[pos - 1];
112*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use array subscript when the index is not an integer constant expression
113*41818ce1SJorge Pinto Sousa
114*41818ce1SJorge Pinto Sousa m.at(pos-1) = 2; // OK, at() instead of []
115*41818ce1SJorge Pinto Sousa gsl::at(m, pos-1) = 2; // OK, gsl::at() instead of []
116*41818ce1SJorge Pinto Sousa m[-1] = 3;
117*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
118*41818ce1SJorge Pinto Sousa m[10] = 4;
119*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
120*41818ce1SJorge Pinto Sousa
121*41818ce1SJorge Pinto Sousa m[const_index(7)] = 3;
122*41818ce1SJorge Pinto Sousa // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
123*41818ce1SJorge Pinto Sousa
124*41818ce1SJorge Pinto Sousa m[0] = 3; // OK, constant index and inside bounds
125*41818ce1SJorge Pinto Sousa m[1] = 3; // OK, constant index and inside bounds
126*41818ce1SJorge Pinto Sousa m[9] = 3; // OK, constant index and inside bounds
127*41818ce1SJorge Pinto Sousa m[const_index(6)] = 3; // OK, constant index and inside bounds
128*41818ce1SJorge Pinto Sousa
129*41818ce1SJorge Pinto Sousa using MyPrivateArray = PrivateDerivedArray<int, 10>;
130*41818ce1SJorge Pinto Sousa MyPrivateArray pm{};
131*41818ce1SJorge Pinto Sousa pm [ pos / 2 /*comment*/] = 1;
132*41818ce1SJorge Pinto Sousa int jjj = pm[pos - 1];
133*41818ce1SJorge Pinto Sousa
134*41818ce1SJorge Pinto Sousa pm.at(pos-1) = 2; // OK, at() instead of []
135*41818ce1SJorge Pinto Sousa pm[-1] = 3;
136*41818ce1SJorge Pinto Sousa pm[10] = 4;
137*41818ce1SJorge Pinto Sousa
138*41818ce1SJorge Pinto Sousa pm[const_index(7)] = 3;
139*41818ce1SJorge Pinto Sousa
140*41818ce1SJorge Pinto Sousa pm[0] = 3; // OK, constant index and inside bounds
141*41818ce1SJorge Pinto Sousa pm[1] = 3; // OK, constant index and inside bounds
142*41818ce1SJorge Pinto Sousa pm[9] = 3; // OK, constant index and inside bounds
143*41818ce1SJorge Pinto Sousa pm[const_index(6)] = 3; // OK, constant index and inside bounds
144*41818ce1SJorge Pinto Sousa }
145*41818ce1SJorge Pinto Sousa
146*41818ce1SJorge Pinto Sousa
147*41818ce1SJorge Pinto Sousa
148*41818ce1SJorge Pinto Sousa
g()14989a1d03eSRichard void g() {
15089a1d03eSRichard int a[10];
15189a1d03eSRichard for (int i = 0; i < 10; ++i) {
15289a1d03eSRichard a[i] = i;
15389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression
15489a1d03eSRichard // CHECK-FIXES: gsl::at(a, i) = i;
15589a1d03eSRichard gsl::at(a, i) = i; // OK, gsl::at() instead of []
15689a1d03eSRichard }
15789a1d03eSRichard
15889a1d03eSRichard a[-1] = 3; // flagged by clang-diagnostic-array-bounds
15989a1d03eSRichard a[10] = 4; // flagged by clang-diagnostic-array-bounds
16089a1d03eSRichard a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds
16189a1d03eSRichard
16289a1d03eSRichard a[0] = 3; // OK, constant index and inside bounds
16389a1d03eSRichard a[1] = 3; // OK, constant index and inside bounds
16489a1d03eSRichard a[9] = 3; // OK, constant index and inside bounds
16589a1d03eSRichard a[const_index(6)] = 3; // OK, constant index and inside bounds
16689a1d03eSRichard }
16789a1d03eSRichard
16889a1d03eSRichard struct S {
16989a1d03eSRichard int& operator[](int i);
17089a1d03eSRichard };
17189a1d03eSRichard
customOperator()17289a1d03eSRichard void customOperator() {
17389a1d03eSRichard S s;
17489a1d03eSRichard int i = 0;
17589a1d03eSRichard s[i] = 3; // OK, custom operator
17689a1d03eSRichard }
17789a1d03eSRichard
178cd40245fSisuckatcs namespace ArrayInitIndexExpr {
17989a1d03eSRichard struct A {
18089a1d03eSRichard // The compiler-generated copy constructor uses an ArraySubscriptExpr. Don't warn.
18189a1d03eSRichard int x[3];
18289a1d03eSRichard };
18389a1d03eSRichard
implicitCopyMoveCtor()184cd40245fSisuckatcs void implicitCopyMoveCtor() {
18589a1d03eSRichard // Force the compiler to generate a copy constructor.
18689a1d03eSRichard A a;
18789a1d03eSRichard A a2(a);
188cd40245fSisuckatcs
189cd40245fSisuckatcs // Force the compiler to generate a move constructor.
190cd40245fSisuckatcs A a3 = (A&&) a;
19189a1d03eSRichard }
192cd40245fSisuckatcs
lambdaCapture()193cd40245fSisuckatcs void lambdaCapture() {
194cd40245fSisuckatcs int arr[3];
195cd40245fSisuckatcs
196cd40245fSisuckatcs // Capturing an array by value uses an ArraySubscriptExpr. Don't warn.
197cd40245fSisuckatcs [arr](){};
198cd40245fSisuckatcs }
199cd40245fSisuckatcs
200cd40245fSisuckatcs #if __cplusplus >= 201703L
structuredBindings()201cd40245fSisuckatcs void structuredBindings() {
202cd40245fSisuckatcs int arr[3];
203cd40245fSisuckatcs
204cd40245fSisuckatcs // Creating structured bindings by value uses an ArraySubscriptExpr. Don't warn.
205cd40245fSisuckatcs auto [a,b,c] = arr;
206cd40245fSisuckatcs }
207cd40245fSisuckatcs #endif
208cd40245fSisuckatcs } // namespace ArrayInitIndexExpr
209