208 lines · cpp
1// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t2 3typedef __SIZE_TYPE__ size_t;4 5namespace std {6 template<typename T, size_t N>7 struct array {8 T& operator[](size_t n);9 T& at(size_t n);10 };11}12 13 14namespace gsl {15 template<class T, size_t N>16 T& at( T(&a)[N], size_t index );17 18 template<class T, size_t N>19 T& at( std::array<T, N> &a, size_t index );20}21 22constexpr int const_index(int base) {23 return base + 3;24}25 26template<class T, size_t N>27class DerivedArray : public std::array<T, N> {};28 29void f(std::array<int, 10> a, int pos) {30 a [ pos / 2 /*comment*/] = 1;31 // 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]32 int j = a[pos - 1];33 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression34 35 a.at(pos-1) = 2; // OK, at() instead of []36 gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []37 38 a[-1] = 3;39 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]40 a[10] = 4;41 // 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]42 43 a[const_index(7)] = 3;44 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)45 46 a[0] = 3; // OK, constant index and inside bounds47 a[1] = 3; // OK, constant index and inside bounds48 a[9] = 3; // OK, constant index and inside bounds49 a[const_index(6)] = 3; // OK, constant index and inside bounds50 51 using MyArray = std::array<int, 10>;52 MyArray m{};53 m [ pos / 2 /*comment*/] = 1;54 // 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]55 int jj = m[pos - 1];56 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use array subscript when the index is not an integer constant expression57 58 m.at(pos-1) = 2; // OK, at() instead of []59 gsl::at(m, pos-1) = 2; // OK, gsl::at() instead of []60 m[-1] = 3;61 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]62 m[10] = 4;63 // 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]64 65 m[const_index(7)] = 3;66 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)67 68 m[0] = 3; // OK, constant index and inside bounds69 m[1] = 3; // OK, constant index and inside bounds70 m[9] = 3; // OK, constant index and inside bounds71 m[const_index(6)] = 3; // OK, constant index and inside bounds72}73 74template<class T, size_t N>75class PrivateDerivedArray : std::array<T, N> {76public:77 T& operator[](size_t n){78 return std::array<T, N>::operator[](static_cast<int>(n));79 };80 T& at(size_t n) {81 return std::array<T, N>::at(static_cast<int>(n));82 };83};84 85void f_derived(DerivedArray<int, 10> a, int pos) {86 a [ pos / 2 /*comment*/] = 1;87 // 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 int j = a[pos - 1];89 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression90 91 a.at(pos-1) = 2; // OK, at() instead of []92 gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []93 94 a[-1] = 3;95 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]96 a[10] = 4;97 // 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 99 a[const_index(7)] = 3;100 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)101 102 a[0] = 3; // OK, constant index and inside bounds103 a[1] = 3; // OK, constant index and inside bounds104 a[9] = 3; // OK, constant index and inside bounds105 a[const_index(6)] = 3; // OK, constant index and inside bounds106 107 using MyArray = DerivedArray<int, 10>;108 MyArray m{};109 m [ pos / 2 /*comment*/] = 1;110 // 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 int jj = m[pos - 1];112 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use array subscript when the index is not an integer constant expression113 114 m.at(pos-1) = 2; // OK, at() instead of []115 gsl::at(m, pos-1) = 2; // OK, gsl::at() instead of []116 m[-1] = 3;117 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]118 m[10] = 4;119 // 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 121 m[const_index(7)] = 3;122 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)123 124 m[0] = 3; // OK, constant index and inside bounds125 m[1] = 3; // OK, constant index and inside bounds126 m[9] = 3; // OK, constant index and inside bounds127 m[const_index(6)] = 3; // OK, constant index and inside bounds128 129 using MyPrivateArray = PrivateDerivedArray<int, 10>;130 MyPrivateArray pm{};131 pm [ pos / 2 /*comment*/] = 1;132 int jjj = pm[pos - 1];133 134 pm.at(pos-1) = 2; // OK, at() instead of []135 pm[-1] = 3;136 pm[10] = 4;137 138 pm[const_index(7)] = 3;139 140 pm[0] = 3; // OK, constant index and inside bounds141 pm[1] = 3; // OK, constant index and inside bounds142 pm[9] = 3; // OK, constant index and inside bounds143 pm[const_index(6)] = 3; // OK, constant index and inside bounds144}145 146 147 148 149void g() {150 int a[10];151 for (int i = 0; i < 10; ++i) {152 a[i] = i;153 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression154 gsl::at(a, i) = i; // OK, gsl::at() instead of []155 }156 157 a[-1] = 3; // flagged by clang-diagnostic-array-bounds158 a[10] = 4; // flagged by clang-diagnostic-array-bounds159 a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds160 161 a[0] = 3; // OK, constant index and inside bounds162 a[1] = 3; // OK, constant index and inside bounds163 a[9] = 3; // OK, constant index and inside bounds164 a[const_index(6)] = 3; // OK, constant index and inside bounds165}166 167struct S {168 int& operator[](int i);169};170 171void customOperator() {172 S s;173 int i = 0;174 s[i] = 3; // OK, custom operator175}176 177namespace ArrayInitIndexExpr {178struct A {179 // The compiler-generated copy constructor uses an ArraySubscriptExpr. Don't warn.180 int x[3];181};182 183void implicitCopyMoveCtor() {184 // Force the compiler to generate a copy constructor.185 A a;186 A a2(a);187 188 // Force the compiler to generate a move constructor.189 A a3 = (A&&) a;190}191 192void lambdaCapture() {193 int arr[3];194 195 // Capturing an array by value uses an ArraySubscriptExpr. Don't warn. 196 [arr](){};197}198 199#if __cplusplus >= 201703L200void structuredBindings() {201 int arr[3];202 203 // Creating structured bindings by value uses an ArraySubscriptExpr. Don't warn.204 auto [a,b,c] = arr;205}206#endif207} // namespace ArrayInitIndexExpr208