5.12.5.2.2.2.2. Return 表达式
返回到 cp_parser_simple_declaration ,在“ SmallObject<> object_; ”中的“ ; ”使得该函数返回。然后从 cp_parser_block_declaration 返回到 cp_parser_declaration_statement ,在 6151 行执行 finish_stmt ,但该函数不做任何事,因为 last_expr_type 已经是 NULL 。接着返回至 cp_parser_statement ,在 5504 行的 cp_parser_parse_definitely 毫无疑问地返回了 true ,因而该函数立即返回。那么在 cp_parser_statement_seq_opt ,其 WHILE 循环再一次调用 cp_parser_statement 来处理接下来的“ return 1; ”。在这个函数中关键字“ return ”使得函数 cp_parser_jump_statement 被调用。
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 }
在 6103 行, cp_parser_expression 引导了一个深的函数调用栈,其中从上到下有: 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 , interpret_integer 返回了一个包含值为 1 的 INTEGER_CST 节点的 cpp_token 。结果,在 6103 行的 expr 保存了这个 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 }
在这里我们需要查看该函数是否会返回一个聚集对象,如果是这样的话,将应用所谓的具名返回值优化( named return value optimization )。在下面的还是中,参数 retval 如果不是 NULL ,指向 return 表达式。在下面的 6016 行, TREE_THIS_VOLATILE 是非 0 值,如果在声明中使用了 volatile ,而如果一个函数被这个谓词所选中,属性“ noreturn ”被应用。根据【 3 】( 15.3.15 )“如果一个 return 语句出现在一个构造函数的 function-try-block 的局部中,该程序非法”。在 6028 行, in_function_try_handler 如果是非 0 值,表示这样的情形( function-try-block 的描述参考 为方法构建节点 )。
接着根据【 3 】( expr.new.13 )“ [ 注意:除非一个分配函数被声明为具有一个空的异常规范( exception-specification , (15.4) ), throw() ,它将通过抛出一个 bad_alloc 异常来显示内存分配的失败(条文 15 , 18.4.2 .1 );否则它返回一个非空指针。如果该分配函数被声明为具有空的异常规范, throw() ,它返回 null 来显示分配失败,反之一个非空指针 ] 。如果该分配函数返回 null ,不应该执行初始化,也不应该调用释放函数,并且该 new 表达式( new-expression )的值应该是 null ”。
因此,在 6100 行的条件警告不恰当返回 NULL 的 new 操作符。
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 }
仍然在【 3 】( class.copy.15 )“当符合某些标准时( certain criteria ),一个实现允许忽略一个类对象的拷贝构造函数,即便该拷贝构造函数及或该类对象的析构函数是有副作用的( side effects )。在这种情形下,该实现视该被忽略的拷贝操作的源及目标,为同一个对象的 2 种不同的引用方式;并且该对象的析构发生在后一些时候,当这两个对象在没有优化的情况下都应该已经被析构时。这个拷贝操作省略在以下情况中是允许的(它们可能组合起来消除多个拷贝):
在一个具有类返回类型函数的一个 return 语句中,当该表达式是一个非易变( non-volatile )自动对象的名字,且该对象与函数返回类型,除 cv 限定词( cv-qualifier )外,相同;通过把该自动对象直接构建入该函数的返回值,可以省略这个拷贝操作。
一个没有绑定到引用( 12.2 )的临时类对象,当它将被拷贝入一个除 cv 限定词( cv-qualifier )外,类型相同的类对象时;通过把该临时对象直接构建入拷贝的目标,可以省略这个拷贝操作。
例如:
class Thing {
public :
Thing();
~Thing();
Thing(const Thing&);
};
Thing f() {
Thing t;
return t;
}
Thing t2 = f();
在这里省略的准则可以组合起来消除对类 Thing 的拷贝构造函数的两次调用:把局部自动对象 t 拷贝入用于函数 f() 返回值的临时对象,及把该临时对象拷贝入对象 t2 。奏效地,局部对象 t 的构造可以被看作是直接初始化全局对象 t2 ,并且该对象的析构将在程序结束时发生。”
如果满足上面的情况,我们需要为将要到来的具名返回值优化做准备。在这里出于这个目的,使用 current_function_return_value 来保存返回表达式。
回到 finish_return_stmt ,对于我们的 return 表达式“ return 1; ”, check_return_expr 不做任何事只是返回该表达式。在该函数中,如果一个析构函数包含这个“ return; ”语句,这个语句将被一个“ goto `dtor_label` ”语句所替代,这个语句随后将被展开为能正确析构基类的代码。接着把这个 RETURN_STMT 加入到由 cfun 持有的 stmt-tree ,并且返回 RETURN_STMT ,该语句接着被 cp_parser_statement 返回。然后右大括号“ } ”使得 cp_parser_statement_seq_opt 返回(注意“ ) ”不被该函数所消化)。接着回到 cp_parser_compound_statement 完成组成函数体的复合语句。在消化了“ } ”之后,返回 cp_parser_function_body ,然后是 cp_parser_ctor_initializer_opt_and_function_body 。在这一点上,我们有:
( 点此打开 )
此时, finish_function_body 的参数 compstmt 是在 begin_function_body 中构建的 COMPOUND_STMT 。在该函数中, finish_constructor_body 是空函数,而 finish_destructor_body 是一个复杂的函数,我们在后面来看它。在 finish_compound_stmt 运行后,我们得到:
( 点此打开 )
接着在 cp_parser_ctor_initializer_opt_and_function_body 中, finish_function_body 已经在 完成阶段 一节中看过了。那么回到 cp_parser_function_definition_after_declarator ,在 完成函数处理 一节描述过了 finish_function ,在这里我们看一下关于具名返回值优化的内容。
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 }
对于具名返回值优化( nrv ),参数 data 是由 current_function_return_value 引用的节点。作为 nrv 的候选者,该变量必须被声明为局部及非静态的,结果它必须是树“ DECL_SAVED_TREE (fndecl) ”中的应该 DECL_STMT 节点。在 10934 行的遍历中,当碰到这个 DECL_STMT 节点时,编译器把它替换为 EXPR_STMT 。注意到这里构建的 EXPR_STMT 具有类型 void_type_node ,比较那些在 start_function 的 begin_stmt_tree 中构建的,它们有空的 type 域。
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 }
那么如果找到 RETURN_STMT ,在应用 nrv 的情形下,将不会返回值,因此在 3046 行,相应的 return 表达式( return-expression )被清除。同样看到该函数总是返回来强制完整遍历,除非被 cp_walk_subtrees 的 walk_subtrees_p 打断。
DECL_SAVED_TREE 指向代表该函数的 STMT 树,函数 walk_tree_without_duplicate 将遍历该树,确保只访问每个节点一次,并且在每个访问的节点上运行 func 所指向的函数(这里是 nullify_returns_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 }
节点访问的单次性由 1958 行的临时哈希表保证。 1959 行的 walk_tree 的定义如下。在该函数中,变量 walk_subtrees 表示是否需要步入下一级子树。注意 1756 行的 return 语句,该遍历为前序遍历,只要一个节点得到处理,就结束。在函数开头定义的宏,大致说来, WALK_SUBTREE 用于访问指定节点的子节点,而 WALK_SUBTREE_TAIL 用于访问兄弟节点。
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;
因为参数 func 在不同的处理中,会指向不同的函数,处理节点不同的部分;因此,必须把所有可能被访问的部分都跑到。 Func 指向的函数会挑出需要被处理的部分。而上面部分的代码笼统地处理代表表达式(类别‘ e ’)、声明(类别‘ d ’)、类型(类别‘ t ’)的节点。
而对于其它类别的节点,首先由语言钩子来着手。在这里,钩子 walk_subtrees 指向 cp_walk_subtrees 。显然,这个函数处理的节点都是 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 }
如果语言钩子都处理不了,那么节点就应该是以下列出的种类。
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 }
在上面的代码中,可以看到,除了类型节点的大小外, func 处理的是表达式中的操作数。