[clang] Implement lifetime analysis for lifetime_capture_by(X) (#115921)
[llvm-project.git] / clang / test / SemaCXX / warn-unsafe-buffer-usage-fixits-local-var-span.cpp
blob292e89cb00c9e467f8a7627a349b088968062065
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]]:8}:"std::span<int> "
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]]:14}:"std::span<int const> "
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]]:10}:"std::span<Int_t>"
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]]:10}:"std::span<Int_t>"
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]]:14}:"std::span<int const>"
55 const int * const q = a;
56 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const>"
57 int tmp;
58 tmp = p[5];
59 tmp = q[5];
61 [[deprecated]] const int * x = a;
62 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:18-[[@LINE-1]]:29}:"std::span<int const>"
63 const int * y [[deprecated]];
64 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const>"
65 tmp = x[5];
66 tmp = y[5];
69 void local_variable_unsupported_specifiers() {
70 int a[10];
71 const int * p [[deprecated]] = a; // not supported because the attribute overlaps the source range of the declaration
72 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
74 static const int * q = a; // storage specifier not supported yet
75 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
77 extern int * x; // storage specifier not supported yet
78 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
80 constexpr int * y = 0; // `constexpr` specifier not supported yet
81 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
83 int tmp;
85 tmp = p[5];
86 tmp = q[5];
87 tmp = x[5];
88 tmp = y[5];
91 void local_array_subscript_variable_extent() {
92 int n = 10;
93 int tmp;
94 int *p = new int[n];
95 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
96 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
97 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", n}"
98 // If the extent expression does not have a constant value, we cannot fill the extent for users...
99 int *q = new int[n++];
100 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
101 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
102 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
103 tmp = p[5];
104 tmp = q[5];
108 void local_ptr_to_array() {
109 int tmp;
110 int n = 10;
111 int a[10];
112 int b[n]; // If the extent expression does not have a constant value, we cannot fill the extent for users...
113 int *p = a;
114 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
115 int *q = b;
116 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
117 // No way to know if `n` is ever mutated since `int b[n];`, so no way to figure out the extent
118 tmp = p[5];
119 tmp = q[5];
122 void local_ptr_addrof_init() {
123 int var;
124 int * q = &var;
125 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
126 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
127 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:", 1}"
128 // This expression involves unsafe buffer accesses, which will crash
129 // at runtime after applying the fix-it,
130 var = q[5];
133 void decl_without_init() {
134 int tmp;
135 int * p;
136 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
137 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
138 Int_t * q;
139 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span<Int_t>"
140 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
141 tmp = p[5];
142 tmp = q[5];
145 // Explicit casts are required in the following cases. No way to
146 // figure out span extent for them automatically.
147 void explict_cast() {
148 int tmp;
149 int * p = (int*) new int[10][10];
150 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
151 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
152 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:35-[[@LINE-3]]:35}:", <# placeholder #>}"
153 tmp = p[5];
155 int a;
156 char * q = (char *)&a;
157 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span<char>"
158 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{"
159 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
160 tmp = (int) q[5];
162 void * r = &a;
163 char * s = (char *) r;
164 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span<char>"
165 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{"
166 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
167 tmp = (int) s[5];
170 void null_init() {
171 #define NULL 0
172 int tmp;
173 int * my_null = 0;
174 int * p = 0;
175 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
176 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
177 int * g = NULL; // cannot handle fix-its involving macros for now
178 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
179 int * f = nullptr;
180 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
181 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
183 // In case of value dependencies, we give up
184 int * q = my_null;
185 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
186 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
187 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", <# placeholder #>}"
188 int * r = my_null + 0;
189 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
190 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
191 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"
193 tmp = p[5]; // `p[5]` will cause crash after `p` being transformed to be a `std::span`
194 tmp = q[5]; // Similar for the rests.
195 tmp = r[5];
196 tmp = g[5];
197 tmp = f[5];
198 #undef NULL
202 void unsupported_multi_decl(int * x) {
203 int * p = x, * q = new int[10];
204 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
205 *p = q[5];
208 void macroVariableIdentifier() {
209 #define MY_NAME p
210 #define MY_NAME_ARG(x) q
212 // Although fix-its include macros, the macros do not overlap with
213 // the bounds of the source range of these fix-its. So these fix-its
214 // are valid.
216 int * MY_NAME = new int[10];
217 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
218 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{"
219 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:30-[[@LINE-3]]:30}:", 10}"
220 int * MY_NAME_ARG( 'x' ) = new int[10];
221 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
222 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:"{"
223 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:41-[[@LINE-3]]:41}:", 10}"
224 p[5] = 5;
225 q[5] = 5;
226 #undef MY_NAME
227 #undef MY_NAME_ARG
230 void unsupported_fixit_overlapping_macro(int * x) {
231 int tmp;
232 // In the case below, a tentative fix-it replaces `MY_INT * p =` with `std::span<MY_INT> p `.
233 // The bounds of the source range of the fix-it overlap with the use of the macro
234 // `MY_INT`. The fix-it is discarded then.
236 // FIXME: we do not have to discard a fix-it if its begin location
237 // overlaps with the begin location of a macro. Similar for end
238 // locations.
240 #define MY_INT int
241 MY_INT * p = new int[10];
242 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
243 tmp = p[5];
245 #define MY_VAR(name) int * name
246 MY_VAR(q) = new int[10];
247 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
248 tmp = q[5];
250 // In cases where fix-its do not change the original code where
251 // macros are used, those fix-its will be emitted. For example,
252 // fixits are inserted before and after `new MY_INT[MY_TEN]` below.
253 #define MY_TEN 10
254 int * g = new MY_INT[MY_TEN];
255 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
256 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
257 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:31-[[@LINE-3]]:31}:", MY_TEN}"
258 tmp = g[5];
260 #undef MY_INT
261 #undef MY_VAR
262 #undef MY_TEN
265 void unsupported_subscript_negative(int i, unsigned j, unsigned long k) {
266 int tmp;
267 int * p = new int[10];
268 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
270 tmp = p[-1]; // If `p` is made a span, this `[]` operation is wrong,
271 // so no fix-it emitted.
273 int * q = new int[10];
274 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
276 tmp = q[5];
277 tmp = q[i]; // If `q` is made a span, this `[]` operation may be
278 // wrong as we do not know if `i` is non-negative, so
279 // no fix-it emitted.
281 int * r = new int[10];
282 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
283 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
284 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
286 tmp = r[j] + r[k]; // both `j` and `k` are unsigned so they must be non-negative
287 tmp = r[(unsigned int)-1]; // a cast-to-unsigned-expression is also non-negative
290 #define DEFINE_PTR(X) int* ptr = (X);
292 void all_vars_in_macro() {
293 int* local;
294 DEFINE_PTR(local)
295 ptr[1] = 0;
298 void few_vars_in_macro() {
299 int* local;
300 DEFINE_PTR(local)
301 ptr[1] = 0;
302 int tmp;
303 ptr[2] = 30;
304 int * p = new int[10];
305 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
306 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
307 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
308 tmp = p[5];
309 int val = *p;
310 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:""
311 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"[0]"
312 val = *p + 30;
313 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:""
314 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:11}:"[0]"