xref: /llvm-project/clang/test/Analysis/uninit-structured-binding-tuple.cpp (revision a618d5e0dd5d6fee5d73e823dbf8301663be0b4f)
1 // RUN: %clang_analyze_cc1 -Wno-ignored-reference-qualifiers -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify %s
2 
3 #include "Inputs/system-header-simulator-cxx.h"
4 
5 void clang_analyzer_eval(bool);
6 
7 namespace std {
8 template <typename T>
9 struct tuple_size {
10 };
11 
12 template <std::size_t I, typename T>
13 struct tuple_element {
14 };
15 
16 // The std::pair in our system header simulator is not tuple-like, so a tuple-like mock is created here
17 template <typename T1, typename T2>
18 struct mock_pair {
19   T1 first;
20   T2 second;
21 };
22 template <typename T1, typename T2>
23 struct tuple_size<mock_pair<T1, T2>> {
24   static const std::size_t value = 2;
25 };
26 
27 template <typename T1, typename T2>
28 struct tuple_element<0, mock_pair<T1, T2>> {
29   using type = T1;
30 };
31 
32 template <typename T1, typename T2>
33 struct tuple_element<1, mock_pair<T1, T2>> {
34   using type = T2;
35 };
36 
37 template <std::size_t I, class T>
38 using tuple_element_t = typename tuple_element<I, T>::type;
39 
40 template <std::size_t I, class T1, class T2>
41 constexpr std::tuple_element_t<I, std::mock_pair<T1, T2>> &
get(std::mock_pair<T1,T2> & p)42 get(std::mock_pair<T1, T2> &p) noexcept {
43   if (I == 0)
44     return p.first;
45   else
46     return p.second;
47 }
48 
49 template <std::size_t I, class T1, class T2>
50 constexpr const std::tuple_element_t<I, std::mock_pair<T1, T2>> &
get(const std::mock_pair<T1,T2> & p)51 get(const std::mock_pair<T1, T2> &p) noexcept {
52   if (I == 0)
53     return p.first;
54   else
55     return p.second;
56 }
57 
58 template <std::size_t I, class T1, class T2>
59 constexpr std::tuple_element_t<I, std::mock_pair<T1, T2>> &&
get(std::mock_pair<T1,T2> && p)60 get(std::mock_pair<T1, T2> &&p) noexcept {
61 
62   if (I == 0)
63     return static_cast<std::tuple_element_t<I, std::mock_pair<T1, T2>> &&>(p.first);
64   else
65     return static_cast<std::tuple_element_t<I, std::mock_pair<T1, T2>> &&>(p.second);
66 }
67 
68 template <std::size_t I, class T1, class T2>
69 constexpr const std::tuple_element_t<I, std::mock_pair<T1, T2>> &&
get(const std::mock_pair<T1,T2> && p)70 get(const std::mock_pair<T1, T2> &&p) noexcept {
71   if (I == 0)
72     return static_cast<std::tuple_element_t<I, std::mock_pair<T1, T2>> &&>(p.first);
73   else
74     return static_cast<std::tuple_element_t<I, std::mock_pair<T1, T2>> &&>(p.second);
75 }
76 
77 } // namespace std
78 // A utility that generates a tuple-like struct with 2 fields
79 //  of the same type. The fields are 'first' and 'second'
80 #define GENERATE_TUPLE_LIKE_STRUCT(name, element_type) \
81   struct name {                                        \
82     element_type first;                                \
83     element_type second;                               \
84   };                                                   \
85                                                        \
86   namespace std {                                      \
87   template <>                                          \
88   struct tuple_size<name> {                            \
89     static const std::size_t value = 2;                \
90   };                                                   \
91                                                        \
92   template <std::size_t I>                             \
93   struct tuple_element<I, name> {                      \
94     using type = element_type;                         \
95   };                                                   \
96   }
97 
non_user_defined_by_value(void)98 void non_user_defined_by_value(void) {
99   std::mock_pair<int, int> p = {1, 2};
100 
101   auto [u, v] = p;
102 
103   clang_analyzer_eval(u == 1); // expected-warning{{TRUE}}
104   clang_analyzer_eval(v == 2); // expected-warning{{TRUE}}
105 
106   int x = u;
107   u = 10;
108   int y = u;
109 
110   clang_analyzer_eval(x == 1);  // expected-warning{{TRUE}}
111   clang_analyzer_eval(u == 10); // expected-warning{{TRUE}}
112 
113   clang_analyzer_eval(y == 10);      // expected-warning{{TRUE}}
114   clang_analyzer_eval(p.first == 1); // expected-warning{{TRUE}}
115 
116   p.first = 5;
117 
118   clang_analyzer_eval(u == 10); // expected-warning{{TRUE}}
119 }
120 
non_user_defined_by_lref(void)121 void non_user_defined_by_lref(void) {
122   std::mock_pair<int, int> p = {1, 2};
123 
124   auto &[u, v] = p;
125 
126   int x = u;
127   u = 10;
128   int y = u;
129 
130   clang_analyzer_eval(x == 1);  // expected-warning{{TRUE}}
131   clang_analyzer_eval(u == 10); // expected-warning{{TRUE}}
132 
133   clang_analyzer_eval(y == 10);       // expected-warning{{TRUE}}
134   clang_analyzer_eval(p.first == 10); // expected-warning{{TRUE}}
135 
136   clang_analyzer_eval(v == 2);        // expected-warning{{TRUE}}
137   clang_analyzer_eval(p.second == 2); // expected-warning{{TRUE}}
138 
139   p.first = 5;
140 
141   clang_analyzer_eval(u == 5); // expected-warning{{TRUE}}
142 }
143 
non_user_defined_by_rref(void)144 void non_user_defined_by_rref(void) {
145   std::mock_pair<int, int> p = {1, 2};
146 
147   auto &&[u, v] = p;
148 
149   int x = u;
150   u = 10;
151   int y = u;
152 
153   clang_analyzer_eval(x == 1);  // expected-warning{{TRUE}}
154   clang_analyzer_eval(u == 10); // expected-warning{{TRUE}}
155 
156   clang_analyzer_eval(y == 10);       // expected-warning{{TRUE}}
157   clang_analyzer_eval(p.first == 10); // expected-warning{{TRUE}}
158 
159   clang_analyzer_eval(v == 2);        // expected-warning{{TRUE}}
160   clang_analyzer_eval(p.second == 2); // expected-warning{{TRUE}}
161 
162   p.first = 5;
163 
164   clang_analyzer_eval(u == 5); // expected-warning{{TRUE}}
165 }
166 
167 GENERATE_TUPLE_LIKE_STRUCT(Test, int);
168 
169 template <std::size_t I>
get(Test t)170 int get(Test t) {
171   if (I == 0) {
172     t.second = 10;
173     return t.first;
174   } else {
175     t.first = 20;
176     return t.second;
177   }
178 }
179 
user_defined_get_val_by_val(void)180 void user_defined_get_val_by_val(void) {
181   Test p{1, 2};
182   auto [u, v] = p;
183 
184   clang_analyzer_eval(u == 1); // expected-warning{{TRUE}}
185 
186   u = 8;
187 
188   int x = u;
189 
190   clang_analyzer_eval(x == 8); // expected-warning{{TRUE}}
191 
192   clang_analyzer_eval(u == 8); // expected-warning{{TRUE}}
193   clang_analyzer_eval(v == 2); // expected-warning{{TRUE}}
194 
195   clang_analyzer_eval(p.first == 1);  // expected-warning{{TRUE}}
196   clang_analyzer_eval(p.second == 2); // expected-warning{{TRUE}}
197 
198   p.first = 5;
199 
200   clang_analyzer_eval(u == 8);       // expected-warning{{TRUE}}
201   clang_analyzer_eval(p.first == 5); // expected-warning{{TRUE}}
202 }
203 
204 GENERATE_TUPLE_LIKE_STRUCT(Test2, int);
205 
206 template <std::size_t I>
get(Test2 & t)207 int get(Test2 &t) {
208   if (I == 0) {
209     t.second = 10;
210     return t.first;
211   } else {
212     t.first = 20;
213     return t.second;
214   }
215 }
216 
user_defined_get_val_by_lref(void)217 void user_defined_get_val_by_lref(void) {
218   Test2 p{1, 2};
219 
220   auto &[u, v] = p;
221 
222   clang_analyzer_eval(u == 1);  // expected-warning{{TRUE}}
223   clang_analyzer_eval(v == 10); // expected-warning{{TRUE}}
224 
225   u = 8;
226 
227   int x = u;
228 
229   clang_analyzer_eval(x == 8); // expected-warning{{TRUE}}
230 
231   clang_analyzer_eval(u == 8);  // expected-warning{{TRUE}}
232   clang_analyzer_eval(v == 10); // expected-warning{{TRUE}}
233 
234   clang_analyzer_eval(p.first == 20);  // expected-warning{{TRUE}}
235   clang_analyzer_eval(p.second == 10); // expected-warning{{TRUE}}
236 
237   p.first = 5;
238 
239   clang_analyzer_eval(u == 8);       // expected-warning{{TRUE}}
240   clang_analyzer_eval(p.first == 5); // expected-warning{{TRUE}}
241 }
242 
user_defined_get_val_by_rref(void)243 void user_defined_get_val_by_rref(void) {
244   Test2 p{1, 2};
245 
246   auto &&[u, v] = p;
247 
248   clang_analyzer_eval(u == 1);  // expected-warning{{TRUE}}
249   clang_analyzer_eval(v == 10); // expected-warning{{TRUE}}
250 
251   u = 8;
252 
253   int x = u;
254 
255   clang_analyzer_eval(x == 8); // expected-warning{{TRUE}}
256 
257   clang_analyzer_eval(u == 8);  // expected-warning{{TRUE}}
258   clang_analyzer_eval(v == 10); // expected-warning{{TRUE}}
259 
260   clang_analyzer_eval(p.first == 20);  // expected-warning{{TRUE}}
261   clang_analyzer_eval(p.second == 10); // expected-warning{{TRUE}}
262 
263   p.first = 5;
264 
265   clang_analyzer_eval(u == 8);       // expected-warning{{TRUE}}
266   clang_analyzer_eval(p.first == 5); // expected-warning{{TRUE}}
267 }
268 
269 struct MixedTest {
270   int x;
271   char &&y;
272   int &z;
273 };
274 
275 namespace std {
276 template <>
277 struct tuple_size<MixedTest> {
278   static const std::size_t value = 3;
279 };
280 
281 template <>
282 struct tuple_element<0, MixedTest> {
283   using type = int;
284 };
285 
286 template <>
287 struct tuple_element<1, MixedTest> {
288   using type = char &&;
289 };
290 
291 template <>
292 struct tuple_element<2, MixedTest> {
293   using type = int &;
294 };
295 
296 template <std::size_t I, typename T>
297 using tuple_element_t = typename tuple_element<I, T>::type;
298 
299 } // namespace std
300 
301 template <std::size_t I>
get(const MixedTest & t)302 const std::tuple_element_t<I, MixedTest> &get(const MixedTest &t) {}
303 
304 template <>
get(const MixedTest & t)305 const std::tuple_element_t<0, MixedTest> &get<0>(const MixedTest &t) {
306   return t.x;
307 }
308 
309 template <>
get(const MixedTest & t)310 const std::tuple_element_t<1, MixedTest> &get<1>(const MixedTest &t) {
311   return t.y;
312 }
313 
314 template <>
get(const MixedTest & t)315 const std::tuple_element_t<2, MixedTest> &get<2>(const MixedTest &t) {
316   return t.z;
317 }
318 
mixed_type_cref(void)319 void mixed_type_cref(void) {
320   int x = 1;
321   char y = 2;
322   int z = 3;
323 
324   MixedTest m{x, std::move(y), z};
325   const auto &[a, b, c] = m;
326 
327   clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
328   clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
329   clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
330 
331   clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
332   clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
333   clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
334 }
335 
336 template <std::size_t I>
get(MixedTest & t)337 std::tuple_element_t<I, MixedTest> &get(MixedTest &t) {}
338 
339 template <>
get(MixedTest & t)340 std::tuple_element_t<0, MixedTest> &get<0>(MixedTest &t) {
341   return t.x;
342 }
343 
344 template <>
get(MixedTest & t)345 std::tuple_element_t<1, MixedTest> &get<1>(MixedTest &t) {
346   return t.y;
347 }
348 
349 template <>
get(MixedTest & t)350 std::tuple_element_t<2, MixedTest> &get<2>(MixedTest &t) {
351   return t.z;
352 }
353 
mixed_type_lref(void)354 void mixed_type_lref(void) {
355   int x = 1;
356   char y = 2;
357   int z = 3;
358 
359   MixedTest m{x, std::move(y), z};
360   auto &[a, b, c] = m;
361 
362   a = 4;
363   b = 5;
364   c = 6;
365 
366   clang_analyzer_eval(get<0>(m) == 4); // expected-warning{{TRUE}}
367   clang_analyzer_eval(get<1>(m) == 5); // expected-warning{{TRUE}}
368   clang_analyzer_eval(get<2>(m) == 6); // expected-warning{{TRUE}}
369 
370   clang_analyzer_eval(get<0>(m) == 4); // expected-warning{{TRUE}}
371   clang_analyzer_eval(get<1>(m) == 5); // expected-warning{{TRUE}}
372   clang_analyzer_eval(get<2>(m) == 6); // expected-warning{{TRUE}}
373 
374   clang_analyzer_eval(z == 6); // expected-warning{{TRUE}}
375 }
376 
mixed_type_rref(void)377 void mixed_type_rref(void) {
378   int x = 1;
379   char y = 2;
380   int z = 3;
381 
382   MixedTest m{x, std::move(y), z};
383   auto &&[a, b, c] = m;
384 
385   a = 4;
386   b = 5;
387   c = 6;
388 
389   clang_analyzer_eval(get<0>(m) == 4); // expected-warning{{TRUE}}
390   clang_analyzer_eval(get<1>(m) == 5); // expected-warning{{TRUE}}
391   clang_analyzer_eval(get<2>(m) == 6); // expected-warning{{TRUE}}
392 
393   clang_analyzer_eval(get<0>(m) == 4); // expected-warning{{TRUE}}
394   clang_analyzer_eval(get<1>(m) == 5); // expected-warning{{TRUE}}
395   clang_analyzer_eval(get<2>(m) == 6); // expected-warning{{TRUE}}
396 
397   clang_analyzer_eval(z == 6); // expected-warning{{TRUE}}
398 }
399 
ref_val(void)400 void ref_val(void) {
401   int i = 1, j = 2;
402   std::mock_pair<int &, int &> p{i, j};
403 
404   auto [a, b] = p;
405   clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
406   clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
407 
408   a = 3;
409   b = 4;
410 
411   clang_analyzer_eval(p.first == 3);  // expected-warning{{TRUE}}
412   clang_analyzer_eval(p.second == 4); // expected-warning{{TRUE}}
413 
414   clang_analyzer_eval(a == 3); // expected-warning{{TRUE}}
415   clang_analyzer_eval(b == 4); // expected-warning{{TRUE}}
416 }
417 
418 struct Small_Non_POD {
419   int i;
420   int j;
421 };
422 
non_user_defined_small_non_pod_by_value(void)423 void non_user_defined_small_non_pod_by_value(void) {
424   std::mock_pair<Small_Non_POD, Small_Non_POD> p{{1, 2}, {1, 2}};
425 
426   auto [a, b] = p;
427 
428   clang_analyzer_eval(a.i == 1); // expected-warning{{TRUE}}
429   clang_analyzer_eval(a.j == 2); // expected-warning{{TRUE}}
430 
431   clang_analyzer_eval(b.i == 1); // expected-warning{{TRUE}}
432   clang_analyzer_eval(b.j == 2); // expected-warning{{TRUE}}
433 
434   a.i = 3;
435   a.j = 4;
436 
437   b.i = 5;
438   b.j = 6;
439 
440   clang_analyzer_eval(a.i == 3); // expected-warning{{TRUE}}
441   clang_analyzer_eval(a.j == 4); // expected-warning{{TRUE}}
442 
443   clang_analyzer_eval(b.i == 5); // expected-warning{{TRUE}}
444   clang_analyzer_eval(b.j == 6); // expected-warning{{TRUE}}
445 
446   clang_analyzer_eval(p.first.i == 1); // expected-warning{{TRUE}}
447   clang_analyzer_eval(p.first.j == 2); // expected-warning{{TRUE}}
448 
449   clang_analyzer_eval(p.second.i == 1); // expected-warning{{TRUE}}
450   clang_analyzer_eval(p.second.j == 2); // expected-warning{{TRUE}}
451 }
452 
non_user_defined_small_non_pod_by_lref(void)453 void non_user_defined_small_non_pod_by_lref(void) {
454   std::mock_pair<Small_Non_POD, Small_Non_POD> p{{1, 2}, {1, 2}};
455 
456   auto &[a, b] = p;
457 
458   clang_analyzer_eval(a.i == 1); // expected-warning{{TRUE}}
459   clang_analyzer_eval(a.j == 2); // expected-warning{{TRUE}}
460 
461   clang_analyzer_eval(b.i == 1); // expected-warning{{TRUE}}
462   clang_analyzer_eval(b.j == 2); // expected-warning{{TRUE}}
463 
464   a.i = 3;
465   a.j = 4;
466 
467   b.i = 5;
468   b.j = 6;
469 
470   clang_analyzer_eval(a.i == 3); // expected-warning{{TRUE}}
471   clang_analyzer_eval(a.j == 4); // expected-warning{{TRUE}}
472 
473   clang_analyzer_eval(b.i == 5); // expected-warning{{TRUE}}
474   clang_analyzer_eval(b.j == 6); // expected-warning{{TRUE}}
475 
476   clang_analyzer_eval(p.first.i == 3); // expected-warning{{TRUE}}
477   clang_analyzer_eval(p.first.j == 4); // expected-warning{{TRUE}}
478 
479   clang_analyzer_eval(p.second.i == 5); // expected-warning{{TRUE}}
480   clang_analyzer_eval(p.second.j == 6); // expected-warning{{TRUE}}
481 }
482 
non_user_defined_small_non_pod_by_rref(void)483 void non_user_defined_small_non_pod_by_rref(void) {
484   std::mock_pair<Small_Non_POD, Small_Non_POD> p{{1, 2}, {1, 2}};
485 
486   auto &&[a, b] = p;
487 
488   clang_analyzer_eval(a.i == 1); // expected-warning{{TRUE}}
489   clang_analyzer_eval(a.j == 2); // expected-warning{{TRUE}}
490 
491   clang_analyzer_eval(b.i == 1); // expected-warning{{TRUE}}
492   clang_analyzer_eval(b.j == 2); // expected-warning{{TRUE}}
493 
494   a.i = 3;
495   a.j = 4;
496 
497   b.i = 5;
498   b.j = 6;
499 
500   clang_analyzer_eval(a.i == 3); // expected-warning{{TRUE}}
501   clang_analyzer_eval(a.j == 4); // expected-warning{{TRUE}}
502 
503   clang_analyzer_eval(b.i == 5); // expected-warning{{TRUE}}
504   clang_analyzer_eval(b.j == 6); // expected-warning{{TRUE}}
505 
506   clang_analyzer_eval(p.first.i == 3); // expected-warning{{TRUE}}
507   clang_analyzer_eval(p.first.j == 4); // expected-warning{{TRUE}}
508 
509   clang_analyzer_eval(p.second.i == 5); // expected-warning{{TRUE}}
510   clang_analyzer_eval(p.second.j == 6); // expected-warning{{TRUE}}
511 }
512 
513 GENERATE_TUPLE_LIKE_STRUCT(Uninit, int);
514 template <std::size_t I>
get(Uninit && t)515 int &get(Uninit &&t) {
516   if (I == 0) {
517     return t.first;
518   } else {
519     return t.second;
520   }
521 }
522 
uninit_a(void)523 void uninit_a(void) {
524   Uninit u;
525 
526   auto [a, b] = u;
527 
528   int x = a; // expected-warning{{Assigned value is garbage or undefined}}
529 }
530 
uninit_b(void)531 void uninit_b(void) {
532   Uninit u;
533 
534   auto [a, b] = u;
535 
536   int x = b; // expected-warning{{Assigned value is garbage or undefined}}
537 }
538 
539 GENERATE_TUPLE_LIKE_STRUCT(UninitCall, int);
540 template <std::size_t I>
get(UninitCall t)541 int get(UninitCall t) {
542   if (I == 0) {
543     return t.first;
544   } else {
545     return t.second;
546   }
547 }
548 
uninit_call(void)549 void uninit_call(void) {
550   UninitCall u;
551 
552   auto [a, b] = u;
553 
554   int x = a;
555   // expected-warning@543{{Undefined or garbage value returned to caller}}
556 }
557 
syntax_2()558 void syntax_2() {
559   std::mock_pair<Small_Non_POD, Small_Non_POD> p{{1, 2}, {3, 4}};
560 
561   auto [a, b]{p};
562 
563   clang_analyzer_eval(a.i == 1); // expected-warning{{TRUE}}
564   clang_analyzer_eval(a.j == 2); // expected-warning{{TRUE}}
565 
566   clang_analyzer_eval(b.i == 3); // expected-warning{{TRUE}}
567   clang_analyzer_eval(b.j == 4); // expected-warning{{TRUE}}
568 }
569 
syntax_3()570 void syntax_3() {
571   std::mock_pair<Small_Non_POD, Small_Non_POD> p{{1, 2}, {3, 4}};
572 
573   auto [a, b](p);
574 
575   clang_analyzer_eval(a.i == 1); // expected-warning{{TRUE}}
576   clang_analyzer_eval(a.j == 2); // expected-warning{{TRUE}}
577 
578   clang_analyzer_eval(b.i == 3); // expected-warning{{TRUE}}
579   clang_analyzer_eval(b.j == 4); // expected-warning{{TRUE}}
580 }
581