Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / test / SemaCXX / warn-unsafe-buffer-usage-fixits-local-var-span.cpp
blob114ceaad56e451a68a14533f2e805c44fa1e0bdc
1 // RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
2 // RUN: -fsafe-buffer-usage-suggestions \
3 // RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
4 typedef int * Int_ptr_t;
5 typedef int Int_t;
7 void local_array_subscript_simple() {
8 int tmp;
9 int *p = new int[10];
10 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
11 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
12 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
13 const int *q = new int[10];
14 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::span<int const> q"
15 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:"{"
16 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:29}:", 10}"
17 tmp = p[5];
18 tmp = q[5];
20 // We do not fix the following declaration. Because if the
21 // definition of `Int_ptr_t` gets changed, the fixed code becomes
22 // incorrect and may NOT be noticed.
23 // FIXME: Fix with std::span<std::remove_pointer_t<Int_ptr_t>>?
24 Int_ptr_t x = new int[10];
25 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
26 Int_t * z = new int[10];
27 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<Int_t> z"
28 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"
29 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}"
30 Int_t * w = new Int_t[10];
31 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<Int_t> w"
32 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"
33 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}"
35 tmp = x[5];
36 tmp = z[5];
37 tmp = w[5];
40 void local_array_subscript_auto() {
41 int tmp;
42 // We do not fix the following declaration because
43 // that'd cause us to hardcode the element type.
44 // FIXME: Can we use the C++17 class template argument deduction
45 // to avoid spelling out the element type?
46 auto p = new int[10];
47 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
48 tmp = p[5];
51 void local_variable_qualifiers_specifiers() {
52 int a[10];
53 const int * p = a;
54 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span<int const> p"
55 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{"
56 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", 10}"
57 const int * const q = a;
58 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:24}:"std::span<int const> const q"
59 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:25-[[@LINE-2]]:25}:"{"
60 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}"
61 int tmp;
62 tmp = p[5];
63 tmp = q[5];
67 void local_array_subscript_variable_extent() {
68 int n = 10;
69 int tmp;
70 int *p = new int[n];
71 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
72 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
73 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", n}"
74 // If the extent expression does not have a constant value, we cannot fill the extent for users...
75 int *q = new int[n++];
76 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
77 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
78 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
79 tmp = p[5];
80 tmp = q[5];
84 void local_ptr_to_array() {
85 int tmp;
86 int n = 10;
87 int a[10];
88 int b[n]; // If the extent expression does not have a constant value, we cannot fill the extent for users...
89 int *p = a;
90 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
91 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
92 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", 10}"
93 int *q = b;
94 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
95 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
96 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
97 // No way to know if `n` is ever mutated since `int b[n];`, so no way to figure out the extent
98 tmp = p[5];
99 tmp = q[5];
102 void local_ptr_addrof_init() {
103 int var;
104 int * q = &var;
105 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> q"
106 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
107 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:", 1}"
108 // This expression involves unsafe buffer accesses, which will crash
109 // at runtime after applying the fix-it,
110 var = q[5];
113 void decl_without_init() {
114 int tmp;
115 int * p;
116 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span<int> p"
117 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
118 Int_t * q;
119 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<Int_t> q"
120 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
121 tmp = p[5];
122 tmp = q[5];
125 // Explicit casts are required in the following cases. No way to
126 // figure out span extent for them automatically.
127 void explict_cast() {
128 int tmp;
129 int * p = (int*) new int[10][10];
130 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> p"
131 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
132 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:35-[[@LINE-3]]:35}:", <# placeholder #>}"
133 tmp = p[5];
135 int a;
136 char * q = (char *)&a;
137 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:13}:"std::span<char> q"
138 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{"
139 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
140 tmp = (int) q[5];
142 void * r = &a;
143 char * s = (char *) r;
144 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:13}:"std::span<char> s"
145 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{"
146 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
147 tmp = (int) s[5];
150 void null_init() {
151 #define NULL 0
152 int tmp;
153 int * my_null = 0;
154 int * p = 0;
155 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> p"
156 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
157 int * g = NULL; // cannot handle fix-its involving macros for now
158 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
159 int * f = nullptr;
160 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> f"
161 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
163 // In case of value dependencies, we give up
164 int * q = my_null;
165 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> q"
166 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
167 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", <# placeholder #>}"
168 int * r = my_null + 0;
169 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> r"
170 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
171 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
173 tmp = p[5]; // `p[5]` will cause crash after `p` being transformed to be a `std::span`
174 tmp = q[5]; // Similar for the rests.
175 tmp = r[5];
176 tmp = g[5];
177 tmp = f[5];
178 #undef NULL
182 void unsupported_multi_decl(int * x) {
183 int * p = x, * q = new int[10];
184 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
185 *p = q[5];
188 void macroVariableIdentifier() {
189 #define MY_NAME p
190 #define MY_NAME_ARG(x) q
192 // Although fix-its include macros, the macros do not overlap with
193 // the bounds of the source range of these fix-its. So these fix-its
194 // are valid.
196 int * MY_NAME = new int[10];
197 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span<int> MY_NAME"
198 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{"
199 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:30-[[@LINE-3]]:30}:", 10}"
200 int * MY_NAME_ARG( 'x' ) = new int[10];
201 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:29}:"std::span<int> MY_NAME_ARG( 'x' )"
202 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:"{"
203 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:41-[[@LINE-3]]:41}:", 10}"
204 p[5] = 5;
205 q[5] = 5;
206 #undef MY_NAME
207 #undef MY_NAME_ARG
210 void unsupported_fixit_overlapping_macro(int * x) {
211 int tmp;
212 // In the case below, a tentative fix-it replaces `MY_INT * p =` with `std::span<MY_INT> p `.
213 // The bounds of the source range of the fix-it overlap with the use of the macro
214 // `MY_INT`. The fix-it is discarded then.
216 // FIXME: we do not have to discard a fix-it if its begin location
217 // overlaps with the begin location of a macro. Similar for end
218 // locations.
220 #define MY_INT int
221 MY_INT * p = new int[10];
222 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
223 tmp = p[5];
225 #define MY_VAR(name) int * name
226 MY_VAR(q) = new int[10];
227 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
228 tmp = q[5];
230 // In cases where fix-its do not change the original code where
231 // macros are used, those fix-its will be emitted. For example,
232 // fixits are inserted before and after `new MY_INT[MY_TEN]` below.
233 #define MY_TEN 10
234 int * g = new MY_INT[MY_TEN];
235 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> g"
236 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
237 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:31-[[@LINE-3]]:31}:", MY_TEN}"
238 tmp = g[5];
240 #undef MY_INT
241 #undef MY_VAR
242 #undef MY_TEN
245 void unsupported_subscript_negative(int i, unsigned j, unsigned long k) {
246 int tmp;
247 int * p = new int[10];
248 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
250 tmp = p[-1]; // If `p` is made a span, this `[]` operation is wrong,
251 // so no fix-it emitted.
253 int * q = new int[10];
254 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
256 tmp = q[5];
257 tmp = q[i]; // If `q` is made a span, this `[]` operation may be
258 // wrong as we do not know if `i` is non-negative, so
259 // no fix-it emitted.
261 int * r = new int[10];
262 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> r"
263 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
264 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
266 tmp = r[j] + r[k]; // both `j` and `k` are unsigned so they must be non-negative
267 tmp = r[(unsigned int)-1]; // a cast-to-unsigned-expression is also non-negative
270 #define DEFINE_PTR(X) int* ptr = (X);
272 void all_vars_in_macro() {
273 int* local;
274 DEFINE_PTR(local)
275 ptr[1] = 0;
278 void few_vars_in_macro() {
279 int* local;
280 DEFINE_PTR(local)
281 ptr[1] = 0;
282 int tmp;
283 ptr[2] = 30;
284 int * p = new int[10];
285 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> p"
286 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
287 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
288 tmp = p[5];
289 int val = *p;
290 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:""
291 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"[0]"
292 val = *p + 30;
293 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:""
294 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:11}:"[0]"