Implement P0217R3 - C++17 structured bindings
authorJakub Jelinek <jakub@redhat.com>
Mon, 14 Nov 2016 07:54:50 +0000 (08:54 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 14 Nov 2016 07:54:50 +0000 (08:54 +0100)
Implement P0217R3 - C++17 structured bindings
* g++.dg/cpp1z/decomp1.C: New test.
* g++.dg/cpp1z/decomp2.C: New test.
* g++.dg/cpp1z/decomp3.C: New test.
* g++.dg/cpp1z/decomp4.C: New test.
* g++.dg/cpp1z/decomp5.C: New test.
* g++.dg/cpp1z/decomp6.C: New test.
* g++.dg/cpp1z/decomp7.C: New test.
* g++.dg/cpp1z/decomp8.C: New test.
* g++.dg/cpp1z/decomp9.C: New test.
* g++.dg/cpp1z/decomp10.C: New test.

Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r242378

gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1z/decomp1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp9.C [new file with mode: 0644]

index 5757bb4ca894e2f4249c27696006ca4902e58b47..385a2b65361b18c17f6d5fedfa23d065446ac3e0 100644 (file)
@@ -1,3 +1,18 @@
+2016-11-14  Jakub Jelinek  <jakub@redhat.com>
+           Jason Merrill  <jason@redhat.com>
+
+       Implement P0217R3 - C++17 structured bindings
+       * g++.dg/cpp1z/decomp1.C: New test.
+       * g++.dg/cpp1z/decomp2.C: New test.
+       * g++.dg/cpp1z/decomp3.C: New test.
+       * g++.dg/cpp1z/decomp4.C: New test.
+       * g++.dg/cpp1z/decomp5.C: New test.
+       * g++.dg/cpp1z/decomp6.C: New test.
+       * g++.dg/cpp1z/decomp7.C: New test.
+       * g++.dg/cpp1z/decomp8.C: New test.
+       * g++.dg/cpp1z/decomp9.C: New test.
+       * g++.dg/cpp1z/decomp10.C: New test.
+
 2016-11-13  Kugan Vivekanandarajah  <kuganv@linaro.org>
 
        * g++.dg/torture/pr78268.C: New test.
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp1.C b/gcc/testsuite/g++.dg/cpp1z/decomp1.C
new file mode 100644 (file)
index 0000000..98f6090
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+int a[2] = { 1, 2 };
+struct S { int a; signed char b; float c; } s = { 6, 7, 8.0f };
+
+int
+main ()
+{
+  auto & [ c, d ] = a;         // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ e, f ] = a;           // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ g, h, i ] = s;                // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ j, k, l ] = s;      // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  c++;
+  d++;
+  e += 6;
+  f += 7;
+  g++;
+  h++;
+  j += 10;
+  k += 11;
+  if (c != 2 || &c != &a[0]
+      || d != 3 || &d != &a[1]
+      || e != 7 || &e == &a[0]
+      || f != 9 || &f == &a[1]
+      || g != 7 || &g == &s.a
+      || h != 8 || &h == &s.b
+      || i != 8.0f || &i == &s.c
+      || j != 16 || &j != &s.a
+      || k != 18 || &k != &s.b
+      || l != 8.0f || &l != &s.c
+      || a[0] != 2 || a[1] != 3
+      || s.a != 16 || s.b != 18 || s.c != 8.0f)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp10.C b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
new file mode 100644 (file)
index 0000000..316cea9
--- /dev/null
@@ -0,0 +1,48 @@
+// { dg-options -std=c++1z }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A1 { int i,j; } a1;
+template<> struct std::tuple_size<A1> {  };
+void f1() { auto [ x ] = a1; } // { dg-error "decomposes into 2" }
+
+struct A2 { int i,j; } a2;
+template<> struct std::tuple_size<A2> { enum { value = 5 }; };
+void f2() { auto [ x ] = a2; } // { dg-error "decomposes into 5" }
+
+struct A3 { int i,j; } a3;
+template<> struct std::tuple_size<A3> { enum { value = 1 }; };
+void f3() { auto [ x ] = a3; } // { dg-error "get" }
+
+struct A3a { int i,j; int get(); } a3a;
+template<> struct std::tuple_size<A3a> { enum { value = 1 }; };
+void f3a() { auto [ x ] = a3a; }       // { dg-error "get<0>" }
+
+struct A3b { int i,j; } a3b;
+int get(A3b&&);
+template<> struct std::tuple_size<A3b> { enum { value = 1 }; };
+void f3b() { auto [ x ] = a3b; }       // { dg-error "get<0>" }
+
+struct A4 {
+  int ar[3];
+  template <int I> int& get() { return ar[I]; }
+} a4;
+template<> struct std::tuple_size<A4> { enum { value = 3 }; };
+template <int I> 
+void f4() { auto [ x, y, z ] = a4; }   // { dg-error "tuple_element" }
+
+struct A5 { } a5;
+template <int I> int& get(A5&& a);
+template<> struct std::tuple_size<A5> { enum { value = 3 }; };
+template <int I> 
+void f5() { auto [ x, y, z ] = a5; }   // { dg-error "tuple_element" }
+
+struct A6 { } a6;
+template <int I> int& get(A6&& a);
+template<> struct std::tuple_size<A6> { enum { value = 3 }; };
+template<> struct std::tuple_element<0, A6> { };
+template <int I> 
+void f6() { auto [ x, y, z ] = a6; }   // { dg-error "no type named .type" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp2.C b/gcc/testsuite/g++.dg/cpp1z/decomp2.C
new file mode 100644 (file)
index 0000000..5831fc7
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+typedef int V __attribute__((vector_size (4 * sizeof (int))));
+V a = (V) { 1, 2, 3, 4 };
+__complex__ double b = 5.0 + 6.0i;
+__complex__ int c = 7 + 8i;
+
+int
+main ()
+{
+  auto & [ d, e, f, g ] = a;   // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ h, i, j, k ] = a;     // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ l, m ] = b;           // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ n, o ] = b;         // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ p, q ] = c;         // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ r, s ] = c;           // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  d += 10;
+  e += 11;
+  f += 12;
+  g += 13;
+  h += 14;
+  i += 15;
+  j += 16;
+  k += 17;
+  l = l * 2.;
+  m = m * 3.;
+  n = n * 3.;
+  o = o * 2.;
+  p += 18;
+  q += 19;
+  r += 22;
+  s += 23;
+  if (d != 11 || &d != &a[0]
+      || e != 13 || &e != &a[1]
+      || f != 15 || &f != &a[2]
+      || g != 17 || &g != &a[3]
+      || h != 15 || &h == &a[0]
+      || i != 17 || &i == &a[1]
+      || j != 19 || &j == &a[2]
+      || k != 21 || &k == &a[3]
+      || l != 10.0 || &l == &__real__ b
+      || m != 18.0 || &m == &__imag__ b
+      || n != 15.0 || &n != &__real__ b
+      || o != 12.0 || &o != &__imag__ b
+      || p != 25 || &p != &__real__ c
+      || q != 27 || &q != &__imag__ c
+      || r != 29 || &r == &__real__ c
+      || s != 31 || &s == &__imag__ c
+      || a[0] != 11 || a[1] != 13 || a[2] != 15 || a[3] != 17
+      || b != 15.0 + 12.0i
+      || c != 25 + 27i)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp3.C b/gcc/testsuite/g++.dg/cpp1z/decomp3.C
new file mode 100644 (file)
index 0000000..a739d3a
--- /dev/null
@@ -0,0 +1,66 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A { int a, b; float c; };
+A &bar ();
+struct B { int d; };
+B baz ();
+
+void
+test (A &b, B c)
+{
+  int && [ d ] = c;                    // { dg-error "decomposition declaration cannot be declared with type 'int'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  char & [ e, f, ff ] { b };           // { dg-error "decomposition declaration cannot be declared with type 'char'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto&[g,h,i]=b;                      // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  decltype (auto) [ j ] = c;           // { dg-error "decomposition declaration cannot be declared with type 'decltype.auto.'" "" { target c++14 } }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+                                       // { dg-error "expected primary-expression before 'decltype'" "" { target c++11_down } .-2 }
+  auto & & && & [ m, n, o ] = b;       // { dg-error "multiple ref-qualifiers" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  constexpr auto [ p ] = c;            // { dg-error "decomposition declaration cannot be declared 'constexpr'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  friend auto [ q ] = c;               // { dg-error "'friend' used outside of class" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  typedef auto [ r ] = c;              // { dg-error "decomposition declaration cannot be declared 'typedef'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  inline auto [ s ] = c;               // { dg-error "decomposition declaration cannot be declared 'inline'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  __restrict auto [ t ] = c;           // { dg-error "invalid use of 'restrict'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  long long auto [ u ] = c;            // { dg-error "'long long' invalid for 'decomposition'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  virtual auto [ v ] = c;              // { dg-error "'virtual' outside class declaration" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  explicit auto [ w ] = c;             // { dg-error "'explicit' outside class declaration" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  static auto [ x ] = c;               // { dg-error "decomposition declaration cannot be declared 'static'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  extern auto [ y ] { c };             // { dg-error "decomposition declaration cannot be declared 'extern'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+}
+
+void
+test2 (auto & [ p ] = bar ())          // { dg-error "'p' was not declared in this scope" }
+{
+}
+
+int arr[4];
+
+void
+test3 (A &b, B c)
+{
+  auto [ d, e, f ] = arr;              // { dg-error "only 3 names provided while 'int .4.' decomposes into 4 elements" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto & [ g, h, i, j, k ] = arr;      // { dg-error "5 names provided while 'int .4.' decomposes into 4 elements" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ l, m ] = b;                   // { dg-error "only 2 names provided while 'A' decomposes into 3 elements" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto & [ n, o, p, q ] = b;           // { dg-error "4 names provided while 'A' decomposes into 3 elements" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [] { c };                       // { dg-error "empty decomposition declaration" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ r, s ] = c;                   // { dg-error "2 names provided while 'B' decomposes into 1 elements" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp4.C b/gcc/testsuite/g++.dg/cpp1z/decomp4.C
new file mode 100644 (file)
index 0000000..95a02ec
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A { int a; struct { int b; }; };
+struct B { int a; union { int c; long d; }; };
+struct C { int a; private: int b; };
+struct D { int a; private: static int b; };
+struct E { protected: int a; };
+struct F { int a; };
+struct G : public F { int b; };
+struct H { int b; };
+struct I : public F, H {};
+
+void
+test (A &a, B &b, C &c, D &d, E &e, F &f, G &g, H &h, I &i)
+{
+  auto [ j ] = a;                      // { dg-error "cannot decompose class type 'A' because it has an anonymous struct member" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ k ] { b };                    // { dg-error "cannot decompose class type 'B' because it has an anonymous union member" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ l ] = c;                      // { dg-error "cannot decompose non-public member 'C::b' of 'C'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ m ] = d;                      // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  auto [ n ] { e };                    // { dg-error "cannot decompose non-public member 'E::a' of 'E'" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ o ] { f };                    // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  auto & [ p ] { g };                  // { dg-error "cannot decompose class type 'G': both it and its base class 'F' have non-static data members" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ q ] { h };                    // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  auto [ r ] { i };                    // { dg-error "cannot decompose class type 'I': its base classes 'F' and 'H' have non-static data members" }
+                                       // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp5.C b/gcc/testsuite/g++.dg/cpp1z/decomp5.C
new file mode 100644 (file)
index 0000000..86b2c22
--- /dev/null
@@ -0,0 +1,40 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct A { int i; long long j; } a[64];
+
+int
+main ()
+{
+  int i = 0;
+  for (auto &x : a)
+    {
+      x.i = i;
+      x.j = 2 * i++;
+    }
+  for (auto & [ x, y ] : a)    // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 2;
+      y += 3;
+    }
+  i = 0;
+  for (const auto [ u, v ] : a)        // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      if (u != i + 2 || v != 2 * i++ + 3)
+       __builtin_abort ();
+    }
+  i = 0;
+  for (auto [ x, y ] : a)      // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 4;
+      y += 5;
+      if (x != i + 6 || y != 2 * i++ + 8)
+       __builtin_abort ();
+    }
+  i = 0;
+  for (const auto x : a)
+    {
+      if (x.i != i + 2 || x.j != 2 * i++ + 3)
+       __builtin_abort ();
+    }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp6.C b/gcc/testsuite/g++.dg/cpp1z/decomp6.C
new file mode 100644 (file)
index 0000000..ed6fce4
--- /dev/null
@@ -0,0 +1,92 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+int ccnt, dcnt, cccnt, tccnt;
+
+struct A
+{
+  A () : a (6) { ccnt++; }
+  ~A () { dcnt++; }
+  explicit A (const A &x) : a (x.a) { cccnt++; }
+  template <typename T>
+  A (const T &x) : a (x.a) { tccnt++; }
+  int a;
+};
+
+int
+main ()
+{
+  if (ccnt || dcnt || cccnt || tccnt)
+    __builtin_abort ();
+  {
+    A a[6];
+    if (ccnt != 6 || dcnt || cccnt || tccnt)
+      __builtin_abort ();
+    {
+      auto [b,c,d,e,f,g] = a;          // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+      if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
+       __builtin_abort ();
+      b.a++;
+      c.a += 2;
+      f.a += 3;
+      if (b.a != 7 || c.a != 8 || d.a != 6 || e.a != 6 || f.a != 9 || g.a != 6)
+       __builtin_abort ();
+      if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == &a[4] || &g == &a[5])
+       __builtin_abort ();
+      {
+       auto&[ h, i, j, k, l, m ] = a;  // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+       if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
+         __builtin_abort ();
+       j.a += 4;
+       k.a += 5;
+       m.a += 6;
+       if (a[0].a != 6 || a[1].a != 6 || a[2].a != 10 || a[3].a != 11 || a[4].a != 6 || a[5].a != 12)
+         __builtin_abort ();
+       if (&h != &a[0] || &i != &a[1] || &j != &a[2] || &k != &a[3] || &l != &a[4] || &m != &a[5])
+         __builtin_abort ();
+      }
+      if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
+       __builtin_abort ();
+    }
+    if (ccnt != 6 || dcnt != 6 || cccnt || tccnt != 6)
+      __builtin_abort ();
+  }
+  if (ccnt != 6 || dcnt != 12 || cccnt || tccnt != 6)
+    __builtin_abort ();
+
+  {
+    A a[6];
+    if (ccnt != 12 || dcnt != 12 || cccnt || tccnt != 6)
+      __builtin_abort ();
+    {
+      auto [b,c,d,e,f,g] { a };                // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+      if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
+       __builtin_abort ();
+      b.a++;
+      c.a += 2;
+      f.a += 3;
+      if (b.a != 7 || c.a != 8 || d.a != 6 || e.a != 6 || f.a != 9 || g.a != 6)
+       __builtin_abort ();
+      if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == &a[4] || &g == &a[5])
+       __builtin_abort ();
+      {
+       auto&[ h, i, j, k, l, m ] {a};  // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+       if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
+         __builtin_abort ();
+       j.a += 4;
+       k.a += 5;
+       m.a += 6;
+       if (a[0].a != 6 || a[1].a != 6 || a[2].a != 10 || a[3].a != 11 || a[4].a != 6 || a[5].a != 12)
+         __builtin_abort ();
+       if (&h != &a[0] || &i != &a[1] || &j != &a[2] || &k != &a[3] || &l != &a[4] || &m != &a[5])
+         __builtin_abort ();
+      }
+      if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
+       __builtin_abort ();
+    }
+    if (ccnt != 12 || dcnt != 18 || cccnt != 6 || tccnt != 6)
+      __builtin_abort ();
+  }
+  if (ccnt != 12 || dcnt != 24 || cccnt != 6 || tccnt != 6)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp7.C b/gcc/testsuite/g++.dg/cpp1z/decomp7.C
new file mode 100644 (file)
index 0000000..d366ade
--- /dev/null
@@ -0,0 +1,60 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+int a[2] = { 1, 2 };
+int b[2] = { 4, 5 };
+struct S { int a; signed char b; float c; } sa = { 6, 7, 8.0f };
+S sb = { 9, 10, 11.0f };
+
+template <typename T, typename U>
+void
+foo (T &x, U &y)
+{
+  auto & [ c, d ] = a;         // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ e, f ] = a;           // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ g, h, i ] = sa;       // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ j, k, l ] = sa;     // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ m, n ] = x;         // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ o, p ] = x;           // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ q, r, s ] = y;                // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ t, u, v ] = y;      // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  c += 1;
+  e += 2;
+  g += 3;
+  j += 4;
+  m += 5;
+  o += 6;
+  q += 7;
+  t += 8;
+  if (c != 2 || &c != &a[0]
+      || d != 2 || &d != &a[1]
+      || e != 3 || &e == &a[0]
+      || f != 2 || &f == &a[1]
+      || g != 9 || &g == &sa.a
+      || h != 7 || &h == &sa.b
+      || i != 8.0f || &i == &sa.c
+      || j != 10 || &j != &sa.a
+      || k != 7 || &k != &sa.b
+      || l != 8.0f || &l != &sa.c
+      || m != 9 || &m != &b[0]
+      || n != 5 || &n != &b[1]
+      || o != 10 || &o == &b[0]
+      || p != 5 || &p == &b[1]
+      || q != 16 || &q == &sb.a
+      || r != 10 || &r == &sb.b
+      || s != 11.0f || &s == &sb.c
+      || t != 17 || &t != &sb.a
+      || u != 10 || &u != &sb.b
+      || v != 11.0f || &v != &sb.c
+      || a[0] != 2 || a[1] != 2
+      || sa.a != 10 || sa.b != 7 || sa.c != 8.0f
+      || b[0] != 9 || b[1] != 5
+      || sb.a != 17 || sb.b != 10 || sb.c != 11.0f)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  foo (b, sb);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp8.C b/gcc/testsuite/g++.dg/cpp1z/decomp8.C
new file mode 100644 (file)
index 0000000..9e1ea5d
--- /dev/null
@@ -0,0 +1,88 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct A { int i; long long j; } a[64];
+A b[32];
+
+template <typename T>
+void
+foo (T &b)
+{
+  int i = 0;
+  for (auto &x : a)
+    {
+      x.i = i;
+      x.j = 2 * i++;
+    }
+  for (auto & [ x, y ] : a)    // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 2;
+      y += 3;
+    }
+  i = 0;
+  for (const auto [ u, v ] : a)        // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      if (u != i + 2 || v != 2 * i++ + 3)
+       __builtin_abort ();
+    }
+  i = 0;
+  for (auto [ x, y ] : a)      // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 4;
+      y += 5;
+      if (x != i + 6 || y != 2 * i++ + 8)
+       __builtin_abort ();
+    }
+  i = 0;
+  for (const auto x : a)
+    {
+      if (x.i != i + 2 || x.j != 2 * i++ + 3)
+       __builtin_abort ();
+    }
+  i = 0;
+  for (auto &x : b)
+    {
+      x.i = i;
+      x.j = 2 * i++;
+    }
+  for (auto & [ x, y ] : b)    // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x -= 2;
+      y -= 3;
+    }
+  i = 0;
+  for (const auto [ u, v ] : b)        // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      if (u != i - 2 || v != 2 * i++ - 3)
+       __builtin_abort ();
+    }
+  i = 0;
+  for (auto [ x, y ] : b)      // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x -= 4;
+      y -= 5;
+      if (x != i - 6 || y != 2 * i++ - 8)
+       __builtin_abort ();
+    }
+  i = 0;
+  for (const auto x : b)
+    {
+      if (x.i != i - 2 || x.j != 2 * i++ - 3)
+       __builtin_abort ();
+    }
+}
+
+int
+main ()
+{
+  foo (b);
+  for (int i = 0; i < 64; i++)
+    {
+      if (a[i].i != i + 2 || a[i].j != 2 * i + 3)
+       __builtin_abort ();
+      if (i >= 32)
+       continue;
+      if (b[i].i != i - 2 || b[i].j != 2 * i - 3)
+       __builtin_abort ();
+    }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp9.C b/gcc/testsuite/g++.dg/cpp1z/decomp9.C
new file mode 100644 (file)
index 0000000..f7c6f56
--- /dev/null
@@ -0,0 +1,47 @@
+// { 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);
+  }
+}