From: Jason Merrill Date: Mon, 2 Jan 2012 17:53:16 +0000 (-0500) Subject: DR 325 PR c++/51666 X-Git-Tag: upstream/12.2.0~78810 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d28c2dcd712c9c79f8608c136f977f5d925886ea;p=platform%2Fupstream%2Fgcc.git DR 325 PR c++/51666 DR 325 PR c++/51666 * parser.c (cp_parser_cache_defarg): Split out... (cp_parser_parameter_declaration): ...from here. (cp_parser_save_nsdmi): Use it. (cp_parser_cache_group): Remove CPP_COMMA support. From-SVN: r182809 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 23f3ae0..7668a7b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2012-01-02 Jason Merrill + + DR 325 + PR c++/51666 + * parser.c (cp_parser_cache_defarg): Split out... + (cp_parser_parameter_declaration): ...from here. + (cp_parser_save_nsdmi): Use it. + (cp_parser_cache_group): Remove CPP_COMMA support. + 2012-01-02 Dodji Seketeli PR c++/51462 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0f5bb8e..7e6915c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2249,6 +2249,8 @@ static void cp_parser_pre_parsed_nested_name_specifier (cp_parser *); static bool cp_parser_cache_group (cp_parser *, enum cpp_ttype, unsigned); +static tree cp_parser_cache_defarg + (cp_parser *parser, bool nsdmi); static void cp_parser_parse_tentatively (cp_parser *); static void cp_parser_commit_to_tentative_parse @@ -17267,159 +17269,18 @@ cp_parser_parameter_declaration (cp_parser *parser, /* If the next token is `=', then process a default argument. */ if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) { + token = cp_lexer_peek_token (parser->lexer); /* If we are defining a class, then the tokens that make up the default argument must be saved and processed later. */ if (!template_parm_p && at_class_scope_p () && TYPE_BEING_DEFINED (current_class_type) && !LAMBDA_TYPE_P (current_class_type)) - { - unsigned depth = 0; - int maybe_template_id = 0; - cp_token *first_token; - cp_token *token; - - /* Add tokens until we have processed the entire default - argument. We add the range [first_token, token). */ - first_token = cp_lexer_peek_token (parser->lexer); - while (true) - { - bool done = false; - - /* Peek at the next token. */ - token = cp_lexer_peek_token (parser->lexer); - /* What we do depends on what token we have. */ - switch (token->type) - { - /* In valid code, a default argument must be - immediately followed by a `,' `)', or `...'. */ - case CPP_COMMA: - if (depth == 0 && maybe_template_id) - { - /* If we've seen a '<', we might be in a - template-argument-list. Until Core issue 325 is - resolved, we don't know how this situation ought - to be handled, so try to DTRT. We check whether - what comes after the comma is a valid parameter - declaration list. If it is, then the comma ends - the default argument; otherwise the default - argument continues. */ - bool error = false; - tree t; - - /* Set ITALP so cp_parser_parameter_declaration_list - doesn't decide to commit to this parse. */ - bool saved_italp = parser->in_template_argument_list_p; - parser->in_template_argument_list_p = true; - - cp_parser_parse_tentatively (parser); - cp_lexer_consume_token (parser->lexer); - begin_scope (sk_function_parms, NULL_TREE); - cp_parser_parameter_declaration_list (parser, &error); - for (t = current_binding_level->names; t; t = DECL_CHAIN (t)) - pop_binding (DECL_NAME (t), t); - leave_scope (); - if (!cp_parser_error_occurred (parser) && !error) - done = true; - cp_parser_abort_tentative_parse (parser); - - parser->in_template_argument_list_p = saved_italp; - break; - } - case CPP_CLOSE_PAREN: - case CPP_ELLIPSIS: - /* If we run into a non-nested `;', `}', or `]', - then the code is invalid -- but the default - argument is certainly over. */ - case CPP_SEMICOLON: - case CPP_CLOSE_BRACE: - case CPP_CLOSE_SQUARE: - if (depth == 0) - done = true; - /* Update DEPTH, if necessary. */ - else if (token->type == CPP_CLOSE_PAREN - || token->type == CPP_CLOSE_BRACE - || token->type == CPP_CLOSE_SQUARE) - --depth; - break; - - case CPP_OPEN_PAREN: - case CPP_OPEN_SQUARE: - case CPP_OPEN_BRACE: - ++depth; - break; - - case CPP_LESS: - if (depth == 0) - /* This might be the comparison operator, or it might - start a template argument list. */ - ++maybe_template_id; - break; - - case CPP_RSHIFT: - if (cxx_dialect == cxx98) - break; - /* Fall through for C++0x, which treats the `>>' - operator like two `>' tokens in certain - cases. */ - - case CPP_GREATER: - if (depth == 0) - { - /* This might be an operator, or it might close a - template argument list. But if a previous '<' - started a template argument list, this will have - closed it, so we can't be in one anymore. */ - maybe_template_id -= 1 + (token->type == CPP_RSHIFT); - if (maybe_template_id < 0) - maybe_template_id = 0; - } - break; - - /* If we run out of tokens, issue an error message. */ - case CPP_EOF: - case CPP_PRAGMA_EOL: - error_at (token->location, "file ends in default argument"); - done = true; - break; - - case CPP_NAME: - case CPP_SCOPE: - /* In these cases, we should look for template-ids. - For example, if the default argument is - `X()', we need to do name lookup to - figure out whether or not `X' is a template; if - so, the `,' does not end the default argument. - - That is not yet done. */ - break; - - default: - break; - } - - /* If we've reached the end, stop. */ - if (done) - break; - - /* Add the token to the token block. */ - token = cp_lexer_consume_token (parser->lexer); - } - - /* Create a DEFAULT_ARG to represent the unparsed default - argument. */ - default_argument = make_node (DEFAULT_ARG); - DEFARG_TOKENS (default_argument) - = cp_token_cache_new (first_token, token); - DEFARG_INSTANTIATIONS (default_argument) = NULL; - } + default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false); /* Outside of a class definition, we can just parse the assignment-expression. */ else - { - token = cp_lexer_peek_token (parser->lexer); - default_argument - = cp_parser_default_argument (parser, template_parm_p); - } + default_argument + = cp_parser_default_argument (parser, template_parm_p); if (!parser->default_arg_ok_p) { @@ -21630,25 +21491,9 @@ cp_parser_save_member_function_body (cp_parser* parser, static tree cp_parser_save_nsdmi (cp_parser* parser) { - /* Save away the tokens that make up the body of the - function. */ - cp_token *first = parser->lexer->next_token; - cp_token *last; - tree node; - - /* Save tokens until the next comma or semicolon. */ - cp_parser_cache_group (parser, CPP_COMMA, /*depth=*/0); - - last = parser->lexer->next_token; - - node = make_node (DEFAULT_ARG); - DEFARG_TOKENS (node) = cp_token_cache_new (first, last); - DEFARG_INSTANTIATIONS (node) = NULL; - - return node; + return cp_parser_cache_defarg (parser, /*nsdmi=*/true); } - /* Parse a template-argument-list, as well as the trailing ">" (but not the opening "<"). See cp_parser_template_argument_list for the return value. */ @@ -22758,12 +22603,6 @@ cp_parser_cache_group (cp_parser *parser, kind of syntax error. */ return true; - /* If we're caching something finished by a comma (or semicolon), - such as an NSDMI, don't consume the comma. */ - if (end == CPP_COMMA - && (token->type == CPP_SEMICOLON || token->type == CPP_COMMA)) - return false; - /* Consume the token. */ cp_lexer_consume_token (parser->lexer); /* See if it starts a new group. */ @@ -22789,6 +22628,178 @@ cp_parser_cache_group (cp_parser *parser, } } +/* Like above, for caching a default argument or NSDMI. Both of these are + terminated by a non-nested comma, but it can be unclear whether or not a + comma is nested in a template argument list unless we do more parsing. + In order to handle this ambiguity, when we encounter a ',' after a '<' + we try to parse what follows as a parameter-declaration-list (in the + case of a default argument) or a member-declarator (in the case of an + NSDMI). If that succeeds, then we stop caching. */ + +static tree +cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) +{ + unsigned depth = 0; + int maybe_template_id = 0; + cp_token *first_token; + cp_token *token; + tree default_argument; + + /* Add tokens until we have processed the entire default + argument. We add the range [first_token, token). */ + first_token = cp_lexer_peek_token (parser->lexer); + if (first_token->type == CPP_OPEN_BRACE) + { + /* For list-initialization, this is straightforward. */ + cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0); + token = cp_lexer_peek_token (parser->lexer); + } + else while (true) + { + bool done = false; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* What we do depends on what token we have. */ + switch (token->type) + { + /* In valid code, a default argument must be + immediately followed by a `,' `)', or `...'. */ + case CPP_COMMA: + if (depth == 0 && maybe_template_id) + { + /* If we've seen a '<', we might be in a + template-argument-list. Until Core issue 325 is + resolved, we don't know how this situation ought + to be handled, so try to DTRT. We check whether + what comes after the comma is a valid parameter + declaration list. If it is, then the comma ends + the default argument; otherwise the default + argument continues. */ + bool error = false; + tree t; + + /* Set ITALP so cp_parser_parameter_declaration_list + doesn't decide to commit to this parse. */ + bool saved_italp = parser->in_template_argument_list_p; + parser->in_template_argument_list_p = true; + + cp_parser_parse_tentatively (parser); + cp_lexer_consume_token (parser->lexer); + + if (nsdmi) + { + int ctor_dtor_or_conv_p; + cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + &ctor_dtor_or_conv_p, + /*parenthesized_p=*/NULL, + /*member_p=*/true); + } + else + { + begin_scope (sk_function_parms, NULL_TREE); + cp_parser_parameter_declaration_list (parser, &error); + for (t = current_binding_level->names; t; t = DECL_CHAIN (t)) + pop_binding (DECL_NAME (t), t); + leave_scope (); + } + if (!cp_parser_error_occurred (parser) && !error) + done = true; + cp_parser_abort_tentative_parse (parser); + + parser->in_template_argument_list_p = saved_italp; + break; + } + case CPP_CLOSE_PAREN: + case CPP_ELLIPSIS: + /* If we run into a non-nested `;', `}', or `]', + then the code is invalid -- but the default + argument is certainly over. */ + case CPP_SEMICOLON: + case CPP_CLOSE_BRACE: + case CPP_CLOSE_SQUARE: + if (depth == 0) + done = true; + /* Update DEPTH, if necessary. */ + else if (token->type == CPP_CLOSE_PAREN + || token->type == CPP_CLOSE_BRACE + || token->type == CPP_CLOSE_SQUARE) + --depth; + break; + + case CPP_OPEN_PAREN: + case CPP_OPEN_SQUARE: + case CPP_OPEN_BRACE: + ++depth; + break; + + case CPP_LESS: + if (depth == 0) + /* This might be the comparison operator, or it might + start a template argument list. */ + ++maybe_template_id; + break; + + case CPP_RSHIFT: + if (cxx_dialect == cxx98) + break; + /* Fall through for C++0x, which treats the `>>' + operator like two `>' tokens in certain + cases. */ + + case CPP_GREATER: + if (depth == 0) + { + /* This might be an operator, or it might close a + template argument list. But if a previous '<' + started a template argument list, this will have + closed it, so we can't be in one anymore. */ + maybe_template_id -= 1 + (token->type == CPP_RSHIFT); + if (maybe_template_id < 0) + maybe_template_id = 0; + } + break; + + /* If we run out of tokens, issue an error message. */ + case CPP_EOF: + case CPP_PRAGMA_EOL: + error_at (token->location, "file ends in default argument"); + done = true; + break; + + case CPP_NAME: + case CPP_SCOPE: + /* In these cases, we should look for template-ids. + For example, if the default argument is + `X()', we need to do name lookup to + figure out whether or not `X' is a template; if + so, the `,' does not end the default argument. + + That is not yet done. */ + break; + + default: + break; + } + + /* If we've reached the end, stop. */ + if (done) + break; + + /* Add the token to the token block. */ + token = cp_lexer_consume_token (parser->lexer); + } + + /* Create a DEFAULT_ARG to represent the unparsed default + argument. */ + default_argument = make_node (DEFAULT_ARG); + DEFARG_TOKENS (default_argument) + = cp_token_cache_new (first_token, token); + DEFARG_INSTANTIATIONS (default_argument) = NULL; + + return default_argument; +} + /* Begin parsing tentatively. We always save tokens while parsing tentatively so that if the tentative parsing fails we can restore the tokens. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ad865db..e1e0dfe 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-01-02 Jason Merrill + + PR c++/51666 + * g++.dg/cpp0x/nsdmi-defer5.C: New. + 2012-01-02 Dodji Seketeli PR c++/51462 diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer5.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer5.C new file mode 100644 index 0000000..85abfbf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer5.C @@ -0,0 +1,20 @@ +// PR c++/51666 (DR 325) +// { dg-options -std=c++0x } + +template +struct tuple +{ + tuple(T, U) { } +}; + +struct Y +{ + tuple tt = tuple{1, 2}; +}; + +struct A +{ + int i = 0; + int j = i < 42, k; // OK, declares j and k + int l = i < 42, 24; // { dg-error "" } +};