GCC-3.4.6源代码学习笔记(144)

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 。在这一点上,我们有:

点此打开

5.12.5.2.2.3.  完成函数体处理

此时, finish_function_body 的参数 compstmt 是在 begin_function_body 中构建的 COMPOUND_STMT 。在该函数中, finish_constructor_body 是空函数,而 finish_destructor_body 是一个复杂的函数,我们在后面来看它。在 finish_compound_stmt 运行后,我们得到:

点此打开

5.12.5.2.3.        函数定义 完成

接着在 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 处理的是表达式中的操作数。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值