@@ -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;
+ }
}
}
new file mode 100644
@@ -0,0 +1,4 @@
+// PR c++/46868
+// { dg-do compile }
+
+template < int > struct S { S < // { dg-error "" }