From d393153e7fb5a4bc1ed79b72c5c6d6c6ccc195b6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 31 Mar 2007 12:41:30 +0000 Subject: [PATCH] re PR c++/31138 (ICE with ellipsis) 2007-03-31 Douglas Gregor PR c++/31138 PR c++/31140 PR c++/31141 * parser.c (declarator_can_be_parameter_pack): New. (cp_parser_template_parameter): Only parse the `...' if the declarator can be a parameter pack. (cp_parser_parameter_declaration): Ditto. Also, handle when TYPE is NULL. * pt.c (find_parameter_packs_r): Look into the bounds on integer types (they could be used as array bounds). (check_for_bare_parameter_packs): Deal with TEMPLATE_PARM_INDEX. (tsubst_pack_expansion): Handle failure to expand parameter packs. 2007-03-31 Douglas Gregor * g++.dg/parser/pr31138.C: New. * g++.dg/parser/pr31140.C: New. * g++.dg/parser/pr31141.C: New. From-SVN: r123380 --- gcc/cp/ChangeLog | 16 ++++++++++++ gcc/cp/parser.c | 69 ++++++++++++++++++++++++++++++++++++------------- gcc/cp/pt.c | 17 ++++++++++++ gcc/testsuite/ChangeLog | 6 +++++ 4 files changed, 90 insertions(+), 18 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4374e6b..c13dcee 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2007-03-31 Douglas Gregor + + PR c++/31138 + PR c++/31140 + PR c++/31141 + * parser.c (declarator_can_be_parameter_pack): New. + (cp_parser_template_parameter): Only parse the `...' if the + declarator can be a parameter pack. + (cp_parser_parameter_declaration): Ditto. Also, handle when TYPE + is NULL. + * pt.c (find_parameter_packs_r): Look into the bounds on integer + types (they could be used as array bounds). + (check_for_bare_parameter_packs): Deal with TEMPLATE_PARM_INDEX. + (tsubst_pack_expansion): Handle failure to expand parameter + packs. + 2007-03-30 Paolo Carlini PR c++/26099 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4fc1a62..63f7fec 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1055,6 +1055,36 @@ make_array_declarator (cp_declarator *element, tree bounds) return declarator; } +/* Determine whether the declarator we've seen so far can be a + parameter pack, when followed by an ellipsis. */ +static bool +declarator_can_be_parameter_pack (cp_declarator *declarator) +{ + /* Search for a declarator name, or any other declarator that goes + after the point where the ellipsis could appear in a parameter + pack. If we find any of these, then this declarator can not be + made into a parameter pack. */ + bool found = false; + while (declarator && !found) + { + switch ((int)declarator->kind) + { + case cdk_id: + case cdk_error: + case cdk_array: + case cdk_ptrmem: + found = true; + break; + + default: + declarator = declarator->declarator; + break; + } + } + + return !found; +} + cp_parameter_declarator *no_parameters; /* Create a parameter declarator with the indicated DECL_SPECIFIERS, @@ -9049,9 +9079,9 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type, marked as a parameter pack, then we have a parameter pack (that has no declarator); */ if (!*is_parameter_pack - && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) + && declarator_can_be_parameter_pack (parameter_declarator->declarator)) { - /* Consume the `...'. */ cp_lexer_consume_token (parser->lexer); maybe_warn_variadic_templates (); @@ -13095,32 +13125,35 @@ cp_parser_parameter_declaration (cp_parser *parser, cp_parser_attributes_opt (parser)); } - /* If the next token is an ellipsis, and the type of the declarator - contains parameter packs but it is not a TYPE_PACK_EXPANSION, then - we actually have a parameter pack expansion expression. Otherwise, - leave the ellipsis for a C-style variadic function. */ + /* If the next token is an ellipsis, and we have not seen a + declarator name, and the type of the declarator contains parameter + packs but it is not a TYPE_PACK_EXPANSION, then we actually have + a parameter pack expansion expression. Otherwise, leave the + ellipsis for a C-style variadic function. */ token = cp_lexer_peek_token (parser->lexer); if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) { tree type = decl_specifiers.type; - if (DECL_P (type)) + if (type && DECL_P (type)) type = TREE_TYPE (type); - if (TREE_CODE (type) != TYPE_PACK_EXPANSION + if (type + && TREE_CODE (type) != TYPE_PACK_EXPANSION + && declarator_can_be_parameter_pack (declarator) && (!declarator || !declarator->parameter_pack_p) && uses_parameter_packs (type)) { - /* Consume the `...'. */ - cp_lexer_consume_token (parser->lexer); - maybe_warn_variadic_templates (); - - /* Build a pack expansion type */ - if (declarator) - declarator->parameter_pack_p = true; - else - decl_specifiers.type = make_pack_expansion (type); - } + /* Consume the `...'. */ + cp_lexer_consume_token (parser->lexer); + maybe_warn_variadic_templates (); + + /* Build a pack expansion type */ + if (declarator) + declarator->parameter_pack_p = true; + else + decl_specifiers.type = make_pack_expansion (type); + } } /* The restriction on defining new types applies only to the type diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f1e6b18..906b8d5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2441,6 +2441,12 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) *walk_subtrees = 0; return NULL_TREE; + case INTEGER_TYPE: + walk_tree (&TYPE_MAX_VALUE (t), &find_parameter_packs_r, + ppd, ppd->visited); + *walk_subtrees = 0; + return NULL_TREE; + default: return NULL_TREE; } @@ -2621,6 +2627,8 @@ check_for_bare_parameter_packs (tree t) if (TREE_CODE (pack) == TEMPLATE_TYPE_PARM || TREE_CODE (pack) == TEMPLATE_TEMPLATE_PARM) name = TYPE_NAME (pack); + else if (TREE_CODE (pack) == TEMPLATE_PARM_INDEX) + name = DECL_NAME (TEMPLATE_PARM_DECL (pack)); else name = DECL_NAME (pack); inform (" %qD", name); @@ -6860,6 +6868,15 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT) arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack); + if (arg_pack && !ARGUMENT_PACK_P (arg_pack)) + /* This can only happen if we forget to expand an argument + pack somewhere else. Just return an error, silently. */ + { + result = make_tree_vec (1); + TREE_VEC_ELT (result, 0) = error_mark_node; + return result; + } + if (arg_pack) { int my_len = diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a1af0d5..35e22c8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2007-03-31 Douglas Gregor + + * g++.dg/parser/pr31138.C: New. + * g++.dg/parser/pr31140.C: New. + * g++.dg/parser/pr31141.C: New. + 2007-03-30 Paolo Carlini PR c++/26099 -- 2.7.4