P1091R3 - Extending structured bindings to be more like var decls P1381R1 - Reference...
authorJakub Jelinek <jakub@gcc.gnu.org>
Wed, 29 May 2019 07:44:50 +0000 (09:44 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 29 May 2019 07:44:50 +0000 (09:44 +0200)
P1091R3 - Extending structured bindings to be more like var decls
P1381R1 - Reference capture of structured bindings
* decl.c (cp_maybe_mangle_decomp): Handle TREE_STATIC decls even at
function scope.
(cp_finish_decomp): Copy over various decl properties from decl to
v[i] in the tuple case.
(grokdeclarator): Allow static, thread_local and __thread for C++2a
and use pedwarn instead of error for older standard revisions.
Make other structured binding diagnostic messages more i18n friendly.

* g++.dg/cpp1z/decomp3.C (test): For static, expect only warning
instead of error and only for c++17_down.  Add a thread_local test.
(z2): Add a __thread test.
* g++.dg/cpp2a/decomp1.C: New test.
* g++.dg/cpp2a/decomp1-aux.cc: New file.
* g++.dg/cpp2a/decomp2.C: New test.
* g++.dg/cpp2a/decomp3.C: New test.

From-SVN: r271730

gcc/cp/decl.c
gcc/testsuite/g++.dg/cpp1z/decomp3.C
gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/decomp1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/decomp2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/decomp3.C [new file with mode: 0644]

index 2bb50e474786130c55bc15bc3efbb6f9cecc048c..99d75574d51594962c71fba60591718b9a30f3ce 100644 (file)
@@ -7626,7 +7626,7 @@ cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count)
 {
   if (!processing_template_decl
       && !error_operand_p (decl)
-      && DECL_NAMESPACE_SCOPE_P (decl))
+      && TREE_STATIC (decl))
     {
       auto_vec<tree, 16> v;
       v.safe_grow (count);
@@ -7857,8 +7857,27 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
              DECL_HAS_VALUE_EXPR_P (v[i]) = 0;
            }
          if (!processing_template_decl)
-           cp_finish_decl (v[i], init, /*constexpr*/false,
-                           /*asm*/NULL_TREE, LOOKUP_NORMAL);
+           {
+             TREE_PUBLIC (v[i]) = TREE_PUBLIC (decl);
+             TREE_STATIC (v[i]) = TREE_STATIC (decl);
+             DECL_COMMON (v[i]) = DECL_COMMON (decl);
+             DECL_COMDAT (v[i]) = DECL_COMDAT (decl);
+             if (TREE_STATIC (v[i]))
+               {
+                 CP_DECL_THREAD_LOCAL_P (v[i])
+                   = CP_DECL_THREAD_LOCAL_P (decl);
+                 set_decl_tls_model (v[i], DECL_TLS_MODEL (decl));
+                 if (DECL_ONE_ONLY (decl))
+                   make_decl_one_only (v[i], cxx_comdat_group (v[i]));
+                 if (TREE_PUBLIC (decl))
+                   DECL_WEAK (v[i]) = DECL_WEAK (decl);
+                 DECL_VISIBILITY (v[i]) = DECL_VISIBILITY (decl);
+                 DECL_VISIBILITY_SPECIFIED (v[i])
+                   = DECL_VISIBILITY_SPECIFIED (decl);
+               }
+             cp_finish_decl (v[i], init, /*constexpr*/false,
+                             /*asm*/NULL_TREE, LOOKUP_NORMAL);
+           }
        }
       /* Ignore reads from the underlying decl performed during initialization
         of the individual variables.  If those will be read, we'll mark
@@ -11067,40 +11086,43 @@ grokdeclarator (const cp_declarator *declarator,
                        ? declarator->declarator->id_loc : declarator->id_loc);
       if (inlinep)
        error_at (declspecs->locations[ds_inline],
-                 "structured binding declaration cannot be %<inline%>");
+                 "structured binding declaration cannot be %qs", "inline");
       if (typedef_p)
        error_at (declspecs->locations[ds_typedef],
-                 "structured binding declaration cannot be %<typedef%>");
+                 "structured binding declaration cannot be %qs", "typedef");
       if (constexpr_p)
        error_at (declspecs->locations[ds_constexpr], "structured "
-                 "binding declaration cannot be %<constexpr%>");
-      if (thread_p)
-       error_at (declspecs->locations[ds_thread],
-                 "structured binding declaration cannot be %qs",
-                 declspecs->gnu_thread_keyword_p
-                 ? "__thread" : "thread_local");
+                 "binding declaration cannot be %qs", "constexpr");
+      if (thread_p && cxx_dialect < cxx2a)
+       pedwarn (declspecs->locations[ds_thread], 0,
+                "structured binding declaration can be %qs only in "
+                "%<-std=c++2a%> or %<-std=gnu++2a%>",
+                declspecs->gnu_thread_keyword_p
+                ? "__thread" : "thread_local");
       if (concept_p)
        error_at (declspecs->locations[ds_concept],
-                 "structured binding declaration cannot be %<concept%>");
+                 "structured binding declaration cannot be %qs", "concept");
       switch (storage_class)
        {
        case sc_none:
          break;
        case sc_register:
-         error_at (loc, "structured binding declaration cannot be "
-                   "%<register%>");
+         error_at (loc, "structured binding declaration cannot be %qs",
+                   "register");
          break;
        case sc_static:
-         error_at (loc, "structured binding declaration cannot be "
-                   "%<static%>");
+         if (cxx_dialect < cxx2a)
+           pedwarn (loc, 0,
+                    "structured binding declaration can be %qs only in "
+                    "%<-std=c++2a%> or %<-std=gnu++2a%>", "static");
          break;
        case sc_extern:
-         error_at (loc, "structured binding declaration cannot be "
-                   "%<extern%>");
+         error_at (loc, "structured binding declaration cannot be %qs",
+                   "extern");
          break;
        case sc_mutable:
-         error_at (loc, "structured binding declaration cannot be "
-                   "%<mutable%>");
+         error_at (loc, "structured binding declaration cannot be %qs",
+                   "mutable");
          break;
        case sc_auto:
          error_at (loc, "structured binding declaration cannot be "
@@ -11126,12 +11148,12 @@ grokdeclarator (const cp_declarator *declarator,
       inlinep = 0;
       typedef_p = 0;
       constexpr_p = 0;
-      thread_p = 0;
       concept_p = 0;
-      storage_class = sc_none;
-      staticp = 0;
-      declspecs->storage_class = sc_none;
-      declspecs->locations[ds_thread] = UNKNOWN_LOCATION;
+      if (storage_class != sc_static)
+       {
+         storage_class = sc_none;
+         declspecs->storage_class = sc_none;
+       }
     }
 
   /* Static anonymous unions are dealt with here.  */
index 95e9f376dd22e27853ed19fb74c5b5815211abeb..a9b23b08d83afc229689ffa135aa2a0a32630de7 100644 (file)
@@ -35,12 +35,17 @@ test (A &b, B c)
                                        // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
   explicit auto [ w ] = c;             // { dg-error "'explicit' outside class declaration" }
                                        // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
-  static auto [ x ] = c;               // { dg-error "structured binding declaration cannot be 'static'" }
+  static auto [ x ] = c;               // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } }
                                        // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
   extern auto [ y ] { c };             // { dg-error "structured binding declaration cannot be 'extern'" }
                                        // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
+  thread_local auto [ z ] = c;         // { dg-warning "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } }
+                                       // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
 }
 
+__thread auto [ z2 ] = B ();           // { dg-warning "structured binding declaration can be '__thread' only in" "" { target c++17_down } }
+                                       // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
+
 void
 test2 (auto & [ p ] = bar ())          // { dg-error "'p' was not declared in this scope" }
 {                                      // { dg-warning "auto" "" { target { ! concepts } } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc b/gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc
new file mode 100644 (file)
index 0000000..2aaa2df
--- /dev/null
@@ -0,0 +1,52 @@
+// P1091R3
+// { dg-do compile { target { c++17 && c++14_down } } }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A {
+  int i;
+  A(int x) : i(x) {}
+  template <int I> int& get() { return i; }
+};
+struct B { int a, b, c; };
+
+template<> struct std::tuple_size<A> { static const int value = 2; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+B s = { 1, 2, 3 };
+
+#line 1
+static auto [ d, e, f ] = s;
+static auto [ g, h ] = A (42);
+
+int &
+foo (int x)
+{
+  switch (x)
+    {
+    case 0: return d;
+    case 1: return e;
+    case 2: return f;
+    case 3: return g;
+    default: return h;
+    }
+}
+
+int
+bar (int x)
+{
+#line 3
+  static auto [ m, n, o ] = s;
+  static auto [ p, q ] = A (43);
+  switch (x)
+    {
+    case 0: return ++m;
+    case 1: return ++n;
+    case 2: return ++o;
+    case 3: return ++p;
+    default: return ++q;
+    }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp1.C b/gcc/testsuite/g++.dg/cpp2a/decomp1.C
new file mode 100644 (file)
index 0000000..7f7dab5
--- /dev/null
@@ -0,0 +1,92 @@
+// P1091R3
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+// { dg-additional-sources decomp1-aux.cc }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A {
+  int i;
+  A(int x) : i(x) {}
+  template <int I> int& get() { return i; }
+};
+struct B { int a, b, c; };
+
+template<> struct std::tuple_size<A> { static const int value = 2; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+extern int &foo (int);
+extern int bar (int);
+extern B s;
+extern "C" void abort ();
+B t = { 4, 5, 6 };
+
+static auto [ d, e, f ] = t;   // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } }
+                               // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+static auto [ g, h ] = A (44); // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } }
+                               // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1  }
+// The following warnings are in decomp1-aux.cc with #line directive.
+// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 1 }
+// { dg-warning "structured bindings only available with" "" { target c++14_down } 1 }
+// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 2 }
+// { dg-warning "structured bindings only available with" "" { target c++14_down } 2 }
+// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 3 }
+// { dg-warning "structured bindings only available with" "" { target c++14_down } 3 }
+// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 4 }
+// { dg-warning "structured bindings only available with" "" { target c++14_down } 4 }
+
+int &
+baz (int x)
+{
+  switch (x)
+    {
+    case 0: return d;
+    case 1: return e;
+    case 2: return f;
+    case 3: return g;
+    default: return h;
+    }
+}
+
+int
+qux (int x)
+{
+  static auto [ m, n, o ] = t; // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } }
+                               // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1  }
+  static auto [ p, q ] = A (45);       // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } }
+                               // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1  }
+  switch (x)
+    {
+    case 0: return ++m;
+    case 1: return ++n;
+    case 2: return ++o;
+    case 3: return ++p;
+    default: return ++q;
+    }
+}
+
+int
+main ()
+{
+  int *a[10];
+  for (int i = 0; i < 5; ++i)
+    {
+      a[i] = &foo (i);
+      a[i + 5] = &baz (i);
+    }
+  for (int i = 0; i < 10; ++i)
+    for (int j = i + 1; j < 10; ++j)
+      if (a[i] == a[j] && (j != i + 1 || (i % 5) != 3))
+       abort ();
+  if (a[1] != a[0] + 1 || a[2] != a[0] + 2 || a[4] != a[3]
+      || a[6] != a[5] + 1 || a[7] != a[5] + 2 || a[9] != a[8])
+    abort ();
+  int b[] = { 1, 2, 3, 43, 43 + 6, 4, 5, 6, 45, 45 + 11 };
+  for (int i = 0; i < 10; ++i)
+    for (int j = 0; j < 3 + i; ++j)
+      if ((i < 5 ? bar (i) : qux (i - 5)) != b[i] + 1 + j)
+       abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp2.C b/gcc/testsuite/g++.dg/cpp2a/decomp2.C
new file mode 100644 (file)
index 0000000..9149d02
--- /dev/null
@@ -0,0 +1,76 @@
+// P1091R3
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+// { dg-require-effective-target tls }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A {
+  int i;
+  A(int x) : i(x) {}
+  template <int I> int& get() { return i; }
+};
+struct B { int a, b, c; };
+
+template<> struct std::tuple_size<A> { static const int value = 2; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+extern "C" void abort ();
+B t = { 4, 5, 6 };
+
+thread_local auto [ d, e, f ] = t;     // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } }
+                                       // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+thread_local auto [ g, h ] = A (44);   // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } }
+                                       // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1  }
+
+int &
+baz (int x)
+{
+  switch (x)
+    {
+    case 0: return d;
+    case 1: return e;
+    case 2: return f;
+    case 3: return g;
+    default: return h;
+    }
+}
+
+int
+qux (int x)
+{
+  thread_local auto [ m, n, o ] = t;   // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } }
+                                       // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1  }
+  thread_local auto [ p, q ] = A (45); // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } }
+                                       // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1  }
+  switch (x)
+    {
+    case 0: return ++m;
+    case 1: return ++n;
+    case 2: return ++o;
+    case 3: return ++p;
+    default: return ++q;
+    }
+}
+
+int
+main ()
+{
+  int *a[5];
+  for (int i = 0; i < 5; ++i)
+    a[i] = &baz (i);
+  for (int i = 0; i < 5; ++i)
+    for (int j = i + 1; j < 5; ++j)
+      if (a[i] == a[j] && (j != i + 1 || i != 3))
+       abort ();
+  if (a[1] != a[0] + 1 || a[2] != a[0] + 2 || a[4] != a[3])
+    abort ();
+  int b[] = { 4, 5, 6, 45, 45 + 6 };
+  for (int i = 0; i < 5; ++i)
+    for (int j = 0; j < 3 + i; ++j)
+      if (qux (i) != b[i] + 1 + j)
+       abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp3.C b/gcc/testsuite/g++.dg/cpp2a/decomp3.C
new file mode 100644 (file)
index 0000000..1afaefd
--- /dev/null
@@ -0,0 +1,26 @@
+// P1381R1
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct Foo { int a : 1; int b; };
+
+int main() {
+  auto[a, b] = Foo();                  // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+
+  auto f1 = [&] { return a; };         // { dg-error "cannot bind bitfield" }
+  auto f2 = [&a = a] { return a; };    // { dg-error "cannot bind bitfield" }
+                                       // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } .-1 }
+  auto f3 = [&a] { return a; };                // { dg-error "cannot bind bitfield" }
+
+  auto g1 = [&] { return b; };
+  auto g2 = [&b = b] { return b; };    // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } }
+  auto g3 = [&b] { return b; };
+
+  auto h1 = [=] { return a; };
+  auto h2 = [a = a] { return a; };     // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } }
+  auto h3 = [a] { return a; };
+
+  auto i1 = [=] { return b; };
+  auto i2 = [b = b] { return b; };     // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } }
+  auto i3 = [b] { return b; };
+}