5.12.5.2.2.2.2. The return expression
Returns in cp_parser_simple_declaration , “;” in “SmallObject<> object_;” makes the function return. Then cp_parser_block_declaration returns back cp_parser_declaration_statement in turn, and finish_stmt at line 6151 is executed but which does nothing as last_expr_type is already NULL. Further back cp_parser_statement , cp_parser_parse_definitely at line 5504 no doubt returns true so the function returns immediately. Then in cp_parser_statement_seq_opt , the WHILE loop again invokes cp_parser_statement to handle “return 1;” following. In the function keyword “return” causes cp_parser_jump_statement be recalled.
6057 static tree
6058 cp_parser_jump_statement (cp_parser* parser) in parser.c
6059 {
6060 tree statement = error_mark_node;
6061 cp_token *token;
6062 enum rid keyword;
6063
6064 /* Peek at the next token. */
6065 token = cp_parser_require (parser, CPP_KEYWORD, "jump-statement");
6066 if (!token)
6067 return error_mark_node;
6068
6069 /* See what kind of keyword it is. */
6070 keyword = token->keyword;
6071 switch (keyword)
6072 {
…
6096 case RID_RETURN:
6097 {
6098 tree expr;
6099
6100 /* If the next token is a `;', then there is no
6101 expression. */
6102 if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
6103 expr = cp_parser_expression (parser);
6104 else
6105 expr = NULL_TREE;
6106 /* Build the return-statement. */
6107 statement = finish_return_stmt (expr);
6108 /* Look for the final `;'. */
6109 cp_parser_require (parser, CPP_SEMICOLON, "`;'");
6110 }
6111 break ;
…
6134 }
6135
6136 return statement;
6137 }
At line 6103, cp_parser_expression guides a deep function invocation stack, which from top to down has: cp_parser_assignment_expression à cp_parser_logical_or_expression à cp_parser_logical_and_expression à cp_parser_inclusive_or_expression à cp_parser_exclusive_or_expression à cp_parser_and_expression à cp_parser_equality_expression à cp_parser_relational_expression à cp_parser_shift_expression à cp_parser_additive_expression à cp_parser_multiplicative_expression à cp_parser_pm_expression à cp_parser_simple_cast_expression à cp_parser_cast_expression à cp_parser_unary_expression à cp_parser_postfix_expression à cp_parser_primary_expression à cp_lexer_consume_token à cp_lexer_read_token à cp_lexer_get_preprocessor_token à c_lex_with_flags à interpret_integer which returns a cpp_token containing INTEGER_CST node of 1. As result, expr at line 6103 holds this cpp_token.
592 tree
593 finish_return_stmt (tree expr) in semantics.c
594 {
595 tree r;
596
597 expr = check_return_expr (expr);
598 if (!processing_template_dec l)
599 {
600 if (DECL_DESTRUCTOR_P (current_function_decl ))
601 {
602 /* Similarly, all destructors must run destructors for
603 base-classes before returning. So, all returns in a
604 destructor get sent to the DTOR_LABEL; finish_function emits
605 code to return a value there. */
606 return finish_goto_stmt (dtor_label );
607 }
608 }
609 r = add_stmt (build_stmt (RETURN_STMT, expr));
610 finish_stmt ();
611
612 return r;
613 }
Here we need to see if the function will return an aggregate object, if so it will apply so-called named return value optimization. In below function, argument retval if not NULL refers to the return expression. At line 6016 below, TREE_THIS_VOLATILE is nonzero if volatile is declared, and if a function is selected by this predicate, attribute “noreturn” is used. According to [3] (15.3.15) “If a return statement appears in the handler of a function-try-block of a constructor, the program is ill-formed”. At line 6028, in_function_try_handler if nonzero indicates such situation (refers to Build nodes for method for description of function-try-block).
Further according to [3] (expr.new.13) “[Note: unless an allocation function is declared with an empty exception-specification (15.4), throw(), it indicates failure to allocate storage by throwing a bad_alloc exception (clause 15, 18.4.2.1); it returns a non-null pointer otherwise. If the allocation function is declared with an empty exception-specification, throw(), it returns null to indicate failure to allocate storage and a non-null pointer otherwise]. If the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of the new-expression shall be null”.
So, condition at line 6100 warns about writing a new operator returns NULL inappropriately.
6004 tree
6005 check_return_expr (tree retval) in typeck.c
6006 {
6007 tree result;
6008 /* The type actually returned by the function, after any
6009 promotions. */
6010 tree valtype;
6011 int fn_returns_value_p;
6012
6013 /* A `volatile' function is one that isn't supposed to return, ever.
6014 (This is a G++ extension, used to get better code for functions
6015 that call the `volatile' function.) */
6016 if (TREE_THIS_VOLATILE (current_function_decl ))
6017 warning ("function declared `noreturn' has a `return' statement");
6018
6019 /* Check for various simple errors. */
6020 if (DECL_DESTRUCTOR_P (current_function_decl ))
6021 {
6022 if (retval)
6023 error ("returning a value from a destructor");
6024 return NULL_TREE;
6025 }
6026 else if (DECL_CONSTRUCTOR_P (current_function_decl ))
6027 {
6028 if (in_function_try_handler )
6029 /* If a return statement appears in a handler of the
6030 function-try-block of a constructor, the program is ill-formed. */
6031 error ("cannot return from a handler of a function-try-block of a constructor");
6032 else if (retval)
6033 /* You can't return a value from a constructor. */
6034 error ("returning a value from a constructor");
6035 return NULL_TREE;
6036 }
6037
6038 if (processing_template_decl )
6039 {
6040 current_function_returns_value = 1;
6041 return retval;
6042 }
6043
6044 /* When no explicit return-value is given in a function with a named
6045 return value, the named return value is used. */
6046 result = DECL_RESULT (current_function_decl );
6047 valtype = TREE_TYPE (result);
6048 my_friendly_assert (valtype != NULL_TREE, 19990924);
6049 fn_returns_value_p = !VOID_TYPE_P (valtype);
6050 if (!retval && DECL_NAME (result) && fn_returns_value_p)
6051 retval = result;
6052
6053 /* Check for a return statement with no return value in a function
6054 that's supposed to return a value. */
6055 if (!retval && fn_returns_value_p)
6056 {
6057 pedwarn ("return-statement with no value, in function returning '%T'",
6058 valtype);
6059 /* Clear this, so finish_function won't say that we reach the
6060 end of a non-void function (which we don't, we gave a
6061 return!). */
6062 current_function_returns_null = 0;
6063 }
6064 /* Check for a return statement with a value in a function that
6065 isn't supposed to return a value. */
6066 else if (retval && !fn_returns_value_p)
6067 {
6068 if (VOID_TYPE_P (TREE_TYPE (retval)))
6069 /* You can return a `void' value from a function of `void'
6070 type. In that case, we have to evaluate the expression for
6071 its side-effects. */
6072 finish_expr_stmt (retval);
6073 else
6074 pedwarn ("return-statement with a value, in function "
6075 "returning 'void'");
6076
6077 current_function_returns_null = 1;
6078
6079 /* There's really no value to return, after all. */
6080 return NULL_TREE;
6081 }
6082 else if (!retval)
6083 /* Remember that this function can sometimes return without a
6084 value. */
6085 current_function_returns_null = 1;
6086 else
6087 /* Remember that this function did return a value. */
6088 current_function_returns_value = 1;
6089
6090 /* Check for erroneous operands -- but after giving ourselves a
6091 chance to provide an error about returning a value from a void
6092 function. */
6093 if (error_operand_p (retval))
6094 {
6095 current_function_return_value = error_mark_node;
6096 return error_mark_node;
6097 }
6098
6099 /* Only operator new(...) throw(), can return NULL [expr.new/13]. */
6100 if ((DECL_OVERLOADED_OPERATOR_P (current_function_decl ) == NEW_EXPR
6101 || DECL_OVERLOADED_OPERATOR_P (current_function_decl ) == VEC_NEW_EXPR)
6102 && !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl ))
6103 && ! flag_check_new
6104 && null_ptr_cst_p (retval))
6105 warning ("`operator new' must not return NULL unless it is declared `throw()' (or -fcheck-new is in effect)");
6106
6107 /* Effective C++ rule 15. See also start_function. */
6108 if (warn_ecpp
6109 && DECL_NAME (current_function_decl ) == ansi_assopname(NOP_EXPR)
6110 && retval != current_class_ref )
6111 warning ("`operator=' should return a reference to `*this'");
6112
6113 /* The fabled Named Return Value optimization, as per [class.copy]/15:
6114
6115 [...] For a function with a class return type, if the expression
6116 i n the return statement is the name of a local object, and the cv-
6117 unqualified type of the local object is the same as the function
6118 return type, an implementation is permitted to omit creating the tem-
6119 porary object to hold the function return value [...]
6120
6121 So, if this is a value-returning function that always returns the same
6122 local variable, remember it.
6123
6124 It might be nice to be more flexible, and choose the first suitable
6125 variable even if the function sometimes returns something else, but
6126 then we run the risk of clobbering the variable we chose if the other
6127 returned expression uses the chosen variable somehow. And people expect
6128 this restriction, anyway. (jason 2000-11-19)
6129
6130 See finish_function, cxx_expand_function_start, and
6131 cp_copy_res_decl_for_inlining for other pieces of this
6132 optimization. */
6133
6134 if (fn_returns_value_p && flag_elide_constructors )
6135 {
6136 if (retval != NULL_TREE
6137 && (current_function_return_value == NULL_TREE
6138 || current_function_return_value == retval)
6139 && TREE_CODE (retval) == VAR_DECL
6140 && DECL_CONTEXT (retval) == current_function_decl
6141 && ! TREE_STATIC (retval)
6142 && (DECL_ALIGN (retval)
6143 >= DECL_ALIGN (DECL_RESULT (current_function_decl )))
6144 && same_type_p ((TYPE_MAIN_VARIANT
6145 (TREE_TYPE (retval))),
6146 (TYPE_MAIN_VARIANT
6147 (TREE_TYPE (TREE_TYPE (current_function_decl ))))))
6148 current_function_return_value = retval;
6149 else
6150 current_function_return_value = error_mark_node;
6151 }
6152
6153 /* We don't need to do any conversions when there's nothing being
6154 returned. */
6155 if (!retval)
6156 return NULL_TREE;
6157
6158 /* Do any required conversions. */
6159 if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl ))
6160 /* No conversions are required. */
6161 ;
6162 else
6163 {
6164 /* The type the function is declared to return. */
6165 tree functype = TREE_TYPE (TREE_TYPE (current_function_decl ));
6166
6167 /* First convert the value to the function's return type, then
6168 to the type of return value's location to handle the
6169 case that functype is smaller than the valtype. */
6170 retval = convert_for_initialization
6171 (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
6172 "return", NULL_TREE, 0);
6173 retval = convert (valtype, retval);
6174
6175 /* If the conversion failed, treat this just like `return;'. */
6176 if (retval == error_mark_node)
6177 return retval;
6178 /* We can't initialize a register from a AGGR_INIT_EXPR. */
6179 else if (! current_function_returns_struct
6180 && TREE_CODE (retval) == TARGET_EXPR
6181 && TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
6182 retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
6183 TREE_OPERAND (retval, 0));
6184 else
6185 maybe_warn_about_returning_address_of_local (retval);
6186 }
6187
6188 /* Actually copy the value returned into the appropriate location. */
6189 if (retval && retval != result)
6190 retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
6191
6192 return retval;
6193 }
Still in [3] (class.copy.15) “When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy operations is permitted in the following circumstances (which may be combined to eliminate multiple copies):
in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value
when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
For example:
class Thing {
public :
Thing();
~Thing();
Thing(const Thing&);
};
Thing f() {
Thing t;
return t;
}
Thing t2 = f();
Here the criteria for elision can be combined to eliminate two calls to the copy constructor of class Thing: the copying of the local automatic object t into the temporary object for the return value of function f() and the copying of that temporary object into object t2. Effectively, the construction of the local object t can be viewed as directly initializing the global object t2, and that object’s destruction will occur at program exit.”
If above circumstances are satisfied, we need prepare for coming named return value optimization. Here it makes current_function_return_value to hold the return expression for the purpose.
Back finish_return_stmt , for our return expression “return 1;”, check_return_expr does nothing but returns the expression. In the function, if a destructor contains the “return;” statement, this statement will be replaced by a “goto `dtor_label`” statement which will be expanded to code correctly destorying base classes later. Then adds the RETURN_STMT into the stmt-tree hold by cfun and returns RETURN_STMT which is returned by cp_parser_statement further, then the closing brace “}” causes cp_parser_statement_seq_opt return (note “)” is not consumed by the function). Next it back cp_parser_compound_statement to finish the compound statement composing the funciton-body. After consuming “}”, it returns cp_parser_function_body , then cp_parser_ctor_initializer_opt_and_function_body . At this point, we get:
(Click here for open )
Now argument compstmt of finish_function_body is the COMPOUND_STMT created in begin_function_body . In this function, finish_constructor_body is empty funciton, while finish_destructor_body is a complex one, and we will return to it later. After running finish_compound_stmt , we then get:
(Click here for open )
Next in cp_parser_ctor_initializer_opt_and_function_body , finish_function_body is studied in section At finish . Then back cp_parser_function_definition_after_declarator , finish_function is described in section Finish function handling , here we have a look at something about named return value optimization.
10815 tree
10816 finish_function (int flags) in decl.c
10817 {
10818 tree fndecl = current_function_decl ;
10819 tree fntype, ctype = NULL_TREE;
10820 int inclass_inline = (flags & 2) != 0;
10821 int nested;
…
10911 /* Set up the named return value optimization, if we can. Here, we
10912 eliminate the copy from the nrv into the RESULT_DECL and any cleanup
10913 for the nrv. genrtl_start_function and declare_return_variable
10914 handle making the nrv and RESULT_DECL share space. */
10915 if (current_function_return_value )
10916 {
10917 tree r = current_function_return_value ;
10918 tree outer;
10919
10920 if (r != error_mark_node
10921 /* This is only worth doing for fns that return in memory--and
10922 simpler, since we don't have to worry about promoted modes. */
10923 && aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)), fndecl)
10924 /* Only allow this for variables declared in the outer scope of
10925 the function so we know that their lifetime always ends with a
10926 return; see g++.dg/opt/nrv6.C. We could be more flexible if
10927 we were to do this optimization in tree-ssa. */
10928 /* Skip the artificial function body block. */
10929 && (outer = BLOCK_SUBBLOCKS (BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl))),
10930 chain_member (r, BLOCK_VARS (outer))))
10931 {
10932
10933 DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fndecl));
10934 walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
10935 nullify_returns_r , r);
10936 }
10937 else
10938 /* Clear it so genrtl_start_function and declare_return_variable
10939 know we're not optimizing. */
10940 current_function_return_value = NULL_TREE;
10941 }
…
11008 return fndecl;
11009 }
For named return value optimization (nrv), argument data is the node referred by current_function_return_value . Being a candidate for nrv, the variable must be declared local and non-static, as result it must be a DECL_STMT in the tree of “DECL_SAVED_TREE (fndecl)”. When encountering this DECL_STMT node, the compiler replaces it with EXPR_STMT. Note that EXPR_STMT built here has type of void_type_node , compared by that built in begin_stmt_tree in start_function which has empty type slot.
3036 tree
3037 nullify_returns_r (tree* tp, int* walk_subtrees, void* data) in semantics.c
3038 {
3039 tree nrv = (tree) data;
3040
3041 /* No need to walk into types. There wouldn't be any need to walk into
3042 non-statements, except that we have to consider STMT_EXPRs. */
3043 if (TYPE_P (*tp))
3044 *walk_subtrees = 0;
3045 else if (TREE_CODE (*tp) == RETURN_STMT)
3046 RETURN_STMT_EXPR (*tp) = NULL_TREE;
3047 else if (TREE_CODE (*tp) == CLEANUP_STMT
3048 && CLEANUP_DECL (*tp) == nrv)
3049 CLEANUP_EH_ONLY (*tp) = 1;
3050 /* Replace the DECL_STMT for the NRV with an initialization of the
3051 RESULT_DECL, if needed. */
3052 else if (TREE_CODE (*tp) == DECL_STMT
3053 && DECL_STMT_DECL (*tp) == nrv)
3054 {
3055 tree init;
3056 if (DECL_INITIAL (nrv)
3057 && DECL_INITIAL (nrv) != error_mark_node)
3058 {
3059 init = build (INIT_EXPR, void_type_node,
3060 DECL_RESULT (current_function_decl ),
3061 DECL_INITIAL (nrv));
3062 DECL_INITIAL (nrv) = error_mark_node;
3063 }
3064 else
3065 init = NULL_TREE;
3066 init = build_stmt (EXPR_STMT, init);
3067 TREE_CHAIN (init) = TREE_CHAIN (*tp);
3068 STMT_LINENO (init) = STMT_LINENO (*tp);
3069 *tp = init;
3070 }
3071
3072 /* Keep iterating. */
3073 return NULL_TREE;
3074 }
Then if RETURN_STMT is found, with nrv applied, no value will be returned, so at line 3046, the return-expression is cleaned. Also see that the function always returns NULL to force a full-walk in subtree except interrupted by walk_subtrees_p in cp_walk_subtrees .
DECL_SAVED_TREE points to the STMT tree representing the function, and function walk_tree_without_duplicate will traverse the tree without more than 1 time visit, and runs function referred by func upon every node (here is simplify_aggr_init_exprs_r ).
1952 tree
1953 walk_tree_without_duplicates (tree *tp, walk_tree_fn func, void *data) in tree-inline.c
1954 {
1955 tree result;
1956 htab_t htab;
1957
1958 htab = htab_create (37, htab_hash_pointer , htab_eq_pointer , NULL);
1959 result = walk_tree (tp, func, data, htab);
1960 htab_delete (htab);
1961 return result;
1962 }
Single visit is ensured by temperary hashtable at line 1958. At line 1959, walk_tree has below definition, in which variable walk_subtrees indicates if step into the subtree. Note return statement at line 1756, it is a preorder traversal, and terminates as long as one node is handled. And in the function, roughly, WALK_SUBTREE is used to walk children of the specified node, and WALK_SUBTREE_TAIL is then used to visit siblings.
1708 tree
1709 walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_) in tree-inline.c
1710 {
1711 htab_t htab = (htab_t) htab_;
1712 enum tree_code code;
1713 int walk_subtrees;
1714 tree result;
1715
1716 #define WALK_SUBTREE(NODE) /
1717 do /
1718 { /
1719 result = walk_tree (&(NODE), func, data, htab); /
1720 if (result) /
1721 return result; /
1722 } /
1723 while (0)
1724
1725 #define WALK_SUBTREE_TAIL(NODE) /
1726 do /
1727 { /
1728 tp = & (NODE); /
1729 goto tail_recurse; /
1730 } /
1731 while (0)
1732
1733 tail_recurse:
1734 /* Skip empty subtrees. */
1735 if (!*tp)
1736 return NULL_TREE;
1737
1738 if (htab)
1739 {
1740 void **slot;
1741
1742 /* Don't walk the same tree twice, if the user has requested
1743 that we avoid doing so. */
1744 slot = htab_find_slot (htab, *tp, INSERT);
1745 if (*slot)
1746 return NULL_TREE;
1747 *slot = *tp;
1748 }
1749
1750 /* Call the function. */
1751 walk_subtrees = 1;
1752 result = (*func) (tp, &walk_subtrees, data);
1753
1754 /* If we found something, return it. */
1755 if (result)
1756 return result;
1757
1758 code = TREE_CODE (*tp);
1759
1760 #ifndef INLINER_FOR_JAVA
1761 /* Even if we didn't, FUNC may have decided that there was nothing
1762 interesting below this point in the tree. */
1763 if (!walk_subtrees)
1764 {
1765 if (STATEMENT_CODE_P (code) || code == TREE_LIST
1766 || (*lang_hooks .tree_inlining.tree_chain_matters_p) (*tp))
1767 /* But we still need to check our siblings. */
1768 WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
1769 else
1770 return NULL_TREE;
1771 }
1772
1773 /* Handle common cases up front. */
1774 if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
1775 #else /* INLINER_FOR_JAVA */
…
1779 #endif /* INLINER_FOR_JAVA */
1780 {
1781 int i, len;
1782
1783 #ifndef INLINER_FOR_JAVA
1784 /* Set lineno here so we get the right instantiation context
1785 if we call instantiate_decl from inlinable_function_p. */
1786 if (STATEMENT_CODE_P (code) && !STMT_LINENO_FOR_FN_P (*tp))
1787 input_line = STMT_LINENO (*tp);
1788 #endif /* not INLINER_FOR_JAVA */
1789
1790 /* Walk over all the sub-trees of this operand. */
1791 len = first_rtl_op (code);
1792 /* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same.
1793 But, we only want to walk once. */
1794 if (code == TARGET_EXPR
1795 && TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
1796 --len;
1797 /* Go through the subtrees. We need to do this in forward order so
1798 that the scope of a FOR_EXPR is handled properly. */
1799 for (i = 0; i < len; ++i)
1800 WALK_SUBTREE (TREE_OPERAND (*tp, i));
1801
1802 #ifndef INLINER_FOR_JAVA
1803 /* For statements, we also walk the chain so that we cover the
1804 entire statement tree. */
1805 if (STATEMENT_CODE_P (code))
1806 {
1807 if (code == DECL_STMT
1808 && DECL_STMT_DECL (*tp)
1809 && DECL_P (DECL_STMT_DECL (*tp)))
1810 {
1811 /* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk
1812 into declarations that are just mentioned, rather than
1813 declared; they don't really belong to this part of the tree.
1814 And, we can see cycles: the initializer for a declaration can
1815 refer to the declaration itself. */
1816 WALK_SUBTREE (DECL_INITIAL (DECL_STMT_DECL (*tp)));
1817 WALK_SUBTREE (DECL_SIZE (DECL_STMT_DECL (*tp)));
1818 WALK_SUBTREE (DECL_SIZE_UNIT (DECL_STMT_DECL (*tp)));
1819 WALK_SUBTREE (TREE_TYPE (*tp));
1820 }
1821
1822 /* This can be tail-recursion optimized if we write it this way. */
1823 WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
1824 }
1825
1826 #endif /* not INLINER_FOR_JAVA */
1827 /* We didn't find what we were looking for. */
1828 return NULL_TREE;
1829 }
1830 else if (TREE_CODE_CLASS (code) == 'd')
1831 {
1832 WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
1833 }
1834 else if (TREE_CODE_CLASS (code) == 't')
1835 {
1836 WALK_SUBTREE (TYPE_SIZE (*tp));
1837 WALK_SUBTREE (TYPE_SIZE_UNIT (*tp));
1838 /* Also examine various special fields, below. */
1839 }
1840
1841 result = (*lang_hooks .tree_inlining.walk_subtrees ) (tp, &walk_subtrees, func,
1842 data, htab);
1843 if (result || ! walk_subtrees)
1844 return result;
As parameter func, in different processing, refers to different function to manipulate different part of nodes; thus, it must enter every part that maybe visited. And function pointed by func will pick out the target. Above code broadly processes nodes representing expression (class ‘e’), declaration (class ‘d’) and type (class ‘t’).
While for nodes of other classes, it first touched by language hook. At here, hook walk_subtrees refers to cp_walk_subtrees . Obviously, this function processes nodes special to C++.
1984 tree
1985 cp_walk_subtrees (tree* tp, in tree.c
1986 int* walk_subtrees_p,
1987 walk_tree_fn func,
1988 void* data,
1989 void* htab)
1990 {
1991 enum tree_code code = TREE_CODE (*tp);
1992 tree result;
1993
1994 #define WALK_SUBTREE(NODE) /
1995 do /
1996 { /
1997 result = walk_tree (&(NODE), func, data, htab); /
1998 if (result) /
1999 return result; /
2000 } /
2001 while (0)
2002
2003 /* Not one of the easy cases. We must explicitly go through the
2004 children. */
2005 switch (code)
2006 {
2007 case DEFAULT_ARG:
2008 case TEMPLATE_TEMPLATE_PARM:
2009 case BOUND_TEMPLATE_TEMPLATE_PARM:
2010 case UNBOUND_CLASS_TEMPLATE:
2011 case TEMPLATE_PARM_INDEX:
2012 case TEMPLATE_TYPE_PARM:
2013 case TYPENAME_TYPE:
2014 case TYPEOF_TYPE:
2015 case BASELINK:
2016 /* None of these have subtrees other than those already walked
2017 above. */
2018 *walk_subtrees_p = 0;
2019 break ;
2020
2021 case PTRMEM_CST:
2022 WALK_SUBTREE (TREE_TYPE (*tp));
2023 *walk_subtrees_p = 0;
2024 break ;
2025
2026 case TREE_LIST:
2027 WALK_SUBTREE (TREE_PURPOSE (*tp));
2028 break ;
2029
2030 case OVERLOAD:
2031 WALK_SUBTREE (OVL_FUNCTION (*tp));
2032 WALK_SUBTREE (OVL_CHAIN (*tp));
2033 *walk_subtrees_p = 0;
2034 break ;
2035
2036 case RECORD_TYPE:
2037 if (TYPE_PTRMEMFUNC_P (*tp))
2038 WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
2039 break ;
2040
2041 default :
2042 break ;
2043 }
2044
2045 /* We didn't find what we were looking for. */
2046 return NULL_TREE;
2047
2048 #undef WALK_SUBTREE
2049 }
If language hook can’t handle it, the node should be one of below kinds.
walk_tree (continue)
1846 /* Not one of the easy cases. We must explicitly go through the
1847 children. */
1848 switch (code)
1849 {
1850 case ERROR_MARK:
1851 case IDENTIFIER_NODE:
1852 case INTEGER_CST:
1853 case REAL_CST:
1854 case VECTOR_CST:
1855 case STRING_CST:
1856 case REAL_TYPE:
1857 case COMPLEX_TYPE:
1858 case VECTOR_TYPE:
1859 case VOID_TYPE:
1860 case BOOLEAN_TYPE:
1861 case UNION_TYPE:
1862 case ENUMERAL_TYPE:
1863 case BLOCK:
1864 case RECORD_TYPE:
1865 case CHAR_TYPE:
1866 case PLACEHOLDER_EXPR:
1867 /* None of these have subtrees other than those already walked
1868 above. */
1869 break ;
1870
1871 case POINTER_TYPE:
1872 case REFERENCE_TYPE:
1873 WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
1874 break ;
1875
1876 case TREE_LIST:
1877 WALK_SUBTREE (TREE_VALUE (*tp));
1878 WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
1879 break ;
1880
1881 case TREE_VEC:
1882 {
1883 int len = TREE_VEC_LENGTH (*tp);
1884
1885 if (len == 0)
1886 break ;
1887
1888 /* Walk all elements but the first. */
1889 while (--len)
1890 WALK_SUBTREE (TREE_VEC_ELT (*tp, len));
1891
1892 /* Now walk the first one as a tail call. */
1893 WALK_SUBTREE_TAIL (TREE_VEC_ELT (*tp, 0));
1894 }
1895
1896 case COMPLEX_CST:
1897 WALK_SUBTREE (TREE_REALPART (*tp));
1898 WALK_SUBTREE_TAIL (TREE_IMAGPART (*tp));
1899
1900 case CONSTRUCTOR:
1901 WALK_SUBTREE_TAIL (CONSTRUCTOR_ELTS (*tp));
1902
1903 case METHOD_TYPE:
1904 WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp));
1905 /* Fall through. */
1906
1907 case FUNCTION_TYPE:
1908 WALK_SUBTREE (TREE_TYPE (*tp));
1909 {
1910 tree arg = TYPE_ARG_TYPES (*tp);
1911
1912 /* We never want to walk into default arguments. */
1913 for (; arg; arg = TREE_CHAIN (arg))
1914 WALK_SUBTREE (TREE_VALUE (arg));
1915 }
1916 break ;
1917
1918 case ARRAY_TYPE:
1919 WALK_SUBTREE (TREE_TYPE (*tp));
1920 WALK_SUBTREE_TAIL (TYPE_DOMAIN (*tp));
1921
1922 case INTEGER_TYPE:
1923 WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
1924 WALK_SUBTREE_TAIL (TYPE_MAX_VALUE (*tp));
1925
1926 case OFFSET_TYPE:
1927 WALK_SUBTREE (TREE_TYPE (*tp));
1928 WALK_SUBTREE_TAIL (TYPE_OFFSET_BASETYPE (*tp));
1929
1930 #ifdef INLINER_FOR_JAVA
1931 case EXIT_BLOCK_EXPR:
1932 WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 1));
1933
1934 case SAVE_EXPR:
1935 WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0));
1936 #endif /* INLINER_FOR_JAVA */
1937
1938 default :
1939 abort ();
1940 }
1941
1942 /* We didn't find what we were looking for. */
1943 return NULL_TREE;
1944
1945 #undef WALK_SUBTREE
1946 #undef WALK_SUBTREE_TAIL
1947 }
In above code, it can see that, besides the size of type node, func processes operands of expression.