I carefully examined the code of setting up tentative firewalls to guard 
current context in cp/parser.c recent days, and think the code could be 
simplified.

For example, in function cp_parser_start_tentative_firewall,
4427 cp_parser_parse_tentatively (parser); 
4428 cp_parser_commit_to_topmost_tentative_parse (parser);

A) cp_parser_parse_tentatively does following jobs:
1) create a new context
2) save current token
3) push deferring access

B) cp_parser_commit_to_topmost_tentative_parse does following jobs:
1) mark the new context as committed
2) pop current token 

Clearly saving and popping current token is unneccessary.

Push deferring access is also unneccessary after a carefull analysis:
In function cp_parser_parse_definitely,
error_occurred = cp_parser_error_occurred (parser) will always return
false for committed context, so pop_to_parent_deferring_access_checks
is always got called, while pushed deferring access in step (A) won't
affect the result wether or not the access check should delayed to 
parent access level.

Performance evaluation:
orig)  perf stat -e instructions:u ../gcc/cc1plus.orig 
g++.dg/template/friend28.C
59,171,628      instructions:u 
after) perf stat -e instructions:u ../gcc/cc1plus g++.dg/template/friend28.C
59,171,598      instructions:u

bootstrapped and checked on x86-64 

Signed-off-by: Zhouyi Zhou <yizhouz...@ict.ac.cn>
---
 gcc/cp/ChangeLog | 14 ++++++++++++++
 gcc/cp/parser.c  | 22 ++++++++++++++++------
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7aca3ac..f095b1d 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,17 @@
+2016-12-29  Zhouyi Zhou  <yizhouz...@ict.ac.cn>
+
+       Simplifying tentative firewalls
+       * parser.c (cp_parser_start_tentative_firewall): Simplifying 
+       tentative firewall so that it only do the necessary jobs to
+       guard current context.
+       * parser.c (cp_parser_end_tentative_firewall): Simplifying the
+       end of tentative firewall.
+       * parser.c (tentative_firewall::tentative_firewall): Simplifying 
+       tentative firewall so that it only do the necessary jobs to
+       guard current context.
+       * parser.c (tentative_firewall::~tentative_firewall): Simplifying 
+       the end of tentative firewall.
+       
 2016-12-24  Jakub Jelinek  <ja...@redhat.com>
 
        PR middle-end/78901
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e2a0a49..ebcc802 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4424,8 +4424,8 @@ cp_parser_start_tentative_firewall (cp_parser *parser)
   if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
     return 0;
 
-  cp_parser_parse_tentatively (parser);
-  cp_parser_commit_to_topmost_tentative_parse (parser);
+  parser->context = cp_parser_context_new (parser->context);
+  parser->context->status = CP_PARSER_STATUS_KIND_COMMITTED;
   return cp_lexer_token_position (parser->lexer, false);
 }
 
@@ -4436,11 +4436,16 @@ static void
 cp_parser_end_tentative_firewall (cp_parser *parser, cp_token_position start,
                                  tree expr)
 {
+  cp_parser_context *context;
+
   if (!start)
     return;
 
   /* Finish the firewall level.  */
-  cp_parser_parse_definitely (parser);
+  context = parser->context;
+  parser->context = context->next;
+  context->next = cp_parser_context_free_list;
+  cp_parser_context_free_list = context;
   /* And remember the result of the parse for when we try again.  */
   cp_token *token = cp_lexer_token_at (parser->lexer, start);
   token->type = CPP_PREPARSED_EXPR;
@@ -4465,8 +4470,8 @@ struct tentative_firewall
        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);
+       parser->context = cp_parser_context_new (parser->context);
+       parser->context->status = CP_PARSER_STATUS_KIND_COMMITTED;
        cp_parser_parse_tentatively (parser);
       }
   }
@@ -4477,9 +4482,14 @@ struct tentative_firewall
       {
        /* Finish the inner tentative parse and the firewall, propagating any
           uncommitted error state to the outer tentative parse.  */
+       cp_parser_context *context;
        bool err = cp_parser_error_occurred (parser);
        cp_parser_parse_definitely (parser);
-       cp_parser_parse_definitely (parser);
+       /* Finish the firewall level.  */
+       context = parser->context;
+       parser->context = context->next;
+       context->next = cp_parser_context_free_list;
+       cp_parser_context_free_list = context;
        if (err)
          cp_parser_simulate_error (parser);
       }
-- 
1.9.1

Reply via email to