aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2017-01-09 16:51:08 -0500
committerJason Merrill <jason@gcc.gnu.org>2017-01-09 16:51:08 -0500
commitf4da28a0ab155d5bff5fe400efb2b5459e5429c8 (patch)
treea6a25a2bcfc6d78bd787d7257b26a8242a21c0c6 /gcc
parentbd2c62704bb7e012a3e780dec1288678f51bcd6c (diff)
downloadgcc-f4da28a0ab155d5bff5fe400efb2b5459e5429c8.zip
gcc-f4da28a0ab155d5bff5fe400efb2b5459e5429c8.tar.gz
gcc-f4da28a0ab155d5bff5fe400efb2b5459e5429c8.tar.bz2
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. From-SVN: r244246
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/cp-tree.def3
-rw-r--r--gcc/cp/error.c19
-rw-r--r--gcc/cp/parser.c24
-rw-r--r--gcc/cp/pt.c40
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/using2.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/using3.C20
7 files changed, 119 insertions, 13 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 78bcd3f..5a84068 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
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..689770f6
--- /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 }
+};