diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 78bcd3f1519..5a84068e1df 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2017-01-09 Jason Merrill + + 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 PR translation/79019 diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 038227bf584..ff4f4ef4698 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 fde84997cba..72044a9013c 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 e8c06424e29..aa045c439b3 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 366c59a2486..dec7d39f0d0 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 00000000000..8b8ee7ba638 --- /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 struct C: Bases... +{ + using Bases::f...; // { dg-warning "pack expansion" "" { target c++14_down } } +}; + +int main() +{ + C 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 00000000000..689770f61c5 --- /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 } +};