Studying note of GCC-3.4.6 source (144)

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 )

5.12.5.2.2.3.  Finish function body handling

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 )

5.12.5.2.3.        Function-definition – finish

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.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值