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

4.3.1.7.8.            完成初始化

下面的 abort_fndecl 代表函数 abort ,而函数 build_library_fn_ptr build_library_fn 相仿,不过它接受字符串作为名字,而不是标识符节点。

 

cxx_init_decl_processing (continue)

 

3115     abort_fndecl

3116       = build_library_fn_ptr ("__cxa_pure_virtual", void_ftype);

3117

3118     /* Perform other language dependent initializations.  */

3119     init_class_processing ();

3120     init_search_processing ();

3121     init_rtti_processing ();

3122  

3123     if (flag_exceptions )

3124       init_exception_processing ();

3125  

3126     if (! supports_one_only ())

3127       flag_weak = 0;

3128  

3129     make_fname_decl = cp_make_fname_decl;

3130     start_fname_decls ();

3131  

3132     /* Show we use EH for cleanups.  */

3133     using_eh_for_cleanups ();

3134  

3135     /* Maintain consistency. Perhaps we should just complain if they

3136      say -fwritable-strings?  */

3137     if (flag_writable_strings )

3138       flag_const_strings = 0;

3139   }

4.3.1.7.8.1.  初始化类处理参数

在处理类声明时, GCC 使用以下的全局变量来控制其处理过程。其中 current_class_depth 表示当前类的嵌套深度,这些嵌套的类毫无疑问构成了一个栈,这就是 current_class_stack ,而 current_class_stack_size 就是栈的当前大小。 GNU C++ 有一个扩展,允许在函数体中定义类,当然这个类只能在该函数体内可见,为了与其他类区别,它们被保存在 local_classes 中。

 

5424   void

5425   init_class_processing (void)                                                                      in class.c

5426   {

5427     current_class_depth = 0;

5428     current_class_stack_size = 10;

5429     current_class_stack

5430       = xmalloc (current_class_stack_size * sizeof (struct class_stack_node));

5431     VARRAY_TREE_INIT (local_classes , 8, "local_classes");

5432  

5433     ridpointers [(int) RID_PUBLIC] = access_public_node;

5434     ridpointers [(int) RID_PRIVATE] = access_private_node;

5435     ridpointers [(int) RID_PROTECTED] = access_protected_node;

5436   }

 

而下面所初始化的 search_obstack 在当前版本中已没有用处,在 V4 版本中已被去除。

 

2346   void

2347   init_search_processing (void)                                                                   in search.c

2348   {

2349     gcc_obstack_init (&search_obstack );

2350   }

4.3.1.7.8.2.      运行时类型识别 RTTI

4.3.1.7.8.2.1.              构建 TYPE_DECL 节点

运行时类型识别( runtime type identification RTTI )允许操纵基类的指针或引用对象,来获取该指针或引用对象的实际派生类型。为了支持 RTTI GCC 提供了 2 个操作符: typeid dynamic_cast typeid 的返回类型是 type_info ,而 type_info 的定义是依赖于实现的。在这里对 RTTI 的初始化中,不像 std::bad_alloc ,必须创建完整的定义,因为这个类是运行时环境所需要使用的。

 

115     void

116     init_rtti_processing (void)                                                                               in rtti.c

117     {

118       tree const_type_info_type;

119    

120      push_namespace (std_identifier);

121      type_info_type_node

122        = xref_tag (class_type, get_identifier ("type_info"),

123                  true, false);

124      pop_namespace ();

125      const_type_info_type = build_qualified_type (type_info_type_node,

126                                            TYPE_QUAL_CONST);

127      type_info_ptr_type = build_pointer_type (const_type_info_type);

128      type_info_ref_type = build_reference_type (const_type_info_type);

129   

130      VARRAY_TREE_INIT (unemitted_tinfo_decls , 10, "RTTI decls");

131   

132      create_tinfo_types ();

133    }

 

这儿 xref_tag 尝试获取具有 name 名字的 struct enum union tag_code 告知是哪个)。如果该类型还没定义,把标签( tag )定义为前向引用。

如果参数 globalize false ,表示标识符 name 是一个定义。在 C++ 中,首先,它允许在不同绑定域(即作用域)中定义同名的类型;其次,在同一绑定域中,同名的不同类型是一个语法错误,除非它们的定义是相同的。在 9476 行, lookup_tag 尝试,在由 b 提交的绑定域中,找出由 code name 指定的类型定义。我们在后面来看这个函数的定义。

而如果 globalize true ,则 name 只是一个类型声明。在 C++ 中,我们可以仅声明一个用户定义类型,然后使用其指针(只要不解引用)。例如,

class A;

A* pa = NULL;

GCC 内部,当它发现找不到任何东西时,它将创建一个伪类型(记得 std::bad_alloc ?),然后为它声明一个隐式的 typedef ,并且将由这个隐式 typedef 所构建的 TYPE_DECL 节点加入指定的绑定域。那么前向声明实际上就是引用这个 TYPE_DECL ,随后当遇到真正的定义时,对应的类型节点(类型 RECORD_TYPE ,或 UNION_TYPE ,或 ENUMERAL_TYPE )进行相应地更新。而当 GCC 找到存在的类型声明(不是伪类型),而且该声明与泛型编程相关,则需要特殊的处理,我们不久将看到这一点。

 

9443   tree

9444   xref_tag (enum tag_types tag_code, tree name,                                                         in decl.c

9445          bool globalize, bool template_header_p)

9446   {

9447     enum tree_code code;

9448     tree t;

9449     struct cp_binding_level *b = current_binding_level;

9450     tree context = NULL_TREE;

9451  

9452     timevar_push (TV_NAME_LOOKUP);

9453  

9454     my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0);

9455  

9456     switch (tag_code)

9457     {

9458       case record_type:

9459       case class_type:

9460         code = RECORD_TYPE;

9461         break ;

9462       case union_type:

9463         code = UNION_TYPE;

9464         break ;

9465       case enum_type:

9466         code = ENUMERAL_TYPE;

9467          break ;

9468       default :

9469         abort ();

9470     }

9471  

9472     if (! globalize)

9473     {

9474       /* If we know we are defining this tag, only look it up in

9475         this scope and don't try to find it as a type.  */

9476       t = lookup_tag (code, name, b, 1);

9477     }

9478     else

9479     {

9480       tree decl = lookup_name (name, 2);

      

这里 globalize true ,使用 lookup_name 来类型声明,因为其第二个参数表示抛弃非类型声明。 lookup_name 是一个复杂的函数,为了不使这里的过程太漫长,我们暂时跳过它。对于我们这里的情形, lookup_name 应该返回 NULL ,因为这必须是第一次声明这个类型。

 

xref_tag (continue)

 

9558     if (! t)

9559     {

9560       /* If no such tag is yet defined, create a forward-reference node

9561         and record it as the "definition".

9562         When a real declaration of this type is found,

9563         the forward-reference will be altered into a real type.  */

9564       if (code == ENUMERAL_TYPE)

9565       {

9566          error ("use of enum `%#D' without previous declaration", name);

9567          POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);

9568       }

9569       else

9570       {

9571          t = make_aggr_type (code);

9572          TYPE_CONTEXT (t) = context;

9573          pushtag (name, t, globalize);

9574       }

9575     }

9576     else

9577     {

          ...

9587     }

9588  

9589     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);

9590   }

 

因为在 9480 行,没有标签( tag )被 lookup_name 所找出,那么将为之创建一个节点。并且由于参数 tag_code class_type ,这个节点应该是 RECORD_TYPE ,而且它的上下文首先被设置为空(参见 9450 行的 NULL_TREE )。

 

4589   void

4590   pushtag (tree name, tree type, int globalize)                                        in name-lookup.c

4591   {

4592     struct cp_binding_level *b;

4593  

4594     timevar_push (TV_NAME_LOOKUP);

4595     b = current_binding_level ;

4596     while (/* Cleanup scopes are not scopes from the point of view of

4597             the language.  */

4598        b->kind == sk_cleanup

4599        /* Neither are the scopes used to hold template parameters

4600         for an explicit specialization. For an ordinary template

4601         declaration, these scopes are not scopes from the point of

4602         view of the language -- but we need a place to stash

4603         things that will go in the containing namespace when the

4604         template is instantiated.  */

4605        || (b->kind == sk_template_parms && b->explicit_spec_p)

4606        || (b->kind == sk_class

4607          && (globalize

4608            /* We may be defining a new type in the initializer

4609             of a static member variable. We allow this when

4610             not pedantic, and it is particularly useful for

4611             type punning via an anonymous union.  */

4612            || COMPLETE_TYPE_P (b->this_entity))))

4613        b = b->level_chain;

4614  

4615     if (b->type_decls == NULL)

4616       b->type_decls = binding_table_new (SCOPE_DEFAULT_HT_SIZE);

4617     binding_table_insert (b->type_decls, name, type);

 

pushtag 首先把类型定义加入当前名字空间。我们已经看到,在一个绑定域中的用户定义类型,被保存在相应的 cp_binding_level 结构的 type_decls 域中。下面的 binding_table_insert 提供了这个处理。

 

190    static void

191    binding_table_insert (binding_table table, tree name, tree type)             in name-lookup.c

192    {

193      const unsigned int hash = IDENTIFIER_HASH_VALUE (name);

194      const size_t i = ENTRY_INDEX (hash, table->chain_count);

195      binding_entry entry = binding_entry_make (name, type);

196   

197      entry->chain = table->chain[i];

198      table->chain[i] = entry;

199      ++table->entry_count;

200   

201      if (3 * table->chain_count < 5 * table->entry_count)

202        binding_table_expand (table);

203    }

 

注意到 type_decls 实际上是一个哈希表,所有具有同一哈希值的类型定义被链接在一起。为了控制链表的长度,如果链表的数目(域 chain_count )与表项数( entry_count )具有如下关系时: 3*table->chain_count < 5*table->entry_count binding_table_expand 将链表数目加倍,并重新哈希及链接已记录的类型。

 

67      static inline binding_entry

68      binding_entry_make (tree name, tree type)                                                 in name-lookup.c

69      {

70        binding_entry entry;

71     

72        if (free_binding_entry )

73        {

74          entry = free_binding_entry ;

75          free_binding_entry = entry->chain;

76        }

77        else

78          entry = ggc_alloc (sizeof (struct binding_entry_s));

79     

80        entry->name = name;

81        entry->type = type;

82        entry->chain = NULL;

83     

84        return entry;

85      }

 

在上面是 binding_entry_make 中,虽然标识符与类型定义通过 binding_entry 实例关联起来了,但标识符节点还没有与 TYPE_DECL 节点绑定。因此在下面, IDENTIFIER_TYPE_VALUE 返回 NULL

 

1700   tree

1701   identifier_type_value (tree id)                                                           in name-lookup.c

1702   {

1703     timevar_push (TV_NAME_LOOKUP);

1704     /* There is no type with that name, anywhere.  */

1705     if (REAL_IDENTIFIER_TYPE_VALUE (id) == NULL_TREE)

1706       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);

1707     /* This is not the type marker, but the real thing.  */

1708     if (REAL_IDENTIFIER_TYPE_VALUE (id) != global_type_node )

1709       POP_TIMEVAR_AND_RETURN(TV_NAME_LOOKUP, REAL_IDENTIFIER_TYPE_VALUE (id));

1710     /* Have to search for it. It must be on the global level, now.

1711       Ask lookup_name not to return non-types.  */

1712     id = lookup_name_real (id, 2, 1, 0, LOOKUP_COMPLAIN);

1713     if (id)

1714       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, TREE_TYPE (id));

1715     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);

1716   }

 

IDENTIFIER_TYPE_VALUE 只是 identifier_type_value 的一个直接的封装。在这里,在我们的情形下, REAL_IDENTIFIER_TYPE_VALUE 应该返回 NULL_TREE ,而下面 4622 行的 type 则是刚创建的 RECORD_TYPE 节点。

 

pushtag (continue)

 

4619     if (name)

4620     {

4621       /* Do C++ gratuitous typedefing.  */

4622       if (IDENTIFIER_TYPE_VALUE (name) != type)

4623       {

4624         tree d = NULL_TREE;

4625          int in_class = 0;

4626          tree context = TYPE_CONTEXT (type);

4627  

4628          if (! context)

4629          {

4630            tree cs = current_scope ();

4631  

4632             if (! globalize)

4633             context = cs;

4634            else if (cs != NULL_TREE && TYPE_P (cs))

4635             /* When declaring a friend class of a local class, we want

4636               to inject the newly named class into the scope

4637               containing the local class, not the namespace scope.  */

4638             context = decl_function_context (get_type_decl (cs));

4639          }

4640          if (!context)

4641            context = current_namespace ;

4642  

4643          if (b->kind == sk_class

4644             || (b->kind == sk_template_parms

4645               && b->level_chain->kind == sk_class))

4646            in_class = 1;

4647  

4648          if (current_lang_name == lang_name_java)

4649            TYPE_FOR_JAVA (type) = 1;

4650  

4651          d = create_implicit_typedef (name, type);

4652          DECL_CONTEXT (d) = FROB_CONTEXT (context);

4653          if (! in_class)

4654            set_identifier_type_value_with_scope (name, d, b);

 

回忆这个类型的上下文是 NULL ,因而在 4630 行, current_scope 被调用。这是一个宏,视情况在 current_function_decl current_class_type 中选择,对于名字空间作用域,它永远返回 NULL 。那么因为我们在 std 名字空间中,在 4641 行,类型上下文被设为当前名字空间作用域。

接着在 4651 行,由 create_implicit_typedef 为类型构建了一个 TYPE_DECL 节点。然后在 set_identifier_type_value_with_scope 里,这个 TYPE_DECL 节点(注意不是类型定义)将被记录入标识符节点的 namespace_bindings 域中。

 

1731   static void

1732   set_identifier_type_value_with_scope (tree id, tree decl, cxx_scope *b)        in name-lookup.c

1733   {

1734     tree type;

1735  

1736     if (b->kind != sk_namespace)

1737     {

1738       /* Shadow the marker, not the real thing, so that the marker

1739          gets restored later.  */

1740       tree old_type_value = REAL_IDENTIFIER_TYPE_VALUE (id);

1741       b->type_shadowed

1742           = tree_cons (id, old_type_value, b->type_shadowed);

1743       type = decl ? TREE_TYPE (decl) : NULL_TREE;

1744     }

1745     else

1746     {

1747       cxx_binding *binding =

1748           binding_for_name (NAMESPACE_LEVEL (current_namespace), id);

1749       if (decl)

1750        {

1751           if (binding->value)

1752           supplement_binding (binding, decl);

1753         else

1754             binding->value = decl;

1755        }

1756       else

1757          abort ();

1758       /* Store marker instead of real type.  */

1759       type = global_type_node ;

1760     }

1761     SET_IDENTIFIER_TYPE_VALUE (id, type);

1762   }

 

在上面 1754 行的赋值操作设置了该标识符目前对应的声明(这是个类型声明)。自此,在当前作用域,该标识符就表示该类型。

 

pushtag (continue)

 

4656          d = maybe_process_template_type_declaration (type,

4657                                                 globalize, b);

4658  

4659          if (b->kind == sk_class)

4660          {

4661            if (!PROCESSING_REAL_TEMPLATE_DECL_P ())

4662             /* Put this TYPE_DECL on the TYPE_FIELDS list for the

4663               class. But if it's a member template class, we

4664               want the TEMPLATE_DECL, not the TYPE_DECL, so this

4665               is done later.  */

4666             finish_member_declaration (d);

4667            else

4668             pushdecl_class_level (d);

4669          }

4670         else

4671            d = pushdecl_with_scope (d, b);

4672  

4673          /* FIXME what if it gets a name from typedef?  */

4674          if (ANON_AGGRNAME_P (name))

4675            DECL_IGNORED_P (d) = 1;

4676  

4677          TYPE_CONTEXT (type) = DECL_CONTEXT (d);

4678  

4679          /* If this is a local class, keep track of it. We need this

4680           information for name-mangling, and so that it is possible to find

4681           all function definitions in a translation unit in a convenient

4682           way. (It's otherwise tricky to find a member function definition

4683           it's only pointed to from within a local class.)  */

4684          if (TYPE_CONTEXT (type)

4685             && TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL

4686             && !processing_template_decl)

4687            VARRAY_PUSH_TREE (local_classes , type);

4688       }

4689       if (b->kind == sk_class

4690            && !COMPLETE_TYPE_P (current_class_type ))

4691       {

4692          maybe_add_class_template_decl_list (current_class_type ,

4693                                         type, /*friend_p=*/ 0);

4694          CLASSTYPE_NESTED_UTDS (current_class_type ) = b->type_decls;

4695       }

4696     }

4697  

4698     if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)

4699       /* Use the canonical TYPE_DECL for this node.  */

4700       TYPE_STUB_DECL (type) = TYPE_NAME (type);

4701     else

4702     {

4703       /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE

4704         will be the tagged type we just added to the current

4705         binding level. This fake NULL-named TYPE_DECL node helps

4706         dwarfout.c to know when it needs to output a

4707         representation of a tagged type, and it also gives us a

4708         convenient place to record the "scope start" address for

4709         the tagged type.  */

4710  

4711       tree d = build_decl (TYPE_DECL, NULL_TREE, type);

4712       TYPE_STUB_DECL (type) = pushdecl_with_scope (d, b);

4713     }

4714     timevar_pop (TV_NAME_LOOKUP);

4715   }

 

现在我们已经把类型定义( RECORD_TYPE 节点)加入到了绑定域中,还把对应的 TYPE_DECL 节点加入到标识符节点的绑定链里。下面的 1960 行, pushdecl 只是调用 add_decl_to_level TYPE_DECL 节点加入对应 cxx_scope names 域。

 

1941   tree

1942   pushdecl_with_scope (tree x, cxx_scope *level)                                   in name-lookup.c

1943   {

1944     struct cp_binding_level *b;

1945     tree function_decl = current_function_decl ;

1946  

1947     timevar_push (TV_NAME_LOOKUP);

1948     current_function_decl = NULL_TREE;

1949     if (level->kind == sk_class)

1950     {

1951       b = class_binding_level;

1952       class_binding_level = level;

1953       pushdecl_class_level (x);

1954       class_binding_level = b;

1955     }

1956     else

1957     {

1958       b = current_binding_level ;

1959       current_binding_level = level;

1960       x = pushdecl (x);

1961       current_binding_level = b;

1962     }

1963     current_function_decl = function_decl;

1964     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);

1965   }

 

type_info 实际上是一个类型系列,编译器根据类的结构选择其一,结构相同的类所选用的 type_info 是一样的,但是不同的实例。因此,编译器在遇到使用 type_info 的地方,并不急着构建实例,而是在前端最后完成这个编译单元时,集中地构建。这些 type_info 所需要的缓存就是在 init_rtti_processing 130 行的 unemitted_tinfo_decls

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值