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