reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
// RUN: %clang_analyze_cc1 -std=c++17 -analyzer-checker=core,deadcode -verify %s

typedef unsigned long size_t;

// Machinery required for custom structured bindings decomposition.
namespace std {
template <class T> class tuple_size;
template <class T>
 constexpr size_t tuple_size_v = tuple_size<T>::value;
template <size_t I, class T> class tuple_element;

template<class T, T v>
struct integral_constant {
    static constexpr T value = v;
    typedef T value_type;
    typedef integral_constant type;
    constexpr operator value_type() const noexcept { return value; }
};
}

struct S {
  int a;
  double b;
  S(int a, double b) : a(a), b(b) {};
};

S GetNumbers();

int used_binding() {
    const auto [a, b] = GetNumbers(); // no-warning
    return a + b; 
}

void no_warning_on_copy(S s) {
  // Copy constructor might have side effects.
  const auto [a, b] = s; // no-warning
}


int unused_binding_ignored() {
    const auto [a, b] = GetNumbers(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}}
    return 0;
}

int unused_binding_liveness_required() {
    auto [a2, b2] = GetNumbers(); // expected-warning{{Value stored to '[a2, b2]' during its initialization is never read}}
    a2 = 10;
    b2 = 20;
    return a2 + b2;
}

int kill_one_binding() {
  auto [a, b] = GetNumbers(); // no-warning
  a = 100;
  return a + b;

}

int kill_one_binding2() {
  auto [a, b] = GetNumbers(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}}
  a = 100;
  return a;
}

void use_const_reference_bindings() {
  const auto &[a, b] = GetNumbers(); // no-warning
}

void use_reference_bindings() {
  S s(0, 0);
  auto &[a, b] = s; // no-warning
  a = 200;
}

int read_through_pointer() {
  auto [a, b] = GetNumbers(); // no-warning
  int *z = &a;
  return *z;
}

auto [globalA, globalB] = GetNumbers(); // no-warning, globals
auto [globalC, globalD] = GetNumbers(); // no-warning, globals

void use_globals() {
  globalA = 300; // no-warning
  globalB = 200;
}

struct Mytuple {
  int a;
  int b;

  template <size_t N>
  int get() const {
    if      constexpr (N == 0) return a;
    else if constexpr (N == 1) return b;
  }
};

namespace std {
    template<>
    struct tuple_size<Mytuple>
        : std::integral_constant<size_t, 2> {};

    template<size_t N>
    struct tuple_element<N, Mytuple> {
        using type = int;
    };
}

void no_warning_on_tuple_types_copy(Mytuple t) {
  auto [a, b] = t; // no-warning
}

Mytuple getMytuple();

void deconstruct_tuple_types_warning() {
  auto [a, b] = getMytuple(); // expected-warning{{Value stored to '[a, b]' during its initialization is never read}}
}

int deconstruct_tuple_types_no_warning() {
  auto [a, b] = getMytuple(); // no-warning
  return a + b;
}