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

5.12.3.2.1.2.1.1.1.            处理函数之前准备数据

接下来,为展开函数体内的语句准备结构体。注意到在 begin_stmt_tree 中的参数 t 指向 RESULT_DECL DECL_SAVED_TREE 域的地址。

 

67      void

68      begin_stmt_tree (tree *t)                                                                   in c-semantics.c

69      {

70        /* We create a trivial EXPR_STMT so that last_tree is never NULL in

71          what follows. We remove the extraneous statement in

72          finish_stmt_tree.  */

73        *t = build_nt (EXPR_STMT, void_zero_node);

74        last_tree = *t;

75        last_expr_type = NULL_TREE;

76        last_expr_filename = input_filename;

77      }

 

在处理之前语句链表必须由一个伪 EXPR_STMT 节点结尾。并且这个 EXPR_STMT 节点将在处理完成时移除。在上面, last_* 是访问作用域节点相关域的宏。

 

300    #define last_tree (current_stmt_tree ()->x_last_stmt)                            in c-common.h

 

316    stmt_tree

317    current_stmt_tree (void)                                                                   in semantics.c

318    {

319      return (cfun

320            ? &cfun ->language->base.x_stmt_tree

321            : &scope_chain ->x_stmt_tree);

322    }

 

现在,因为是在处理方法, cfun 已经为 start_function 10360 行的 allocate_struct_function 所分配。因此在这里,我们先看一下 cfun 的构建。

 

6434   void

6435   allocate_struct_function (tree fndecl)                                                         in function.c

6436   {

6437     tree result;

6438  

6439     cfun = ggc_alloc_cleared (sizeof (struct function));

6440  

6441     max_parm_reg = LAST_VIRTUAL_REGISTER + 1;

6442  

6443     cfun ->stack_alignment_needed = STACK_BOUNDARY;

6444     cfun ->preferred_stack_boundary = STACK_BOUNDARY;

6445  

6446     current_function_funcdef_no = funcdef_no ++;

6447  

6448     cfun ->function_frequency = FUNCTION_FREQUENCY_NORMAL;

6449  

6450     init_stmt_for_function ();

6451     init_eh_for_function ();

6452  

6453     (*lang_hooks .function.init ) (cfun );

6454     if (init_machine_status)

6455       cfun ->machine = (*init_machine_status ) ();

6456  

6457     if (fndecl == NULL)

6458       return ;

6459  

6460     DECL_SAVED_INSNS (fndecl) = cfun ;

6461     cfun ->decl = fndecl;

6462  

6463     result = DECL_RESULT (fndecl);

6464     if (aggregate_value_p (result, fndecl))

6465     {

6466   #ifdef PCC_STATIC_STRUCT_RETURN

6467       current_function_returns_pcc_struct = 1;

6468   #endif

6469       current_function_returns_struct = 1;

6470     }

6471  

6472     current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result));

6473  

6474     current_function_needs_context

6475       = (decl_function_context (current_function_decl ) != 0

6476          && ! DECL_NO_STATIC_CHAIN (current_function_decl ));

6477   }

 

其细节可参考章节: 评估算术操作的代价 创建伪数上下文 。在这次调用里,参数 fndecl 指向 FUNCTION_DECL 节点。 在上面, init_stmt_for_function init_eh_for_function 仅为 cfun 创建 stmt_status eh_status 的实例。

而在 6453 行,在 C++ 前端中, cxx_push_function_context 被注册到 lang_hooks 中的 function.init 。它初始化用于编译 C++ 函数的变量。

 

11290 void

11291 cxx_push_function_context (struct function * f)                                                in decl.c

11292 {

11293   struct language_function *p

11294     = ggc_alloc_cleared (sizeof (struct language_function));

11295   f->language = p;

11296

11297   /* Whenever we start a new function, we destroy temporaries in the

11298     usual way.  */

11299   current_stmt_tree ()->stmts_are_full_exprs_p = 1;

11300

11301   if (f->decl)

11302   {

11303     tree fn = f->decl;

11304

11305     if (DECL_SAVED_FUNCTION_DATA (fn))

11306     {

11307       /* If we already parsed this function, and we're just expanding it

11308         now, restore saved state.  */

11309       *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn);

11310

11311       /* If we decided that we didn't want to inline this function,

11312         make sure the back-end knows that.  */

11313       if (!current_function_cannot_inline)

11314         current_function_cannot_inline = cp_function_chain->cannot_inline;

11315

11316        /* We don't need the saved data anymore. Unless this is an inline

11317         function; we need the named return value info for

11318         cp_copy_res_decl_for_inlining.  */

11319       if (! DECL_INLINE (fn))

11320         DECL_SAVED_FUNCTION_DATA (fn) = NULL;

11321     }

11322   }

11323 }

 

下面的 cp_function_chain 返回 cfun language 域。

 

802    #define cp_function_chain (cfun ->language)                                               in cp-tree.h

 

DECL_SAVED_FUNCTION_DATA 返回 FUNCTION_DECL 节点中的域 saved_language_function 的地址,它在该函数完成解析时被填充。但是如果 DECL_SAVED_FUNCTION_DATA 不是 NULL ,这意味着发生了函数重复定义的错误。实际上,参数 f 是在 6439 行新构建的 cfun ,它不满足 11301 行的条件,因此对于 C++ 11302 11322 行的代码不会执行(在当前版本, cxx_push_function_context 只有这一处调用)。为了记录 C++ 函数的状态,定义了以下结构体。

 

771    struct language_function GTY(())                                                              in cp-tree.h

772    {

773      struct c_language_function base;

774   

775      tree x_dtor_label;

776      tree x_current_class_ptr;

777      tree x_current_class_ref;

778      tree x_eh_spec_block;

779      tree x_in_charge_parm;

780      tree x_vtt_parm;

781      tree x_return_value;

782   

783      int returns_value;

784      int returns_null;

785      int returns_abnormally;

786      int in_function_try_handler;

787      int in_base_initializer;

788   

789      /* True if this function can throw an exception.  */

790      BOOL_BITFIELD can_throw : 1;

791   

792      struct named_label_use_list *x_named_label_uses;

793      struct named_label_list *x_named_labels;

794      struct cp_binding_level *bindings;

795      varray_type x_local_names;

796   

797      const char *cannot_inline;

798    };

 

因为 C++ 包含 C 的语法,这个结构体包含了 c_language_function 来保存与 C 相关的状态。而其它域专用于 C++

 

289    struct c_language_function GTY(()) {                                                        in c-common.h

290      /* While we are parsing the function, this contains information

291        about the statement-tree that we are building.  */

292      struct stmt_tree_s x_stmt_tree;

293      /* The stack of SCOPE_STMTs for the current function.  */

294      tree x_scope_stmt_stack;

295    };

 

为不同的机器产生代码必须考虑机器的特性,为机器产生指令时,需要使用这些信息。

 

11911 static struct machine_function *

11912 ix86_init_machine_status (void)                                                               in i386.c

11913 {

11914   struct machine_function *f;

11915

11916   f = ggc_alloc_cleared (sizeof (struct machine_function));

11917   f->use_fast_prologue_epilogue_nregs = -1;

11918

11919   return f;

11920 }

 

看到为 x86 机器定义的 machine_function 将记录,在执行函数这一点上,机器的快像( snapshot )。

 

3167   struct machine_function GTY(())                                                               in i386.h

3168   {

3169     struct stack_local_entry *stack_locals;

3170     const char *some_ld_name;

3171     int save_varrargs_registers;

3172     int accesses_prev_frame;

3173     int optimize_mode_switching;

3174     /* Set by ix86_compute_frame_layout and used by prologue/epilogue expander to

3175       determine the style used.  */

3176     int use_fast_prologue_epilogue;

3177     /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE has been computed

3178       for.  */

3179     int use_fast_prologue_epilogue_nregs;

3180   };

 

下面的 stmt_tree_s 用于保存函数体内的语句。看到在 begin_stmt_tree 73 行, x_last_stmt 将是 EXPR_STMT 的链表。

 

259    struct stmt_tree_s GTY(()) {                                                              in c-common.h

260      /* The last statement added to the tree.  */

261      tree x_last_stmt;

262      /* The type of the last expression statement. (This information is

263        needed to implement the statement-expression extension.)  */

264      tree x_last_expr_type;

265      /* The last filename we recorded.  */

266      const char *x_last_expr_filename;

267      /* In C++, Nonzero if we should treat statements as full

268        expressions. In particular, this variable is no-zero if at the

269        end of a statement we should destroy any temporaries created

270         during that statement. Similarly, if, at the end of a block, we

271        should destroy any local variables in this block. Normally, this

272        variable is nonzero, since those are the normal semantics of

273        C++.

274   

275        However, in order to represent aggregate initialization code as

276        tree structure, we use statement-expressions. The statements

277        within the statement expression should not result in cleanups

278        being run until the entire enclosing statement is complete.

279   

280        This flag has no effect in C.  */

281      int stmts_are_full_exprs_p;

282    };

283   

284    typedef struct stmt_tree_s *stmt_tree ;

 

那么在 allocate_struct_function 6460 行, DECL_SAVED_INSNS 指向 cfun 。看到当在处理下一个函数时, cfun 将在 6439 行被重新构建,而 DECL_SAVED_INSNS 将是该函数节点的唯一的引用。

进一步的,如果该函数返回聚合类型,需要产生更多的代码来传递其地址,并且可能应用特定的优化。例如:

struct A { … };

A func() { return A(); }

int main() {

    A a = func();

}

一个优化的机会就是使得 func 直接操控 a

简而言之,返回聚合类型的函数需要特殊的处理,这里由 aggregate_value_p 把它们找出来,并标记它。这个函数我们稍后再看。

 

start_function (continue)

 

10373   /* Let the user know we're compiling this function.  */

10374   announce_function (decl1);

10375

10376   /* Record the decl so that the function name is defined.

10377     If we already have a decl for this name, and it is a FUNCTION_DECL,

10378     use the old decl.  */

10379   if (!processing_template_decl && !(flags & SF_PRE_PARSED))

10380   {

          …

10405   }

10406

10407   /* Reset these in case the call to pushdecl changed them.  */

10408   current_function_decl = decl1;

10409   cfun ->decl = decl1;

10410

10411   /* If we are (erroneously) defining a function that we have already

10412     defined before, wipe out what we knew before.  */

10413   if (!DECL_PENDING_INLINE_P (decl1))

10414     DECL_SAVED_FUNCTION_DATA (decl1) = NULL;

10415

10416   if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1))

10417   {

10418     /* We know that this was set up by `grokclassfn'. We do not

10419        wait until `store_parm_decls', since evil parse errors may

10420        never get us to that point. Here we keep the consistency

10421        between `current_class_type' and `current_class_ptr'.  */

10422     tree t = DECL_ARGUMENTS (decl1);

10423

10424     my_friendly_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL,

10425                      162);

10426     my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,

10427                      19990811);

10428

10429     cp_function_chain->x_current_class_ref

10430       = build_indirect_ref (t, NULL);

10431     cp_function_chain->x_current_class_ptr = t;

10432

10433     /* Constructors and destructors need to know whether they're "in

10434        charge" of initializing virtual base classes.  */

10435     t = TREE_CHAIN (t);

10436     if (DECL_HAS_IN_CHARGE_PARM_P (decl1))

10437     {

10438        current_in_charge_parm = t;

10439        t = TREE_CHAIN (t);

10440     }

10441     if (DECL_HAS_VTT_PARM_P (decl1))

10442     {

10443        if (DECL_NAME (t) != vtt_parm_identifier)

10444          abort ();

10445        current_vtt_parm = t;

10446     }

10447   }

 

上面在 10374 announce_function 仅打印出将要编译的函数的信息。在 10416 如果 ctype 不是 NULL 可以确认正在处理方法 method 。并且如果方法不是静态的 那么在 10422 行的 DECL_ARGUMENTS 将返回 const this* 。为了可以快速地访问这个“ this ”实例,最好把这个引用及指针保存在 function 结构体里。这就是 10429 10431 行的 x_current_class_ref x_current_class_ptr 的目的。

引用由下面的函数来构建。

 

2082   tree

2083   build_indirect_ref (tree ptr, const char *errorstring)                                           in typeck.c

2084   {

2085     tree pointer, type;

2086  

2087     if (ptr == error_mark_node)

2088       return error_mark_node;

2089  

2090     if (ptr == current_class_ptr)

2091       return current_class_ref;

2092  

2093     pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE

2094             ? ptr : decay_conversion (ptr));

2095     type = TREE_TYPE (pointer);

2096  

2097     if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE)

2098     {

2099       /* [expr.unary.op]

2100       

2101          If the type of the expression is "pointer to T," the type

2102          of the result is "T."  

2103  

2104          We must use the canonical variant because certain parts of

2105          the back end, like fold, do pointer comparisons between

2106          types.  */

2107       tree t = canonical_type_variant (TREE_TYPE (type));

2108  

2109       if (VOID_TYPE_P (t))

2110       {

2111         /* A pointer to incomplete type (other than cv void) can be

2112           dereferenced [expr.unary.op]/1  */

2113         error ("`%T' is not a pointer-to-object type", type);

2114         return error_mark_node;

2115       }

2116       else if (TREE_CODE (pointer) == ADDR_EXPR

2117             && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))

2118         /* The POINTER was something like `&x'. We simplify `*&x' to

2119           `x'.  */

2120         return TREE_OPERAND (pointer, 0);

2121       else

2122       {

2123         tree ref = build1 (INDIRECT_REF, t, pointer);

2124  

2125         /* We *must* set TREE_READONLY when dereferencing a pointer to const,

2126           so that we get the proper error message if the result is used

2127           to assign to. Also, &* is supposed to be a no-op.  */

2128         TREE_READONLY (ref) = CP_TYPE_CONST_P (t);

2129         TREE_THIS_VOLATILE (ref) = CP_TYPE_VOLATILE_P (t);

2130         TREE_SIDE_EFFECTS (ref)

2131             = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer));

2132         return ref;

2133       }

2134     }

2135     /* `pointer' won't be an error_mark_node if we were given a

2136        pointer to member, so it's cool to check for this here.  */

2137     else if (TYPE_PTR_TO_MEMBER_P (type))

2138       error ("invalid use of `%s' on pointer to member", errorstring);

2139     else if (pointer != error_mark_node)

2140     {

2141       if (errorstring)

2142          error ("invalid type argument of `%s'", errorstring);

2143       else

2144          error ("invalid type argument");

2145     }

2146     return error_mark_node;

2147   }

 

上面在 2094 行, decay_conversion 不做任何事情,仅返回 ptr const this* ”的 PARM_DECL 节点。而在 2107 行, canonical_type_variant 仅是 cp_build_qualified_type 的简单封装,它创建了 cv-qualifier 的限定类型。

 

start_function (continue)

 

10449   if (DECL_INTERFACE_KNOWN (decl1))

10450   {

10451     tree ctx = decl_function_context (decl1);

10452

10453     if (DECL_NOT_REALLY_EXTERN (decl1))

10454       DECL_EXTERNAL (decl1) = 0;

10455

10456     if (ctx != NULL_TREE && DECL_DECLARED_INLINE_P (ctx)

10457        && TREE_PUBLIC (ctx))

10458      /* This is a function in a local class in an extern inline

10459         function.  */

10460      comdat_linkage (decl1);

10461   }

10462   /* If this function belongs to an interface, it is public.

10463     If it belongs to someone else's interface, it is also external.

10464      This only affects inlines and template instantiations.  */

10465   else if (interface_unknown == 0

10466          && ! DECL_TEMPLATE_INSTANTIATION (decl1))

10467   {

10468     if (DECL_DECLARED_INLINE_P (decl1)

10469         || DECL_TEMPLATE_INSTANTIATION (decl1)

10470         || processing_template_decl )

10471     {

10472        DECL_EXTERNAL (decl1)

10473               = (interface_only

10474                  || (DECL_DECLARED_INLINE_P (decl1)

10475                     && ! flag_implement_inlines

10476                    && !DECL_VINDEX (decl1)));

10477

10478        /* For WIN32 we also want to put these in linkonce sections.  */

10479        maybe_make_one_only (decl1);

10480     }

10481     else

10482       DECL_EXTERNAL (decl1) = 0;

10483     DECL_NOT_REALLY_EXTERN (decl1) = 0;

10484     DECL_INTERFACE_KNOWN (decl1) = 1;

10485   }

10486   else if (interface_unknown && interface_only

10487          && ! DECL_TEMPLATE_INSTANTIATION (decl1))

10488   {

10489     /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma

10490        interface, we will have interface_only set but not

10491        interface_known. In that case, we don't want to use the normal

10492        heuristics because someone will supply a #pragma implementation

10493        elsewhere, and deducing it here would produce a conflict.  */

10494     comdat_linkage (decl1);

10495     DECL_EXTERNAL (decl1) = 0;

10496     DECL_INTERFACE_KNOWN (decl1) = 1;

10497     DECL_DEFER_OUTPUT (decl1) = 1;

10498   }

10499   else

10500   {

10501     /* This is a definition, not a reference.

10502       So clear DECL_EXTERNAL.  */

10503     DECL_EXTERNAL (decl1) = 0;

10504

10505     if ((DECL_DECLARED_INLINE_P (decl1)

10506           || DECL_TEMPLATE_INSTANTIATION (decl1))

10507         && ! DECL_INTERFACE_KNOWN (decl1)

10508           /* Don't try to defer nested functions for now.  */

10509         && ! decl_function_context (decl1))

10510       DECL_DEFER_OUTPUT (decl1) = 1;

10511     else

10512       DECL_INTERFACE_KNOWN (decl1) = 1;

10513   }

 

上面关于 interface_unknown interface_only ,其细节参考章节 #pragma interface #pragma implementation 。对于我们的例子,没有使用“ #pragma interface ”及“ #pragma implementation ”,因此满足 10499 行。

5.12.3.2.1.2.1.1.2.            加入函数作用域

在退出该函数前,需要使所处理的函数作用域生效。注意到 sk_function_parms 专指包含函数参数的作用域。

 

start_function (continue)

 

10515   begin_scope (sk_function_parms, decl1);

10516

10517   ++function_depth ;

10518

10519   if (DECL_DESTRUCTOR_P (decl1))

10520   {

10521     dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);

10522     DECL_CONTEXT (dtor_label) = current_function_decl ;

10523   }

10524

10525   start_fname_decls ();

10526  

10527   store_parm_decls (current_function_parms);

10528

10529   return 1;

10530 }

 

然后前端需要设立代表函数名的标识符,【 6 】给出如下细节:

5.43 函数名字符串

GCC 提供了三个魔术变量来保存作为当前函数名字的字符串。第一个是 __func__ ,它是 C99 标准的一部分:

标识符 __func__ 是由编译器隐式声明的,就仿佛直接跟在每个函数定义的开大括号后面的声明:

static const char __func__[] = "function-name";

此处 function-name 是词法意义上封闭的函数( the lexically-enclosing function )的名字。这个名字是未修饰的函数名。

__FUNCTION__ 是对应 __func__ 的另一个名字。旧版本的 GCC 只能识别这个名字。不过,它不是标准的。为了达到最大可移植性,建议使用 __func__ ,不过要通过预处理器提供一个后备定义:

#if __STDC_VERSION__ < 199901L

# if __GNUC__ >= 2

# define __func__ __FUNCTION__

# else

# define __func__ "<unknown>"

# endif

#endif

C 中, __PRETTY_FUNCTION__ 则是对应 __func__ 的另一个名字。不过,在 C++ 中, __RETTY_FUNCTION__ 除了基本的名字( bare name ),还包含了函数的类型签名( type signature )。例如,程序:

extern "C" {

extern int printf (char *, ...);

}

class a {

public :

void sub (int i) {

printf ("__FUNCTION__ = %s/n", __FUNCTION__);

printf ("__PRETTY_FUNCTION__ = %s/n", __PRETTY_FUNCTION__);

}

};

int

main (void) {

a ax;

ax.sub (0);

return 0;

}

给出输出:

__FUNCTION__ = sub

__PRETTY_FUNCTION__ = void a::sub(int)

这些标识符都不是预处理宏。在 GCC 3.3 及更早的版本,仅在 C 里, __FUNCTION__ __PRETTY_FUNCTION__ 被处理作字符串;它们可以被用作字符数组的初始值,并且可以与其他字符串串接起来。 GCC 3.4 及更新的版本把它们处理作变量,比如 __func__ 。在 C++ 中, __FUNCTION__ __PRETTY_FUNCTION__ 一直是变量。

 

991    void

992    start_fname_decls (void)                                                                   in c-common.c

993    {

994      unsigned ix;

995      tree saved = NULL_TREE;

996   

997      for (ix = 0; fname_vars [ix].decl; ix++)

998      {

999        tree decl = *fname_vars [ix].decl;

1000  

1001       if (decl)

1002       {

1003         saved = tree_cons (decl, build_int_2 (ix, 0), saved);

1004         *fname_vars [ix].decl = NULL_TREE;

1005       }

1006     }

1007     if (saved || saved_function_name_decls)

1008       /* Normally they'll have been NULL, so only push if we've got a

1009         stack, or they are non-NULL.  */

1010       saved_function_name_decls = tree_cons (saved, NULL_TREE,

1011                                       saved_function_name_decls);

1012   }

 

如上面所提及的,在高于 v3.4 的编译器中, __func__ ___FUNCTION__ __PRETTY_FUNCTION__ 都被实现作标识符。结构体 fname_var_t 保存这些标识符的信息。

 

689    struct fname_var_t                                                                            in c-common.c

690    {

691      tree *const decl;      /* pointer to the VAR_DECL.  */

692      const unsigned rid;  /* RID number for the identifier.  */

693      const int pretty;       /* How pretty is it? */

694    };

695   

696    /* The three ways of getting then name of the current function.  */

697   

698    const struct fname_var_t fname_vars [] =

699    {

700      /* C99 compliant __func__, must be first.  */

701      {&c99_function_name_decl_node, RID_C99_FUNCTION_NAME, 0},

702      /* GCC __FUNCTION__ compliant.  */

703      {&function_name_decl_node, RID_FUNCTION_NAME, 0},

704      /* GCC __PRETTY_FUNCTION__ compliant.  */

705      {&pretty_function_name_decl_node, RID_PRETTY_FUNCTION_NAME, 1},

706      {NULL, 0, 0},

707    };

 

显然,这些标识符必须是全局可见并且唯一,因此它们实际上被声明在 c_global_trees 里,并且具有 RID 标签来标记为由解析器识别的特殊符号(类似保留字)。注意其中的 decl 域, c99_function_name_decl_node function_name_decl_node pretty_function_name_decl_node 更像占位符,它们都是空指针。

因此看到在 start_fname_decl 1004 行,如果 fname_vars 中的 decl 不是 NULL ,这意味着在调用函数中使用了 __func__ 等,那么在进入被调用函数前,其内容需要被被缓存到全局栈 saved_function_name_decls 中。当从被调用函数返回时,这个保存的 decl 将被恢复入 fname_vars 中,使其在调用函数余下部分可用。

当该函数域成为 current_binding_level ,需要把其参数加入该作用域,使得随后的名字查找可以找出正确的项。现在 current_function_parms 指向该函数的参数链表。

 

10538 static void

10539 store_parm_decls (tree current_function_parms)                                         in decl.c

10540 {

10541   tree fndecl = current_function_decl ;

10542   tree parm;

10543

10544   /* This is a chain of any other decls that came in among the parm

10545     declarations. If a parm is declared with enum {foo, bar} x;

10546     then CONST_DECLs for foo and bar are put here.  */

10547   tree nonparms = NULL_TREE;

10548

10549   if (current_function_parms)

10550   {

10551     /* This case is when the function was defined with an ANSI prototype.

10552       The parms already have decls, so we need not do anything here

10553       except record them as in effect

10554       and complain if any redundant old-style parm decls were written.  */

10555

10556     tree specparms = current_function_parms;

10557     tree next;

10558

10559     /* Must clear this because it might contain TYPE_DECLs declared

10560       at class level.  */

10561     current_binding_level ->names = NULL;

10562

10563     /* If we're doing semantic analysis, then we'll call pushdecl

10564         for each of these. We must do them in reverse order so that

10565       they end in the correct forward order.  */

10566     specparms = nreverse (specparms);

10567

10568     for (parm = specparms; parm; parm = next)

10569     {

10570       next = TREE_CHAIN (parm);

10571       if (TREE_CODE (parm) == PARM_DECL)

10572       {

10573         if (DECL_NAME (parm) == NULL_TREE

10574             || TREE_CODE (parm) != VOID_TYPE)

10575           pushdecl (parm);

10576         else

10577           error ("parameter `%D' declared void", parm);

10578       }

10579       else

10580       {

10581         /* If we find an enum constant or a type tag,

10582           put it aside for the moment.  */

10583         TREE_CHAIN (parm) = NULL_TREE;

10584         nonparms = chainon (nonparms, parm);

10585       }

10586     }

10587

10588     /* Get the decls in their original chain order and record in the

10589       function. This is all and only the PARM_DECLs that were

10590       pushed into scope by the loop above.  */

10591     DECL_ARGUMENTS (fndecl) = getdecls ();

10592   }

10593   else

10594     DECL_ARGUMENTS (fndecl) = NULL_TREE;

10595

10596   /* Now store the final chain of decls for the arguments

10597     as the decl-chain of the current lexical scope.

10598     Put the enumerators in as well, at the front so that

10599     DECL_ARGUMENTS is not modified.  */

10600   current_binding_level ->names = chainon (nonparms, DECL_ARGUMENTS (fndecl));

10601

10602   /* Do the starting of the exception specifications, if we have any.  */

10603   if (flag_exceptions && ! processing_template_decl

10604       && flag_enforce_eh_specs

10605       && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl )))

10606     current_eh_spec_block = begin_eh_spec_block ();

10607 }

 

这里在 10573 10574 行,再一次验证参数,如果参数是有效的,通过我们的老朋友 pushdecl 把它加入函数域。而在这一点上 current_function_decl 指向方法的 FUNCTION_DECL 节点。对于每个参数,以相反的次序调用 pushdecl 。因此对于第一次调用,“ const Host& ”的 PARM_DECL 节点是无名的。

 

566    tree

567    pushdecl (tree x)                                                                                     in name-lookup.c

568    {

569      tree t;

570      tree name;

571      int need_new_binding;

572   

573      timevar_push (TV_NAME_LOOKUP);

574   

575      need_new_binding = 1;

576   

577      if (DECL_TEMPLATE_PARM_P (x))

578        /* Template parameters have no context; they are not X::T even

579          when declared within a class or namespace.  */

580        ;

581      else

582      {

583        if (current_function_decl && x != current_function_decl

584           /* A local declaration for a function doesn't constitute

585             nesting.  */

586           && TREE_CODE (x) != FUNCTION_DECL

587           /* A local declaration for an `extern' variable is in the

588             scope of the current namespace, not the current

589             function.  */

590           && !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))

591           && !DECL_CONTEXT (x))

592          DECL_CONTEXT (x) = current_function_decl ;

593   

594        /* If this is the declaration for a namespace-scope function,

595          but the declaration itself is in a local scope, mark the

596          declaration.  */

597        if (TREE_CODE (x) == FUNCTION_DECL

598           && DECL_NAMESPACE_SCOPE_P (x)

599           && current_function_decl

600           && x != current_function_decl )

601          DECL_LOCAL_FUNCTION_P (x) = 1;

602      }

603   

604      name = DECL_NAME (x);

605      if (name)

606      {

          …

1007     }

1008  

1009     if (need_new_binding)

1010       add_decl_to_level (x,

1011                       DECL_NAMESPACE_SCOPE_P (x)

1012                       ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))

1013                       : current_binding_level );

1014  

1015     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);

1016   }

 

因为参数是无名的,因此没有 cxx_binding 节点为这个参数创建,仅把它记录在 FUNCTION_DECL names 域中。

点此打开

92 :加入“ const Host& ”的 PARM_DECL

对于我们的例子,最后一个处理的参数是“ const this* ”,它具有名字“ this ”。毫无疑问,“ this ”具有一个对应的 IDNETIFIER_NODE ,并且它需要被绑定入这个作用域。为了方便起见,我们在下面重新贴出 pushdecl 中相关的代码。可以看到加入具名参数与加入其它 DECL 节点没有什么不同。

 

566    tree

567    pushdecl (tree x)                                                                                     in name-lookup.c

568    {

569      tree t;

570      tree name;

571      int need_new_binding;

572   

573      timevar_push (TV_NAME_LOOKUP);

574   

575      need_new_binding = 1;

576   

577      if (DECL_TEMPLATE_PARM_P (x))

578        /* Template parameters have no context; they are not X::T even

579          when declared within a class or namespace.  */

580         ;

581      else

582      {

583        if (current_function_decl && x != current_function_decl

584           /* A local declaration for a function doesn't constitute

585             nesting.  */

586           && TREE_CODE (x) != FUNCTION_DECL

587           /* A local declaration for an `extern' variable is in the

588             scope of the current namespace, not the current

589             function.  */

590           && !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))

591           && !DECL_CONTEXT (x))

592          DECL_CONTEXT (x) = current_function_decl ;

593   

594        /* If this is the declaration for a namespace-scope function,

595          but the declaration itself is in a local scope, mark the

596          declaration.  */

597        if (TREE_CODE (x) == FUNCTION_DECL

598           && DECL_NAMESPACE_SCOPE_P (x)

599           && current_function_decl

600           && x != current_function_decl )

601          DECL_LOCAL_FUNCTION_P (x) = 1;

602      }

603   

604      name = DECL_NAME (x);

605      if (name)

606      {

607        int different_binding_level = 0;

608   

609        if (TREE_CODE (x) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (x))

610          check_default_args (x);

611    

612        if (TREE_CODE (name) == TEMPLATE_ID_EXPR)

613          name = TREE_OPERAND (name, 0);

614   

615        /* In case this decl was explicitly namespace-qualified, look it

616          up in its namespace context.  */

617        if (DECL_NAMESPACE_SCOPE_P (x) && namespace_bindings_p ())

618          t = namespace_binding (name, DECL_CONTEXT (x));

619        else

620          t = lookup_name_current_level (name);

           ...

743        check_template_shadow (x);

          ...

828        /* This name is new in its binding level.

829          Install the new declaration and return it.  */

830        if ( namespace_bindings_p ())

831        {

            ...

872        }

873        else

874        {

875           /* Here to install a non-global value.  */

876          tree oldlocal = IDENTIFIER_VALUE (name);

877          tree oldglobal = IDENTIFIER_NAMESPACE_VALUE (name);

878   

879          if (need_new_binding)

880          {

881               push_local_binding (name, x, 0);

882               /* Because push_local_binding will hook X on to the

883              current_binding_level's name list, we don't want to

884              do that again below.  */

885             need_new_binding = 0;

886          }

            ...

898          if (oldlocal)

899          {

900            tree d = oldlocal;

901   

902            while (oldlocal

903                  && TREE_CODE (oldlocal) == VAR_DECL

904                  && DECL_DEAD_FOR_LOCAL (oldlocal))

905              oldlocal = DECL_SHADOWED_FOR_VAR (oldlocal);

906   

907            if (oldlocal == NULL_TREE)

908              oldlocal = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (d));

909          }

910   

911           /* If this is an extern function declaration, see if we

912            have a global definition or declaration for the function.  */

913          if (oldlocal == NULL_TREE

914             && DECL_EXTERNAL (x)

915             && oldglobal != NULL_TREE

916             && TREE_CODE (x) == FUNCTION_DECL

917             && TREE_CODE (oldglobal) == FUNCTION_DECL)

918          {

              …

927          }

928          /* If we have a local external declaration,

929            and no file-scope declaration has yet been seen,

930            then if we later have a file-scope decl it must not be static.  */

931          if (oldlocal == NULL_TREE

932             && oldglobal == NULL_TREE

933             && DECL_EXTERNAL (x)

934             && TREE_PUBLIC (x))

935            TREE_PUBLIC (name) = 1;

936   

937          /* Warn if shadowing an argument at the top level of the body.  */

938          if (oldlocal != NULL_TREE && !DECL_EXTERNAL (x)

939              /* Inline decls shadow nothing.  */

940             && !DECL_FROM_INLINE (x)

941             && TREE_CODE (oldlocal) == PARM_DECL

942             /* Don't check the `this' parameter.  */

943             && !DECL_ARTIFICIAL (oldlocal))

944          {

              …

971          }

972   

973          /* Maybe warn if shadowing something else.  */

974          else if (warn_shadow && !DECL_EXTERNAL (x)

975                /* No shadow warnings for internally generated vars.  */

976                && ! DECL_ARTIFICIAL (x)

977                /* No shadow warnings for vars made for inlining.  */

978                && ! DECL_FROM_INLINE (x))

979          {

              …

1002         }

1003       }

1004  

1005       if (TREE_CODE (x) == VAR_DECL)

1006          maybe_register_incomplete_var (x);

1007     }

1008  

1009     if (need_new_binding)

1010       add_decl_to_level (x,

1011                       DECL_NAMESPACE_SCOPE_P (x)

1012                       ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))

1013                       : current_binding_level);

1014  

1015     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);

1016   }

 

上面在 881 行, push_local_binding 构建了 cxx_binding 节点,并且利用它把这个 IDENTIFIER_NODE 绑定在这个作用域中。当该标识符在代码中出现多于一次时,需要检查是否会引入危险。上面 876 行, IDENTIFIER_VALUE 返回在非名字空间作用域中的最后的同名声明,而 IDENTIFIER_NAMESPACE_VALUE 返回在最里层的起效名字空间作用域中的最后的同名声明。 那么 902 行, WHILE 循环跳过了声明在局部块(比如, FOR 块)中的变量。在 908 行,如果没有找到不在名字空间及局部块中的声明, oldlocal 将得到在名字空间作用域中的声明。参数“ const this* ”是由前端产生的,它设置了 DECL_ARTIFICIAL 标记。接着,通过 getdecls 更新 FUNCTION_DECL arguments 域为绑定在该作用域的名字。

 

1533   tree

1534   getdecls (void)                                                                                  in name-lookup.c

1535   {

1536     return current_binding_level ->names;

1537   }

 

那么我们将得到如下的图形。注意,在 PARM_DECL 节点中的“ this ”表示对应的 IDENTIFIER_NODE 。从“ this ”到 cxx_binding 的连线,表示 IDENTIFIER_BINDING

点此打开

93 :加入“ const this* ”的 PARM_DECL

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值