From patchwork Wed Oct 30 12:33:43 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 287200 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]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C232A2C0349 for ; Wed, 30 Oct 2013 23:34:03 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=kzOp1dnGEnwhP8mlyH7oppmkHdL74PpSP4+jQ47QQB7 AxZHecCMsjbI4OoPgfLYqRvmjw+QqDBcSr9K/O0cepP95Q5kcsyZlcyccDaoZcTv HQuVBc6OE/MuzoFgz8ho2AKXik9Qe43hWCqX80cx87peScl9tlDXHiB1nF/k7Xs4 = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=nucLArFeqO6+dbAB/jPQZXa1CNw=; b=ZTyuVqC7YCMONG/NP H+TAsuJKkwXgYNqtXHqo+kFHT58Elru3DXeLnRMRCGPU/2O79g4MA+V79YvjLPKk ruNJytLPDl+pxcYL4w2ArgJq4z8dOKZ8TNAaF5Tl9f2QolwXrKzBrQZutq28pv1H 4iMbVYgca5Q1i2phLV7G+B4ZbI= Received: (qmail 17500 invoked by alias); 30 Oct 2013 12:33:52 -0000 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 Received: (qmail 17358 invoked by uid 89); 30 Oct 2013 12:33:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.9 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_PASS, UNPARSEABLE_RELAY autolearn=ham version=3.3.2 X-HELO: aserp1040.oracle.com Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Wed, 30 Oct 2013 12:33:50 +0000 Received: from ucsinet21.oracle.com (ucsinet21.oracle.com [156.151.31.93]) by aserp1040.oracle.com (Sentrion-MTA-4.3.1/Sentrion-MTA-4.3.1) with ESMTP id r9UCXkAJ025638 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 30 Oct 2013 12:33:47 GMT Received: from aserz7022.oracle.com (aserz7022.oracle.com [141.146.126.231]) by ucsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id r9UCXjKa001676 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 30 Oct 2013 12:33:46 GMT Received: from abhmt117.oracle.com (abhmt117.oracle.com [141.146.116.69]) by aserz7022.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id r9UCXjUm020512; Wed, 30 Oct 2013 12:33:45 GMT Received: from poldo4.casa (/79.33.222.253) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 30 Oct 2013 05:33:45 -0700 Message-ID: <5270FCA7.8000508@oracle.com> Date: Wed, 30 Oct 2013 13:33:43 +0100 From: Paolo Carlini User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.0 MIME-Version: 1.0 To: "gcc-patches@gcc.gnu.org" CC: Jason Merrill Subject: [C++ Patch / RFC] PR 29234 X-IsSubscribed: yes Hi, I'm having a look at this very old parsing issue. We reject things like: struct S { void operator () (); }; void foo () { ( S()() ); } because the parenthesized S()() triggers an hard error from groktypename as called at the end of cp_parser_type_id (called by cp_parser_cast_expression), about a function returning a function. Of course we have to parse it as an unary-expression. I scratched my head for a while, but then I noticed that in cp_parser_cast_expression, a bit later the cp_parser_type_id call at issue, we are *already* using a cp_parser_tokens_start_cast_expression which helps use figuring out whether the tokens following the outer ')' make sense as a cast-expression. Using it a bit earlier to completely avoid calling cp_parser_type_id in the cases at issue, appears to work well, for a - negligeable in my opinion - additional computational cost. Then, cp_parser_unary_expression is actually used. As part of that, cp_parser_postfix_expression looks for a compound-literal, but not in the robust way we are using elsewhere involving a cp_parser_skip_to_closing_parenthesis, but just using tentative parsing with cp_parser_type_id. Thus we are incurring again in the same issue. Parsing the compound-literal in the same way used elesewhere - thus looking for the '{' after the ')', solves the problem. In my personal opinion, again, the computational cost shouldn't be too high, because if we don't find '{' we completely avoid cp_parser_type_id. Is this the kind of approach we want to pursue for this issue? Tested x86_64-linux. Thanks! Paolo. ///////////////////////////// Index: cp/parser.c =================================================================== --- cp/parser.c (revision 204202) +++ cp/parser.c (working copy) @@ -5800,31 +5800,45 @@ cp_parser_postfix_expression (cp_parser *parser, b && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { tree initializer = NULL_TREE; - bool saved_in_type_id_in_expr_p; + bool compound_literal_p; cp_parser_parse_tentatively (parser); /* Consume the `('. */ cp_lexer_consume_token (parser->lexer); - /* Parse the type. */ - saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; - parser->in_type_id_in_expr_p = true; - type = cp_parser_type_id (parser); - parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; - /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + + /* Avoid calling cp_parser_type_id pointlessly, see comment + in cp_parser_cast_expression about c++/29234. */ + cp_lexer_save_tokens (parser->lexer); + + compound_literal_p + = (cp_parser_skip_to_closing_parenthesis (parser, false, false, + /*consume_paren=*/true) + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)); + + /* Roll back the tokens we skipped. */ + cp_lexer_rollback_tokens (parser->lexer); + + if (!compound_literal_p) + cp_parser_simulate_error (parser); + else + { + /* Parse the type. */ + bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; + parser->in_type_id_in_expr_p = true; + type = cp_parser_type_id (parser); + parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + } + /* If things aren't going well, there's no need to keep going. */ if (!cp_parser_error_occurred (parser)) { - if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) - { - bool non_constant_p; - /* Parse the brace-enclosed initializer list. */ - initializer = cp_parser_braced_list (parser, - &non_constant_p); - } - else - cp_parser_simulate_error (parser); + bool non_constant_p; + /* Parse the brace-enclosed initializer list. */ + initializer = cp_parser_braced_list (parser, + &non_constant_p); } /* If that worked, we're definitely looking at a compound-literal expression. */ @@ -7559,7 +7573,9 @@ cp_parser_cast_expression (cp_parser *parser, bool { tree type = NULL_TREE; tree expr = NULL_TREE; + bool skip_to_closing_ok_p; bool compound_literal_p; + bool cast_expression_p; const char *saved_message; /* There's no way to know yet whether or not this is a cast. @@ -7587,21 +7603,44 @@ cp_parser_cast_expression (cp_parser *parser, bool if the token after the `)' is a `{'. If so, we are not looking at a cast-expression. + Another tricky case is the following (c++/29234): + + struct S { void operator () (); }; + + void foo () + { + ( S()() ); + } + + where the parenthesized S()(), as a type-id would be parsed as a + function returning a function. Thus see if the tokens after the + outer `)' are starting a cast-expression. + Save tokens so that we can put them back. */ cp_lexer_save_tokens (parser->lexer); - /* Skip tokens until the next token is a closing parenthesis. - If we find the closing `)', and the next token is a `{', then + + /* Skip tokens until the next token is a closing parenthesis. */ + skip_to_closing_ok_p + = cp_parser_skip_to_closing_parenthesis (parser, false, false, + /*consume_paren=*/true); + + /* If we find the closing `)', and the next token is a `{', then we are looking at a compound-literal. */ compound_literal_p - = (cp_parser_skip_to_closing_parenthesis (parser, false, false, - /*consume_paren=*/true) + = (skip_to_closing_ok_p && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)); + + /* Alternately, we may be looking at a cast-expression. */ + cast_expression_p + = (skip_to_closing_ok_p + && cp_parser_tokens_start_cast_expression (parser)); + /* Roll back the tokens we skipped. */ cp_lexer_rollback_tokens (parser->lexer); - /* If we were looking at a compound-literal, simulate an error - so that the call to cp_parser_parse_definitely below will - fail. */ - if (compound_literal_p) + /* If we were looking at a compound-literal or we can't possibly + be looking at a cast-expression, simulate an error so that the + call to cp_parser_parse_definitely below will fail. */ + if (compound_literal_p || !cast_expression_p) cp_parser_simulate_error (parser); else { @@ -7620,8 +7659,7 @@ cp_parser_cast_expression (cp_parser *parser, bool /* At this point this can only be either a cast or a parenthesized ctor such as `(T ())' that looks like a cast to function returning T. */ - if (!cp_parser_error_occurred (parser) - && cp_parser_tokens_start_cast_expression (parser)) + if (!cp_parser_error_occurred (parser)) { cp_parser_parse_definitely (parser); expr = cp_parser_cast_expression (parser, Index: testsuite/g++.dg/parse/pr29234.C =================================================================== --- testsuite/g++.dg/parse/pr29234.C (revision 0) +++ testsuite/g++.dg/parse/pr29234.C (working copy) @@ -0,0 +1,16 @@ +// PR c++/29234 + +struct S { void operator()(); }; + +void foo () +{ + ( S()() ); +} + +struct C { void operator[](C); }; + +void bar () +{ + C x; + ( C()[x] ); +}