From patchwork Fri Dec 17 16:09:11 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Froyd X-Patchwork-Id: 75918 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 0DF611007D3 for ; Sat, 18 Dec 2010 03:09:28 +1100 (EST) Received: (qmail 15024 invoked by alias); 17 Dec 2010 16:09:24 -0000 Received: (qmail 15015 invoked by uid 22791); 17 Dec 2010 16:09:23 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL, BAYES_00, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 17 Dec 2010 16:09:17 +0000 Received: (qmail 27788 invoked from network); 17 Dec 2010 16:09:15 -0000 Received: from unknown (HELO codesourcery.com) (froydnj@127.0.0.2) by mail.codesourcery.com with ESMTPA; 17 Dec 2010 16:09:15 -0000 Date: Fri, 17 Dec 2010 11:09:11 -0500 From: Nathan Froyd To: gcc-patches@gcc.gnu.org Subject: [PATCH,c++] fix PR 46868, segfault after bogus semicolon recovery Message-ID: <20101217160907.GJ25059@nightcrawler> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) X-IsSubscribed: yes 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 In the testcase from the PR: template < int > struct S { S < what happens is that we treat the 'S <' as a CPP_TEMPLATE_ID and turn the '<' token into a CPP_PURGED token. Then, when we determine we ought to emit an error message for the missing semicolon after the definition of a struct, we set our current token to a CPP_PURGED token. Since such a token has UNKNOWN_LOCATION, this wreaks havoc on input_location and leads to segfaults later on. The simplest way to handle this is to avoid the error message and rewinding of the stream if we would rewind onto a purged token. I considered making cp_lexer_previous_{token,token_position} skip CPP_PURGED tokens, but I don't think that's worth it. Tested on x86_64-unknown-linux-gnu. OK to commit? -Nathan gcc/cp/ PR c++/46868 * parser.c (cp_parser_class_specifier): Don't error and rewind if we'd move over a CPP_PURGED token. gcc/testsuite/ PR c++/4686 * g++.dg/pr46868.C: New test. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 3e6930f..77524bf 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16983,23 +16983,28 @@ cp_parser_class_specifier (cp_parser* parser) cp_token_position prev = cp_lexer_previous_token_position (parser->lexer); cp_token *prev_token = cp_lexer_token_at (parser->lexer, prev); - location_t loc = prev_token->location; - - if (CLASSTYPE_DECLARED_CLASS (type)) - error_at (loc, "expected %<;%> after class definition"); - else if (TREE_CODE (type) == RECORD_TYPE) - error_at (loc, "expected %<;%> after struct definition"); - else if (TREE_CODE (type) == UNION_TYPE) - error_at (loc, "expected %<;%> after union definition"); - else - gcc_unreachable (); - /* Unget one token and smash it to look as though we encountered - a semicolon in the input stream. */ - cp_lexer_set_token_position (parser->lexer, prev); - token = cp_lexer_peek_token (parser->lexer); - token->type = CPP_SEMICOLON; - token->keyword = RID_MAX; + /* Don't rewind over purged tokens. */ + if (prev_token->type != CPP_PURGED) + { + location_t loc = prev_token->location; + + if (CLASSTYPE_DECLARED_CLASS (type)) + error_at (loc, "expected %<;%> after class definition"); + else if (TREE_CODE (type) == RECORD_TYPE) + error_at (loc, "expected %<;%> after struct definition"); + else if (TREE_CODE (type) == UNION_TYPE) + error_at (loc, "expected %<;%> after union definition"); + else + gcc_unreachable (); + + /* Unget one token and smash it to look as though we encountered + a semicolon in the input stream. */ + cp_lexer_set_token_position (parser->lexer, prev); + token = cp_lexer_peek_token (parser->lexer); + token->type = CPP_SEMICOLON; + token->keyword = RID_MAX; + } } } diff --git a/gcc/testsuite/g++.dg/pr46868.C b/gcc/testsuite/g++.dg/pr46868.C new file mode 100644 index 0000000..544c7b2 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr46868.C @@ -0,0 +1,4 @@ +// PR c++/46868 +// { dg-do compile } + +template < int > struct S { S < // { dg-error "" }