Studying note of GCC-3.4.6 source (101)

5.12.3.2.1.1.3.4.3.            Cache body for inline function

Routine start_method creates nodes for the declarator of the method-declaration; after that if the method has default argument, this (these) argument(s) should be remembered by parser into field unparsed_functions_queues . If following token is “{”, the rule of function-definition applied, which defines the inline function.

 

cp_parser_save_member_function_body (continue)

 

14656   /* Remember it, if there default args to post process.  */

14657   cp_parser_save_default_args (parser, fn);

14658

14659   /* Create a token cache.  */

14660   cache = cp_token_cache_new ();

14661   /* Save away the tokens that make up the body of the

14662     function.  */

14663   cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/ 0);

14664   /* Handle function try blocks.  */

14665   while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))

14666     cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/ 0);

14667

14668   /* Save away the inline definition; we will process it when the

14669     class is complete.  */

14670   DECL_PENDING_INLINE_INFO (fn) = cache;

14671   DECL_PENDING_INLINE_P (fn) = 1;

14672

14673   /* We need to know that this was defined in the class, so that

14674     friend templates are handled correctly.  */

14675   DECL_INITIALIZED_IN_CLASS_P (fn) = 1;

14676

14677   /* We're done with the inline definition.  */

14678   finish_method (fn);

14679

14680   /* Add FN to the queue of functions to be parsed later.  */

14681   TREE_VALUE (parser->unparsed_functions_queues)

14682     = tree_cons (NULL_TREE, fn,

14683                TREE_VALUE (parser->unparsed_functions_queues));

14684

14685   return fn;

14686 }

 

Inline function should be expanded at point of invocation, so its definition must be remembered by the parser. The parser uses blocks of type cp_token_block to cache the function definition. Every block is of size 512 bytes.

 

100    typedef struct cp_token_block GTY (())                                                     in parser.c

101    {

102      /* The tokens.  */

103      cp_token tokens[CP_TOKEN_BLOCK_NUM_TOKENS];

104      /* The number of tokens in this block.  */

105      size_t num_tokens;

106      /* The next token block in the chain.  */

107      struct cp_token_block *next;

108      /* The previous block in the chain.  */

109      struct cp_token_block *prev;

110     } cp_token_block;

 

112     typedef struct cp_token_cache GTY (())   

113     {

114       /* The first block in the cache. NULL if there are no tokens in the

115         cache.  */

116       cp_token_block *first;

117       /* The last block in the cache. NULL If there are no tokens in the

118         cache.  */

119       cp_token_block *last;

120    } cp_token_cache;

 

For every function, a cp_token_cache is associated which can chain variable number of blocks to hold the whole definition.

 

131    static cp_token_cache *

132    cp_token_cache_new (void)                                                                      in parser.c

133    {

134      return ggc_alloc_cleared (sizeof (cp_token_cache));

135    }

 

Routine cp_parser_cache_group is a recursive function, as a function can contain arbitrary number of pair of parenthesis or brace, recursive function can handle the case in much simpler form. Note that end will be either CPP_CLOSE_PAREN or CPP_CLOSE_BRACE, and first token consumed by the routine must be “{”.

 

15349 static void

15350 cp_parser_cache_group (cp_parser *parser,                                                in parser.c

15351                     cp_token_cache *cache,

15352                     enum cpp_ttype end,

15353                     unsigned depth)

15354 {

15355   while (true)

15356   {

15357     cp_token *token;

15358

15359     /* Abort a parenthesized expression if we encounter a brace.  */

15360     if ((end == CPP_CLOSE_PAREN || depth == 0)

15361         && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))

15362       return ;

15363     /* If we've reached the end of the file, stop.  */

15364     if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))

15365       return ;

15366     /* Consume the next token.  */

15367     token = cp_lexer_consume_token (parser->lexer);

15368      /* Add this token to the tokens we are saving.  */

15369     cp_token_cache_push_token (cache, token);

15370      /* See if it starts a new group.  */

15371     if (token->type == CPP_OPEN_BRACE)

15372     {

15373       cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, depth + 1);

15374       if (depth == 0)

15375         return ;

15376     }

15377     else if (token->type == CPP_OPEN_PAREN)

15378       cp_parser_cache_group (parser, cache, CPP_CLOSE_PAREN, depth + 1);

15379     else if (token->type == end)

15380       return ;

15381   }

15382 }

 

Normally, matching close parenthesis or close brace satisfies condition at line 15379, and makes the function exit gracefully. However, condition at line 15360 is not the one described by the comment, semicolon within parenthesis pair instead of brace will hold. For example, inline function:

void m1() {

   for (int j = 0 ; j < 10; j++)

{

 

}

}

The cache triggered by the open parenthesis contains only tokens in red, rest tokens ahead of the close parenthesis are saved in the cache started by the open brace at beginning of the functionbody.

 

139    static void

140    cp_token_cache_push_token (cp_token_cache *cache,                                 in parser.c

141                             cp_token *token)

142    {

143      cp_token_block *b = cache->last;

144   

145      /* See if we need to allocate a new token block.  */

146      if (!b || b->num_tokens == CP_TOKEN_BLOCK_NUM_TOKENS)

147      {

148        b = ggc_alloc_cleared (sizeof (cp_token_block));

149        b->prev = cache->last;

150        if (cache->last)

151        {

152          cache->last->next = b;

153          cache->last = b;

154        }

155        else

156          cache->first = cache->last = b;

157      }

158      /* Add this token to the current token block.  */

159      b->tokens[b->num_tokens++] = *token;

160    }

5.12.3.2.1.1.3.4.4.            Exit from the binding scope of the method

At time seeing the declarator of the method, the front-end pushes the binding scope of the method and makes it current ones, now we step over the closing brace for the function definition, it should pop the effective binding scope up.

 

11111  tree

11112  finish_method (tree decl)                                                                                 in decl.c

11113  {

11114    tree fndecl = decl;

11115    tree old_initial;

11116 

11117    tree link;

11118 

11119    if (decl == void_type_node)

11120     return decl;

11121

11122   old_initial = DECL_INITIAL (fndecl);

11123

11124   /* Undo the level for the parms (from start_method).

11125     This is like poplevel, but it causes nothing to be

11126     saved. Saving information here confuses symbol-table

11127     output routines. Besides, this information will

11128     be correctly output when this method is actually

11129     compiled.  */

11130

11131   /* Clear out the meanings of the local variables of this level;

11132     also record in each decl which block it belongs to.  */

11133

11134   for (link = current_binding_level ->names; link; link = TREE_CHAIN (link))

11135   {

11136     if (DECL_NAME (link) != NULL_TREE)

11137       pop_binding (DECL_NAME (link), link);

11138     my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163);

11139     DECL_CONTEXT (link) = NULL_TREE;

11140   }

11141

11142   poplevel (0, 0, 0);

11143

11144   DECL_INITIAL (fndecl) = old_initial;

11145

11146   /* We used to check if the context of FNDECL was different from

11147     current_class_type as another way to get inside here. This didn't work

11148     for String.cc in libg++.  */

11149   if (DECL_FRIEND_P (fndecl))

11150   {

11151     CLASSTYPE_INLINE_FRIENDS (current_class_type )

11152        = tree_cons (NULL_TREE, fndecl, CLASSTYPE_INLINE_FRIENDS (current_class_type ));

11153     decl = void_type_node;

11154   }

11155

11156   return decl;

11157 }

 

Our constructor only has an empty body, as result, finish_method and its callee only request leave_scope for the operation. Then seeing that the node of the scope is disconnected from the scopes chain, and linked into free_binding_level now.

(Click here for open )

Figure 72 : FUNCTION_DECL for ctor of “Lock” – leaving the scope

5.12.3.2.1.1.3.4.5.            Insert constructor into the class

Go back cp_parser_member_declaration , next finish_member_declaration finishes the method declaraction. Below, as the constructor declared within struct, in pushclass at line 5482, current_access_specifier is set as access_public_node .

 

2089   void

2090   finish_member_declaration (tree decl)                                                in semantics.c

2091   {

2092     if (decl == error_mark_node || decl == NULL_TREE)

2093       return ;

2094  

2095     if (decl == void_type_node)

2096       /* The COMPONENT was a friend, not a member, and so there's

2097         nothing for us to do.  */

2098       return ;

2099  

2100     /* We should see only one DECL at a time.  */

2101     my_friendly_assert (TREE_CHAIN (decl) == NULL_TREE, 0);

2102  

2103     /* Set up access control for DECL.  */

2104     TREE_PRIVATE (decl)

2105         = (current_access_specifier == access_private_node);

2106     TREE_PROTECTED (decl)

2107         = (current_access_specifier == access_protected_node);

2108     if (TREE_CODE (decl) == TEMPLATE_DECL)

2109     {

2110       TREE_PRIVATE (DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl);

2111       TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl);

2112     }

2113  

2114     /* Mark the DECL as a member of the current class.  */

2115     DECL_CONTEXT (decl) = current_class_type ;

2116  

2117     /* [dcl.link]

2118  

2119       A C language linkage is ignored for the names of class members

2120       and the member function type of class member functions.  */

2121     if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c)

2122       SET_DECL_LANGUAGE (decl, lang_cplusplus);

2123  

2124     /* Put functions on the TYPE_METHODS list and everything else on the

2125       TYPE_FIELDS list. Note that these are built up in reverse order.

2126       We reverse them (to obtain declaration order) in finish_struct.  */

2127     if (TREE_CODE (decl) == FUNCTION_DECL

2128         || DECL_FUNCTION_TEMPLATE_P (decl))

2129     {

2130       /* We also need to add this function to the

2131          CLASSTYPE_METHOD_VEC.  */

2132       add_method (current_class_type , decl, /*error_p=*/ 0);

2133  

2134       TREE_CHAIN (decl) = TYPE_METHODS (current_class_type );

2135       TYPE_METHODS (current_class_type ) = decl;

2136  

2137       maybe_add_class_template_decl_list (current_class_type , decl,

2138                                      /*friend_p=*/ 0);

2139     }

2140     /* Enter the DECL into the scope of the class.  */

2141     else if ((TREE_CODE (decl) == USING_DECL && TREE_TYPE (decl))

2142            || pushdecl_class_level (decl))

2143     {

         

2172     }

2173   }

 

Now it can insert the method into the node of the containing class. In front-end, class keeps a vector to store all methods declared within. For constructor and destructor, they are commonly used methods, so they are placed at fix position (0 for constructor, 1 for destructor).

 

721    void

722    add_method (tree type, tree method, int error_p)                                        in class.c

723    {

724      int using;

725      int len;

726      int slot;

727      tree method_vec;

728      int template_conv_p;

729   

730      if (method == error_mark_node)

731        return ;

732     

733      using = (DECL_CONTEXT (method) != type);

734      template_conv_p = (TREE_CODE (method) == TEMPLATE_DECL

735                         && DECL_TEMPLATE_CONV_FN_P (method));

736   

737      if (!CLASSTYPE_METHOD_VEC (type))

738        /* Make a new method vector. We start with 8 entries. We must

739          allocate at least two (for constructors and destructors), and

740          we're going to end up with an assignment operator at some point

741          as well.

742          

743          We could use a TREE_LIST for now, and convert it to a TREE_VEC

744          in finish_struct, but we would probably waste more memory

745          making the links in the list than we would by over-allocating

746          the size of the vector here. Furthermore, we would complicate

747          all the code that expects this to be a vector.  */

748        CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);

749   

750      method_vec = CLASSTYPE_METHOD_VEC (type);

751      len = TREE_VEC_LENGTH (method_vec);

752   

753      /* Constructors and destructors go in special slots.  */

754      if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))

755        slot = CLASSTYPE_CONSTRUCTOR_SLOT;

756      else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))

757      {

758        slot = CLASSTYPE_DESTRUCTOR_SLOT;

759        TYPE_HAS_DESTRUCTOR (type) = 1;

760         

761        if (TYPE_FOR_JAVA (type))

762          error (DECL_ARTIFICIAL (method)

763               ? "Java class '%T' cannot have an implicit non-trivial destructor"

764               : "Java class '%T' cannot have a destructor",

765                 DECL_CONTEXT (method));

766      }

767      else

768      {

         

866      }

867         

868      if (processing_template_decl )

869        /* TYPE is a template class. Don't issue any errors now; wait

870          until instantiation time to complain.  */

871         ;

872      else

873      {

         

949      }

950   

951      /* Actually insert the new method.  */

952      TREE_VEC_ELT (method_vec, slot)

953         = build_overload (method, TREE_VEC_ELT (method_vec, slot));

954   

955      /* Add the new binding.  */

956      if (!DECL_CONSTRUCTOR_P (method)

957         && !DECL_DESTRUCTOR_P (method))

958        push_class_level_binding (DECL_NAME (method),

959                              TREE_VEC_ELT (method_vec, slot));

960    }

 

Further, for class template declaration, maybe_add_class_template_decl_list also records the method in decl_list of the containing template class.

(Click here for open )

Figure 73 : Insert default constructor into class

 

你可能感兴趣的:(Studying note of GCC-3.4.6 source (101))