diff mbox

C++ PATCH to implement C++17 variadic using

Message ID CADzB+2mZkHwb_ZhO_YiDroyWoWtyFCfYg-4a7G7x7GJ-d=Gmvg@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Jan. 9, 2017, 9:50 p.m. UTC
The last C++17 feature was pretty trivial to implement, as expected.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 10650d842cd49cad2adb396bc19192bf52975be8
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jan 9 15:08:47 2017 -0500

            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.

Comments

Jakub Jelinek Jan. 9, 2017, 9:56 p.m. UTC | #1
On Mon, Jan 09, 2017 at 04:50:20PM -0500, Jason Merrill wrote:
> The last C++17 feature

What about P0490R0?

	Jakub
Jason Merrill Jan. 9, 2017, 10:02 p.m. UTC | #2
On Mon, Jan 9, 2017 at 4:56 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Jan 09, 2017 at 04:50:20PM -0500, Jason Merrill wrote:
>> The last C++17 feature
>
> What about P0490R0?

That's the response to various national body comments, I don't see
anything in there that I would consider a new feature, most is just
wording clarification.  Are you thinking of something in particular?

Jason
Jakub Jelinek Jan. 9, 2017, 10:11 p.m. UTC | #3
On Mon, Jan 09, 2017 at 05:02:03PM -0500, Jason Merrill wrote:
> On Mon, Jan 9, 2017 at 4:56 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Mon, Jan 09, 2017 at 04:50:20PM -0500, Jason Merrill wrote:
> >> The last C++17 feature
> >
> > What about P0490R0?
> 
> That's the response to various national body comments, I don't see
> anything in there that I would consider a new feature, most is just
> wording clarification.  Are you thinking of something in particular?

Yeah, it doesn't look like a feature, just lots of minor changes.
What I wanted to mention is that we should nevertheless go through them and
implement them (unless they are reverted (I hope GB 20 will be, because
right now decomp is broken for const structures when <utility> is included)).

	Jakub
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 038227b..ff4f4ef 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -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)
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index fde8499..72044a9 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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:
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e8c0642..aa045c4 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 366c59a..dec7d39 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
index 0000000..8b8ee7b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/using2.C
@@ -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
index 0000000..689770f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/using3.C
@@ -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 }
+};