From 1bf2ca0b75a3b6ce72ab4065dbc10b7f80413d4b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 6 Dec 2015 23:35:14 -0500 Subject: [PATCH] Fix parse/no-type-defn1.C with -std=c++1z. * parser.c (struct tentative_firewall): New. (cp_parser_template_id, cp_parser_decltype_expr): Use it. From-SVN: r231354 --- gcc/cp/ChangeLog | 3 ++ gcc/cp/parser.c | 47 ++++++++++++++++++++++ gcc/testsuite/g++.dg/parse/no-type-defn1.C | 2 + 3 files changed, 52 insertions(+) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ca9b97cba47..c4daf75d394 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,8 @@ 2015-12-06 Jason Merrill + * parser.c (struct tentative_firewall): New. + (cp_parser_template_id, cp_parser_decltype_expr): Use it. + * parser.h (struct cp_token): Tell GTY that CPP_DECLTYPE uses tree_check_value. * parser.c (cp_parser_decltype): Use tree_check_value. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ce5a21a759a..3e90f11dc03 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4326,6 +4326,43 @@ cp_parser_end_tentative_firewall (cp_parser *parser, cp_token_position start, cp_lexer_purge_tokens_after (parser->lexer, start); } +/* Like the above functions, but let the user modify the tokens. Used by + CPP_DECLTYPE and CPP_TEMPLATE_ID, where we are saving the side-effects for + later parses, so it makes sense to localize the effects of + cp_parser_commit_to_tentative_parse. */ + +struct tentative_firewall +{ + cp_parser *parser; + bool set; + + tentative_firewall (cp_parser *p): parser(p) + { + /* If we're currently parsing tentatively, start a committed level as a + firewall and then an inner tentative parse. */ + if ((set = cp_parser_uncommitted_to_tentative_parse_p (parser))) + { + cp_parser_parse_tentatively (parser); + cp_parser_commit_to_topmost_tentative_parse (parser); + cp_parser_parse_tentatively (parser); + } + } + + ~tentative_firewall() + { + if (set) + { + /* Finish the inner tentative parse and the firewall, propagating any + uncommitted error state to the outer tentative parse. */ + bool err = cp_parser_error_occurred (parser); + cp_parser_parse_definitely (parser); + cp_parser_parse_definitely (parser); + if (err) + cp_parser_simulate_error (parser); + } + } +}; + /* Parse a GNU statement-expression, i.e. ({ stmts }), except for the enclosing parentheses. */ @@ -12921,6 +12958,11 @@ cp_parser_decltype_expr (cp_parser *parser, cp_token *id_expr_start_token; tree expr; + /* Since we're going to preserve any side-effects from this parse, set up a + firewall to protect our callers from cp_parser_commit_to_tentative_parse + in the expression. */ + tentative_firewall firewall (parser); + /* First, try parsing an id-expression. */ id_expr_start_token = cp_lexer_peek_token (parser->lexer); cp_parser_parse_tentatively (parser); @@ -14687,6 +14729,11 @@ cp_parser_template_id (cp_parser *parser, return templ; } + /* Since we're going to preserve any side-effects from this parse, set up a + firewall to protect our callers from cp_parser_commit_to_tentative_parse + in the template arguments. */ + tentative_firewall firewall (parser); + /* If we find the sequence `[:' after a template-name, it's probably a digraph-typo for `< ::'. Substitute the tokens and check if we can parse correctly the argument list. */ diff --git a/gcc/testsuite/g++.dg/parse/no-type-defn1.C b/gcc/testsuite/g++.dg/parse/no-type-defn1.C index 9e899579ef6..a8d6ad88ae0 100644 --- a/gcc/testsuite/g++.dg/parse/no-type-defn1.C +++ b/gcc/testsuite/g++.dg/parse/no-type-defn1.C @@ -3,3 +3,5 @@ template struct A { }; A< struct B { }* >::SomeNonSense // { dg-error "types may not be defined" } int y; + +// { dg-prune-output "SomeNonSense" } -- 2.30.2