Studying note of GCC-3.4.6 source (109)

5.12.3.2.1.2.1.2.    Parse function body

For the keyword “return” seen at line 14368 which follows “)”, refers to section Build nodes for method for detail.

 

14356 static tree

14357 cp_parser_function_definition_after_declarator (cp_parser* parser,               in parser.c

14358                                         bool inline_p)

14359 {

14360   tree fn;

14361   bool ctor_initializer_p = false;

14362   bool saved_in_unbraced_linkage_specification_p;

14363   unsigned saved_num_template_parameter_lists;

14364

14365   /* If the next token is `return', then the code may be trying to

14366     make use of the "named return value" extension that G++ used to

14367     support.  */

14368   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_RETURN))

14369   {

14370     /* Consume the `return' keyword.  */

14371     cp_lexer_consume_token (parser->lexer);

14372     /* Look for the identifier that indicates what value is to be

14373       returned.  */

14374     cp_parser_identifier (parser);

14375     /* Issue an error message.  */

14376     error ("named return values are no longer supported");

14377     /* Skip tokens until we reach the start of the function body.  */

14378     while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)

14379           && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))

14380       cp_lexer_consume_token (parser->lexer);

14381   }

14382   /* The `extern' in `extern "C" void f () { ... }' does not apply to

14383     anything declared inside `f'.  */

14384   saved_in_unbraced_linkage_specification_p

14385     = parser->in_unbraced_linkage_specification_p;

14386   parser->in_unbraced_linkage_specification_p = false;

14387   /* Inside the function, surrounding template-parameter-lists do not

14388     apply.  */

14389   saved_num_template_parameter_lists

14390     = parser->num_template_parameter_lists;

14391   parser->num_template_parameter_lists = 0;

14392   /* If the next token is `try', then we are looking at a

14393     function-try-block.  */

14394   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))

14395     ctor_initializer_p = cp_parser_function_try_block (parser);

14396   /* A function-try-block includes the function-body, so we only do

14397     this next part if we're not processing a function-try-block.  */

14398   else

14399     ctor_initializer_p

14400        = cp_parser_ctor_initializer_opt_and_function_body (parser);

14401

14402   /* Finish the function.  */

14403   fn = finish_function ((ctor_initializer_p ? 1 : 0) |

14404                    (inline_p ? 2 : 0));

14405   /* Generate code for it, if necessary.  */

14406   expand_or_defer_fn (fn);

14407   /* Restore the saved values.  */

14408   parser->in_unbraced_linkage_specification_p

14409     = saved_in_unbraced_linkage_specification_p;

14410   parser->num_template_parameter_lists

14411     = saved_num_template_parameter_lists;

14412

14413   return fn;

14414 }

5.12.3.2.1.2.1.2.1.            Preparation

Though our example method contains an empty function body, but handling empty function body still embodies rather complex procedure.

 

11469 static bool

11470 cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)         in parser.c

11471 {

11472   tree body;

11473   bool ctor_initializer_p;

11474

11475   /* Begin the function body.  */

11476   body = begin_function_body ();

11477   /* Parse the optional ctor-initializer.  */

11478   ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);

11479   /* Parse the function-body.  */

11480   cp_parser_function_body (parser);

11481   /* Finish the function body.  */

11482   finish_function_body (body);

11483

11484   return ctor_initializer_p;

11485 }

 

The function body is a compound statement itself, which has following rule:

compound-statement:

     { statement-seq [opt] }

The statement-seq is enclosed the pair of brace which forms a scope that separates this statement-seq from outside. So before really handling function body it needs some preparation.

 

10756 tree

10757 begin_function_body (void)                                                                                    in decl.c

10758 {

10759   tree stmt;

10760

10761   if (processing_template_decl )

10762     /* Do nothing now.  */;

10763   else

10764     /* Always keep the BLOCK node associated with the outermost pair of

10765       curly braces of a function. These are needed for correct

10766       operation of dwarfout.c.  */

10767     keep_next_level (true);

10768

10769   stmt = begin_compound_stmt (/*has_no_scope=*/ false);

10770   COMPOUND_STMT_BODY_BLOCK (stmt) = 1;

10771

10772   if (processing_template_decl )

10773     /* Do nothing now.  */;

10774   else if (DECL_CONSTRUCTOR_P (current_function_decl ))

10775     begin_constructor_body ();

10776   else if (DECL_DESTRUCTOR_P (current_function_decl ))

10777     begin_destructor_body ();

10778

10779   return stmt;

10780 }

 

See that argument has_no_scope is false for the invocation, which means the compound statement defines a scope.

 

998    tree

999    begin_compound_stmt (bool has_no_scope)                                        in semantics.c

1000   {

1001     tree r;

1002     int is_try = 0;

1003  

1004     r = build_stmt (COMPOUND_STMT, NULL_TREE);

1005  

1006     if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)

1007       is_try = 1;

1008  

1009     add_stmt (r);

1010     if (has_no_scope)

1011       COMPOUND_STMT_NO_SCOPE (r) = 1;

1012  

1013     last_expr_type = NULL_TREE;

1014  

1015     if (!has_no_scope)

1016       do_pushlevel (is_try ? sk_try : sk_block);

1017     else

1018        /* Normally, we try hard to keep the BLOCK for a

1019         statement-expression. But, if it's a statement-expression with

1020         a scopeless block, there's nothing to keep, and we don't want

1021         to accidentally keep a block *inside* the scopeless block.  */

1022       keep_next_level (false);

1023  

1024     return r;

1025   }

 

In intermediate tree, brace and parethensis can’t be present. To mark all statements within the compound statement, a node of COMPOUND_STMT is created being the head of statement list. At line 84, last_expr_filename is updated as input_filename in begin_stmt_tree . And if current input file is not the same as that current function belonged, node of FILE_STMT is created to tell the difference.

 

81      tree

82      add_stmt (tree t)                                                                                     in c-semantics.c

83      {

84        if (input_filename != last_expr_filename)

85        {

86          /* If the filename has changed, also add in a FILE_STMT. Do a string

87             compare first, though, as it might be an equivalent string.  */

88          int add = (strcmp (input_filename, last_expr_filename) != 0);

89          last_expr_filename = input_filename;

90          if (add)

91          {

92            tree pos = build_nt (FILE_STMT, get_identifier (input_filename));

93            add_stmt (pos);

94          }

95        }

96     

97        /* Add T to the statement-tree.  */

98        TREE_CHAIN (last_tree) = t;

99        last_tree = t;

100   

101      /* When we expand a statement-tree, we must know whether or not the

102        statements are full-expressions. We record that fact here.  */

103      STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();

104   

105      return t;

106    }

 

Notice that the statement is added at tail of the statement-list, however, field saved_tree of the FUNCTION_DECL still refers to the head of the list. Routine stmts_are_full_exprs_p returns true if the current statement is a full expression (i.e. temporaries created during that statement should be destroyed at the end of the statement). Field stmts_are_full_exprs_p is set as 1 at line 11299 in cxx_push_function_context .

 

306    int

307    stmts_are_full_exprs_p (void)                                                            in semantics.c

308    {

309      return current_stmt_tree ()->stmts_are_full_exprs_p;

310    }

 

Then if the compound statement defines a scope, a new scope should be pushed as sk_block or try_block.

 

364    void

365    do_pushlevel (scope_kind sk)                                                            in semantics.c

366    {

367      if (stmts_are_full_exprs_p ())

368      {

369        if (!processing_template_decl )

370          add_scope_stmt (/*begin_p=*/ 1, /*partial_p=*/ 0);

371        begin_scope (sk, NULL);

372      }

373    }

 

If it is not a template declaration, a node of SCOPE_STMT is inserted into the statement-list. Argument begin_p indicates whether this statement opens or closes a scope; partial_p is true for a partial scope, i.e, the scope that begins after a label when an object that needs a cleanup is created. In C++, scopes can be contained wholy by other scopes, but can’t be overlapped partial each other. So stack is appropriate for recording scopes, with new node represents new scope.

 

131    tree

132    add_scope_stmt (int begin_p, int partial_p)                                         in c-semantics.c

133    {

134      tree *stack_ptr = current_scope_stmt_stack ();

135      tree ss;

136      tree top = *stack_ptr;

137   

138      /* Build the statement.  */

139      ss = build_stmt (SCOPE_STMT, NULL_TREE);

140      SCOPE_BEGIN_P (ss) = begin_p;

141      SCOPE_PARTIAL_P (ss) = partial_p;

142   

143      /* Keep the scope stack up to date.  */

144      if (begin_p)

145      {

146        top = tree_cons (ss, NULL_TREE, top);

147        *stack_ptr = top;

148      }

149      else

150      {

151        if (partial_p != SCOPE_PARTIAL_P (TREE_PURPOSE (top)))

152          abort ();

153        TREE_VALUE (top) = ss;

154        *stack_ptr = TREE_CHAIN (top);

155      }

156   

157      /* Add the new statement to the statement-tree.  */

158      add_stmt (ss);

159   

160      return top;

161    }

 

The SCOPE_STMT stack mentioned above is returned by current_scope_stmt_stack .

 

1199   tree *

1200   current_scope_stmt_stack (void)                                                         in c-semantics.c

1201   {

1202     return &cfun ->language->base.x_scope_stmt_stack;

1203   }

 

At line 151 SCOPE_PARTIAL_P indicates partial scope, which for example:

     S s;

  l:

     S s2;

     goto l;

There is (implicitly) a new scope after `l', even though there are no curly braces. In particular, when we hit the goto, we must destroy s2 and then re-construct it.

Then following nodes will be created before real function-body parsing. We omit the node of last_tree here, as it always refers to the node at tail of the list.

(Click here for open )

Figure 94 : Before real function-body parsing

 

你可能感兴趣的:(function,tree,processing,token,Constructor,destructor)