1137ca91fSGeorge Karpenkov // RUN: %clang_analyze_cc1 -std=c++17 -analyzer-checker=core,deadcode -verify %s
2137ca91fSGeorge Karpenkov 
3137ca91fSGeorge Karpenkov typedef unsigned long size_t;
4137ca91fSGeorge Karpenkov 
5137ca91fSGeorge Karpenkov // Machinery required for custom structured bindings decomposition.
6137ca91fSGeorge Karpenkov namespace std {
7137ca91fSGeorge Karpenkov template <class T> class tuple_size;
8137ca91fSGeorge Karpenkov template <class T>
9137ca91fSGeorge Karpenkov  constexpr size_t tuple_size_v = tuple_size<T>::value;
10137ca91fSGeorge Karpenkov template <size_t I, class T> class tuple_element;
11137ca91fSGeorge Karpenkov 
12137ca91fSGeorge Karpenkov template<class T, T v>
13137ca91fSGeorge Karpenkov struct integral_constant {
14137ca91fSGeorge Karpenkov     static constexpr T value = v;
15137ca91fSGeorge Karpenkov     typedef T value_type;
16137ca91fSGeorge Karpenkov     typedef integral_constant type;
operator value_typestd::integral_constant17137ca91fSGeorge Karpenkov     constexpr operator value_type() const noexcept { return value; }
18137ca91fSGeorge Karpenkov };
19137ca91fSGeorge Karpenkov }
20137ca91fSGeorge Karpenkov 
21137ca91fSGeorge Karpenkov struct S {
22137ca91fSGeorge Karpenkov   int a;
23137ca91fSGeorge Karpenkov   double b;
SS24137ca91fSGeorge Karpenkov   S(int a, double b) : a(a), b(b) {};
25137ca91fSGeorge Karpenkov };
26137ca91fSGeorge Karpenkov 
27137ca91fSGeorge Karpenkov S GetNumbers();
28137ca91fSGeorge Karpenkov 
used_binding()29137ca91fSGeorge Karpenkov int used_binding() {
30137ca91fSGeorge Karpenkov     const auto [a, b] = GetNumbers(); // no-warning
31137ca91fSGeorge Karpenkov     return a + b;
32137ca91fSGeorge Karpenkov }
33137ca91fSGeorge Karpenkov 
no_warning_on_copy(S s)34137ca91fSGeorge Karpenkov void no_warning_on_copy(S s) {
35137ca91fSGeorge Karpenkov   // Copy constructor might have side effects.
36137ca91fSGeorge Karpenkov   const auto [a, b] = s; // no-warning
37137ca91fSGeorge Karpenkov }
38137ca91fSGeorge Karpenkov 
39137ca91fSGeorge Karpenkov 
unused_binding_ignored()40137ca91fSGeorge Karpenkov int unused_binding_ignored() {
41137ca91fSGeorge Karpenkov     const auto [a, b] = GetNumbers(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}}
42137ca91fSGeorge Karpenkov     return 0;
43137ca91fSGeorge Karpenkov }
44137ca91fSGeorge Karpenkov 
unused_binding_liveness_required()45137ca91fSGeorge Karpenkov int unused_binding_liveness_required() {
46137ca91fSGeorge Karpenkov     auto [a2, b2] = GetNumbers(); // expected-warning{{Value stored to '[a2, b2]' during its initialization is never read}}
47137ca91fSGeorge Karpenkov     a2 = 10;
48137ca91fSGeorge Karpenkov     b2 = 20;
49137ca91fSGeorge Karpenkov     return a2 + b2;
50137ca91fSGeorge Karpenkov }
51137ca91fSGeorge Karpenkov 
kill_one_binding()52137ca91fSGeorge Karpenkov int kill_one_binding() {
53137ca91fSGeorge Karpenkov   auto [a, b] = GetNumbers(); // no-warning
54137ca91fSGeorge Karpenkov   a = 100;
55137ca91fSGeorge Karpenkov   return a + b;
56137ca91fSGeorge Karpenkov 
57137ca91fSGeorge Karpenkov }
58137ca91fSGeorge Karpenkov 
kill_one_binding2()59137ca91fSGeorge Karpenkov int kill_one_binding2() {
60137ca91fSGeorge Karpenkov   auto [a, b] = GetNumbers(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}}
61137ca91fSGeorge Karpenkov   a = 100;
62137ca91fSGeorge Karpenkov   return a;
63137ca91fSGeorge Karpenkov }
64137ca91fSGeorge Karpenkov 
use_const_reference_bindings()65137ca91fSGeorge Karpenkov void use_const_reference_bindings() {
66137ca91fSGeorge Karpenkov   const auto &[a, b] = GetNumbers(); // no-warning
67137ca91fSGeorge Karpenkov }
68137ca91fSGeorge Karpenkov 
use_reference_bindings()69137ca91fSGeorge Karpenkov void use_reference_bindings() {
70137ca91fSGeorge Karpenkov   S s(0, 0);
71137ca91fSGeorge Karpenkov   auto &[a, b] = s; // no-warning
72137ca91fSGeorge Karpenkov   a = 200;
73137ca91fSGeorge Karpenkov }
74137ca91fSGeorge Karpenkov 
read_through_pointer()75137ca91fSGeorge Karpenkov int read_through_pointer() {
76137ca91fSGeorge Karpenkov   auto [a, b] = GetNumbers(); // no-warning
77137ca91fSGeorge Karpenkov   int *z = &a;
78137ca91fSGeorge Karpenkov   return *z;
79137ca91fSGeorge Karpenkov }
80137ca91fSGeorge Karpenkov 
81137ca91fSGeorge Karpenkov auto [globalA, globalB] = GetNumbers(); // no-warning, globals
82137ca91fSGeorge Karpenkov auto [globalC, globalD] = GetNumbers(); // no-warning, globals
83137ca91fSGeorge Karpenkov 
use_globals()84137ca91fSGeorge Karpenkov void use_globals() {
85137ca91fSGeorge Karpenkov   globalA = 300; // no-warning
86137ca91fSGeorge Karpenkov   globalB = 200;
87137ca91fSGeorge Karpenkov }
88137ca91fSGeorge Karpenkov 
89137ca91fSGeorge Karpenkov struct Mytuple {
90137ca91fSGeorge Karpenkov   int a;
91137ca91fSGeorge Karpenkov   int b;
92137ca91fSGeorge Karpenkov 
93137ca91fSGeorge Karpenkov   template <size_t N>
getMytuple94137ca91fSGeorge Karpenkov   int get() const {
95137ca91fSGeorge Karpenkov     if      constexpr (N == 0) return a;
96137ca91fSGeorge Karpenkov     else if constexpr (N == 1) return b;
97137ca91fSGeorge Karpenkov   }
98137ca91fSGeorge Karpenkov };
99137ca91fSGeorge Karpenkov 
100137ca91fSGeorge Karpenkov namespace std {
101137ca91fSGeorge Karpenkov     template<>
102137ca91fSGeorge Karpenkov     struct tuple_size<Mytuple>
103137ca91fSGeorge Karpenkov         : std::integral_constant<size_t, 2> {};
104137ca91fSGeorge Karpenkov 
105137ca91fSGeorge Karpenkov     template<size_t N>
106137ca91fSGeorge Karpenkov     struct tuple_element<N, Mytuple> {
107137ca91fSGeorge Karpenkov         using type = int;
108137ca91fSGeorge Karpenkov     };
109137ca91fSGeorge Karpenkov }
110137ca91fSGeorge Karpenkov 
no_warning_on_tuple_types_copy(Mytuple t)111137ca91fSGeorge Karpenkov void no_warning_on_tuple_types_copy(Mytuple t) {
112137ca91fSGeorge Karpenkov   auto [a, b] = t; // no-warning
113137ca91fSGeorge Karpenkov }
114137ca91fSGeorge Karpenkov 
115137ca91fSGeorge Karpenkov Mytuple getMytuple();
116137ca91fSGeorge Karpenkov 
deconstruct_tuple_types_warning()117137ca91fSGeorge Karpenkov void deconstruct_tuple_types_warning() {
118*a618d5e0Sisuckatcs   // The initializers reference the decomposed region, so the warning is not reported
119*a618d5e0Sisuckatcs   // FIXME: ideally we want to ignore that the initializers reference the decomposed region, and report the warning,
120*a618d5e0Sisuckatcs   // though the first step towards that is to handle DeadCode if the initializer is CXXConstructExpr.
121*a618d5e0Sisuckatcs   auto [a, b] = getMytuple(); // no-warning
122137ca91fSGeorge Karpenkov }
123137ca91fSGeorge Karpenkov 
deconstruct_tuple_types_no_warning()124137ca91fSGeorge Karpenkov int deconstruct_tuple_types_no_warning() {
125137ca91fSGeorge Karpenkov   auto [a, b] = getMytuple(); // no-warning
126137ca91fSGeorge Karpenkov   return a + b;
127137ca91fSGeorge Karpenkov }
128