// { dg-do run }
// { dg-options -std=c++1z }

#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)

namespace std {
  template<typename T> struct tuple_size;
  template<int, typename> struct tuple_element;
}

struct A {
  int i;
  template <int I> int& get() { return i; }
};

template<> struct std::tuple_size<A> { static const int value = 2; };
template<int I> struct std::tuple_element<I,A> { using type = int; };

struct B {
  int i;
};
template <int I> int& get(B&& b) { return b.i; }
template <int I> int& get(B& b) { return b.i; }

template<> struct std::tuple_size<B> { static const int value = 2; };
template<int I> struct std::tuple_element<I,B> { using type = int; };

int main()
{
  {
    A a = { 42 };
    auto& [ x, y ] = a;
    assert (&x == &y && &x == &a.i && x == 42);

    auto [ x2, y2 ] = a;
    assert (&x2 == &y2 && &x2 != &a.i && x2 == 42);
  }

  {
    B b = { 42 };
    auto& [ x, y ] = b;
    assert (&x == &y && &x == &b.i && x == 42);

    auto [ x2, y2 ] = b;
    assert (&x2 == &y2 && &x2 != &b.i && x2 == 42);
  }
}
