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