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;
operator value_typestd::integral_constant17     constexpr operator value_type() const noexcept { return value; }
18 };
19 }
20 
21 struct S {
22   int a;
23   double b;
SS24   S(int a, double b) : a(a), b(b) {};
25 };
26 
27 S GetNumbers();
28 
used_binding()29 int used_binding() {
30     const auto [a, b] = GetNumbers(); // no-warning
31     return a + b;
32 }
33 
no_warning_on_copy(S s)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 
unused_binding_ignored()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 
unused_binding_liveness_required()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 
kill_one_binding()52 int kill_one_binding() {
53   auto [a, b] = GetNumbers(); // no-warning
54   a = 100;
55   return a + b;
56 
57 }
58 
kill_one_binding2()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 
use_const_reference_bindings()65 void use_const_reference_bindings() {
66   const auto &[a, b] = GetNumbers(); // no-warning
67 }
68 
use_reference_bindings()69 void use_reference_bindings() {
70   S s(0, 0);
71   auto &[a, b] = s; // no-warning
72   a = 200;
73 }
74 
read_through_pointer()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 
use_globals()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>
getMytuple94   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 
no_warning_on_tuple_types_copy(Mytuple t)111 void no_warning_on_tuple_types_copy(Mytuple t) {
112   auto [a, b] = t; // no-warning
113 }
114 
115 Mytuple getMytuple();
116 
deconstruct_tuple_types_warning()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 
deconstruct_tuple_types_no_warning()121 int deconstruct_tuple_types_no_warning() {
122   auto [a, b] = getMytuple(); // no-warning
123   return a + b;
124 }
125