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