1 | // RUN: %clang_analyze_cc1 -std=c++17 -analyzer-checker=core,deadcode -verify %s |
2 | |
3 | typedef unsigned long size_t; |
4 | |
5 | // Machinery required for custom structured bindings decomposition. |
6 | namespace std { |
7 | template <class T> class tuple_size; |
8 | template <class T> |
9 | constexpr size_t tuple_size_v = tuple_size<T>::value; |
10 | template <size_t I, class T> class tuple_element; |
11 | |
12 | template<class T, T v> |
13 | struct integral_constant { |
14 | static constexpr T value = v; |
15 | typedef T value_type; |
16 | typedef integral_constant type; |
17 | constexpr operator value_type() const noexcept { return value; } |
18 | }; |
19 | } |
20 | |
21 | struct S { |
22 | int a; |
23 | double b; |
24 | S(int a, double b) : a(a), b(b) {}; |
25 | }; |
26 | |
27 | S GetNumbers(); |
28 | |
29 | int used_binding() { |
30 | const auto [a, b] = GetNumbers(); // no-warning |
31 | return a + b; |
32 | } |
33 | |
34 | void no_warning_on_copy(S s) { |
35 | // Copy constructor might have side effects. |
36 | const auto [a, b] = s; // no-warning |
37 | } |
38 | |
39 | |
40 | int unused_binding_ignored() { |
41 | const auto [a, b] = GetNumbers(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}} |
42 | return 0; |
43 | } |
44 | |
45 | int unused_binding_liveness_required() { |
46 | auto [a2, b2] = GetNumbers(); // expected-warning{{Value stored to '[a2, b2]' during its initialization is never read}} |
47 | a2 = 10; |
48 | b2 = 20; |
49 | return a2 + b2; |
50 | } |
51 | |
52 | int kill_one_binding() { |
53 | auto [a, b] = GetNumbers(); // no-warning |
54 | a = 100; |
55 | return a + b; |
56 | |
57 | } |
58 | |
59 | int kill_one_binding2() { |
60 | auto [a, b] = GetNumbers(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}} |
61 | a = 100; |
62 | return a; |
63 | } |
64 | |
65 | void use_const_reference_bindings() { |
66 | const auto &[a, b] = GetNumbers(); // no-warning |
67 | } |
68 | |
69 | void use_reference_bindings() { |
70 | S s(0, 0); |
71 | auto &[a, b] = s; // no-warning |
72 | a = 200; |
73 | } |
74 | |
75 | int read_through_pointer() { |
76 | auto [a, b] = GetNumbers(); // no-warning |
77 | int *z = &a; |
78 | return *z; |
79 | } |
80 | |
81 | auto [globalA, globalB] = GetNumbers(); // no-warning, globals |
82 | auto [globalC, globalD] = GetNumbers(); // no-warning, globals |
83 | |
84 | void use_globals() { |
85 | globalA = 300; // no-warning |
86 | globalB = 200; |
87 | } |
88 | |
89 | struct Mytuple { |
90 | int a; |
91 | int b; |
92 | |
93 | template <size_t N> |
94 | int get() const { |
95 | if constexpr (N == 0) return a; |
96 | else if constexpr (N == 1) return b; |
97 | } |
98 | }; |
99 | |
100 | namespace std { |
101 | template<> |
102 | struct tuple_size<Mytuple> |
103 | : std::integral_constant<size_t, 2> {}; |
104 | |
105 | template<size_t N> |
106 | struct tuple_element<N, Mytuple> { |
107 | using type = int; |
108 | }; |
109 | } |
110 | |
111 | void no_warning_on_tuple_types_copy(Mytuple t) { |
112 | auto [a, b] = t; // no-warning |
113 | } |
114 | |
115 | Mytuple getMytuple(); |
116 | |
117 | void deconstruct_tuple_types_warning() { |
118 | auto [a, b] = getMytuple(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}} |
119 | } |
120 | |
121 | int deconstruct_tuple_types_no_warning() { |
122 | auto [a, b] = getMytuple(); // no-warning |
123 | return a + b; |
124 | } |
125 | |