From patchwork Mon Jan 2 15:33:30 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 133861 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 30B3E1007D2 for ; Tue, 3 Jan 2012 02:33:57 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1326123238; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=gNBKSxy LY1ghtnRXFtqo4nLOWic=; b=PYm2TD16/Y9mDOuBRK5EeC0GKj5HEe6ZHiXGwdA cZQizTPheJVdpS3ihzuKb//+0KBZWlhU74x+wPDJe0V6TP0lwAzn489x+KA9agvJ OV5ALoFzDxuu9lo5t48P+LBifLFvUOCK6KvVRqtlNva213jhFYr1768W0uOUhTqH 0a+4= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=CSqWR/XavPUyCTmfX/lVo/I8azFbA+ui97RDSKm0+CCQF4+ab2fef1rUethkr4 oRlGRgLpRgf1ufXRvuW3/MGsJk0iM2TxVaHgOHCKiMLR8qkiaT6BXZcQMxDxSCW+ 7vlL+w4CTKSrmoqLKed/Mz5nLh9ACDc0pumajYkmELElE=; Received: (qmail 643 invoked by alias); 2 Jan 2012 15:33:52 -0000 Received: (qmail 634 invoked by uid 22791); 2 Jan 2012 15:33:50 -0000 X-SWARE-Spam-Status: No, hits=-7.2 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 02 Jan 2012 15:33:33 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q02FXWbb006409 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 2 Jan 2012 10:33:32 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q02FXWXm025704 for ; Mon, 2 Jan 2012 10:33:32 -0500 Received: from [0.0.0.0] (ovpn-113-37.phx2.redhat.com [10.3.113.37]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id q02FXUSH024746 for ; Mon, 2 Jan 2012 10:33:31 -0500 Message-ID: <4F01CE4A.8000809@redhat.com> Date: Mon, 02 Jan 2012 10:33:30 -0500 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20111112 Thunderbird/8.0 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/51666 (comma in NSDMI) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org As discussed in the audit trail, this is DR 325 as it affects NSDMI rather than default arguments. So to fix it I re-used the same code for dealing with the default argument case. Tested x86_64-pc-linux-gnu, applying to trunk. commit bd815e955cfe15f7ecd36366bc79062278e8f2e5 Author: Jason Merrill Date: Sun Jan 1 23:44:24 2012 -0500 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. 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/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 "" } +};