diff mbox

[c++] fix PR 46868, segfault after bogus semicolon recovery

Message ID 20101217160907.GJ25059@nightcrawler
State New
Headers show

Commit Message

Nathan Froyd Dec. 17, 2010, 4:09 p.m. UTC
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.

Comments

Jason Merrill Jan. 5, 2011, 7:38 p.m. UTC | #1
How about if we only attempt semicolon recovery if we actually saw the 
closing brace?

Jason
diff mbox

Patch

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 "" }