Implement P0195R2, C++17 variadic using.
authorJason Merrill <jason@redhat.com>
Mon, 9 Jan 2017 21:51:08 +0000 (16:51 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 9 Jan 2017 21:51:08 +0000 (16:51 -0500)
* parser.c (cp_parser_using_declaration): Handle ellipsis and comma.
* pt.c (tsubst_decl): Handle pack expansion in USING_DECL_SCOPE.
* error.c (dump_decl): Likewise.

From-SVN: r244246

gcc/cp/ChangeLog
gcc/cp/cp-tree.def
gcc/cp/error.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/using2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/using3.C [new file with mode: 0644]

index 78bcd3f151940f1df1fd4ee012b0863af1d8419d..5a84068e1dfacb45755f797b224c7a79b32d881c 100644 (file)
@@ -1,3 +1,10 @@
+2017-01-09  Jason Merrill  <jason@redhat.com>
+
+       Implement P0195R2, C++17 variadic using.
+       * parser.c (cp_parser_using_declaration): Handle ellipsis and comma.
+       * pt.c (tsubst_decl): Handle pack expansion in USING_DECL_SCOPE.
+       * error.c (dump_decl): Likewise.
+
 2017-01-09  Jakub Jelinek  <jakub@redhat.com>
 
        PR translation/79019
index 038227bf58403049c0e36c284a2edc9962b52190..ff4f4ef4698739487547b3d20153fa6cddaa90cd 100644 (file)
@@ -199,7 +199,8 @@ DEFTREECODE (BOUND_TEMPLATE_TEMPLATE_PARM, "bound_template_template_parm",
 DEFTREECODE (UNBOUND_CLASS_TEMPLATE, "unbound_class_template", tcc_type, 0)
 
 /* A using declaration.  USING_DECL_SCOPE contains the specified
-   scope.  In a member using decl, unless DECL_DEPENDENT_P is true,
+   scope.  In a variadic using-declaration, this is a TYPE_PACK_EXPANSION.
+   In a member using decl, unless DECL_DEPENDENT_P is true,
    USING_DECL_DECLS contains the _DECL or OVERLOAD so named.  This is
    not an alias, but is later expanded into multiple aliases.  */
 DEFTREECODE (USING_DECL, "using_decl", tcc_declaration, 0)
index fde84997cbabece020e3faefbd9b28736d226f9d..72044a9013cb13075b62612c1a8e003995d3a42a 100644 (file)
@@ -1268,10 +1268,21 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
       break;
 
     case USING_DECL:
-      pp_cxx_ws_string (pp, "using");
-      dump_type (pp, USING_DECL_SCOPE (t), flags);
-      pp_cxx_colon_colon (pp);
-      dump_decl (pp, DECL_NAME (t), flags);
+      {
+       pp_cxx_ws_string (pp, "using");
+       tree scope = USING_DECL_SCOPE (t);
+       bool variadic = false;
+       if (PACK_EXPANSION_P (scope))
+         {
+           scope = PACK_EXPANSION_PATTERN (scope);
+           variadic = true;
+         }
+       dump_type (pp, scope, flags);
+       pp_cxx_colon_colon (pp);
+       dump_decl (pp, DECL_NAME (t), flags);
+       if (variadic)
+         pp_cxx_ws_string (pp, "...");
+      }
       break;
 
     case STATIC_ASSERT:
index e8c06424e29f515c0aeca26d017025bdd476904d..aa045c439b336e31e0594f38fe6334f24afe0ecf 100644 (file)
@@ -18372,6 +18372,7 @@ cp_parser_using_declaration (cp_parser* parser,
       /* Look for the `using' keyword.  */
       cp_parser_require_keyword (parser, RID_USING, RT_USING);
       
+ again:
       /* Peek at the next token.  */
       token = cp_lexer_peek_token (parser->lexer);
       /* See if it's `typename'.  */
@@ -18438,6 +18439,16 @@ cp_parser_using_declaration (cp_parser* parser,
       if (!cp_parser_parse_definitely (parser))
        return false;
     }
+  else if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+    {
+      cp_token *ell = cp_lexer_consume_token (parser->lexer);
+      if (cxx_dialect < cxx1z
+         && !in_system_header_at (ell->location))
+       pedwarn (ell->location, 0,
+                "pack expansion in using-declaration only available "
+                "with -std=c++1z or -std=gnu++1z");
+      qscope = make_pack_expansion (qscope);
+    }
 
   /* The function we call to handle a using-declaration is different
      depending on what scope we are in.  */
@@ -18455,7 +18466,7 @@ cp_parser_using_declaration (cp_parser* parser,
       if (at_class_scope_p ())
        {
          /* Create the USING_DECL.  */
-         decl = do_class_using_decl (parser->scope, identifier);
+         decl = do_class_using_decl (qscope, identifier);
 
          if (decl && typename_p)
            USING_DECL_TYPENAME_P (decl) = 1;
@@ -18490,6 +18501,17 @@ cp_parser_using_declaration (cp_parser* parser,
        }
     }
 
+  if (!access_declaration_p
+      && cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+    {
+      cp_token *comma = cp_lexer_consume_token (parser->lexer);
+      if (cxx_dialect < cxx1z)
+       pedwarn (comma->location, 0,
+                "comma-separated list in using-declaration only available "
+                "with -std=c++1z or -std=gnu++1z");
+      goto again;
+    }
+
   /* Look for the final `;'.  */
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
index 366c59a2486a1f0481b8db57af522ee9405e3683..dec7d39f0d092fd31e5e47364748d3a7c5660623 100644 (file)
@@ -12591,16 +12591,42 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
       if (DECL_DEPENDENT_P (t)
          || uses_template_parms (USING_DECL_SCOPE (t)))
        {
-         tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args,
-                                        complain, in_decl);
+         tree scope = USING_DECL_SCOPE (t);
          tree name = tsubst_copy (DECL_NAME (t), args, complain, in_decl);
-         r = do_class_using_decl (inst_scope, name);
-         if (!r)
-           r = error_mark_node;
+         if (PACK_EXPANSION_P (scope))
+           {
+             tree vec = tsubst_pack_expansion (scope, args, complain, in_decl);
+             int len = TREE_VEC_LENGTH (vec);
+             r = make_tree_vec (len);
+             for (int i = 0; i < len; ++i)
+               {
+                 tree escope = TREE_VEC_ELT (vec, i);
+                 tree elt = do_class_using_decl (escope, name);
+                 if (!elt)
+                   {
+                     r = error_mark_node;
+                     break;
+                   }
+                 else
+                   {
+                     TREE_PROTECTED (elt) = TREE_PROTECTED (t);
+                     TREE_PRIVATE (elt) = TREE_PRIVATE (t);
+                   }
+                 TREE_VEC_ELT (r, i) = elt;
+               }
+           }
          else
            {
-             TREE_PROTECTED (r) = TREE_PROTECTED (t);
-             TREE_PRIVATE (r) = TREE_PRIVATE (t);
+             tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args,
+                                            complain, in_decl);
+             r = do_class_using_decl (inst_scope, name);
+             if (!r)
+               r = error_mark_node;
+             else
+               {
+                 TREE_PROTECTED (r) = TREE_PROTECTED (t);
+                 TREE_PRIVATE (r) = TREE_PRIVATE (t);
+               }
            }
        }
       else
diff --git a/gcc/testsuite/g++.dg/cpp1z/using2.C b/gcc/testsuite/g++.dg/cpp1z/using2.C
new file mode 100644 (file)
index 0000000..8b8ee7b
--- /dev/null
@@ -0,0 +1,19 @@
+// Test for P0195R2 variadic using.
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A { void f(); };
+struct B { void f(int); };
+
+template <class... Bases> struct C: Bases...
+{
+  using Bases::f...; // { dg-warning "pack expansion" "" { target c++14_down } }
+};
+
+int main()
+{
+  C<A,B> c;
+  c.f();
+  c.f(42);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1z/using3.C b/gcc/testsuite/g++.dg/cpp1z/using3.C
new file mode 100644 (file)
index 0000000..689770f
--- /dev/null
@@ -0,0 +1,20 @@
+// Test for P0195R2 multiple using.
+// { dg-options "" }
+
+namespace A {
+  int i;
+}
+
+namespace A1 {
+  using A::i, A::i;     // OK: double declaration
+  // { dg-warning "comma" "" { target c++14_down } .-1 }
+}
+
+struct B {
+  int i;
+};
+
+struct X : B {
+  using B::i, B::i; // { dg-error "redeclaration" }
+  // { dg-warning "comma" "" { target c++14_down } .-1 }
+};