一个类类型由一个RECORD_TYPE节点或者UNION_TYPE节点来表示。声明为union 的类由UNION_TYPE来表示,而声明为struct或者class的类由RECORD_TYPE来表示。你可以使用宏CLASSTYPE_DECLARED_CLASS来辨别特定的类是class还是struct。如果类被声明为class,这个宏返回true。
几乎所有的非函数成员都出现在节点的TYPE_FIELDS链中。给定一个成员,下一个成员可以通过TREE_CHAIN找到。你不能以任何方式来依赖成员出现在链中的次序。这个链中的所有节点必须为DECL系列节点。其中,FIELD_DECL节点用于表示非静态数据成员, VAR_DECL节点用于表示静态数据成员,而TYPE_DECL节点用于表示类型声明。注意,如果在类中声明了枚举类型,用于枚举常量的CONST_DECL也会出现在链中(当然,枚举类型的TYPE_DECL也会出现)。但在这个链中不会出现代表基类的节点。特别的没有代表基类部分的FIELD_DECL(注:在后面的layout_class_type函数中,实际上代表基类部分的FIELD_DECL会由编译器加到TYPE_FIELDS的头部,不过这在最后完成类节点构造的步骤中)。
TYPE_VFIELD是由编译器生成的域,用于指向虚函数表。它可能会出现在TYPE_FIELDS链(注:取决于类是否需要虚函数表)。不过,在后端看来TYPE_VFIELD和其他TYPE_FIELDS上的节点并无不同。
函数成员则出现在TYPE_METHODS链。同样,后续的函数成员可以通过TREE_CHAIN 访问。如果函数被重载,每个被重载的函数都会出现,但OVERLOAD节点(注:代表重载函数)不出现在TYPE_METHODS链上(注:出现在链的分支)。隐含声明的函数(包括缺省构造函数,拷贝构造函数,赋值操作符,及析构函数)也都会出现在链上。
每个类都一个伴随的binfo,它可以通过TYPE_BINFO访问。Binfo用于代表基类。TYPE_BINFO给出的binfo是退化的,因为每个类都被视为自己的基类。给定一个binfo,其基类可以通过BINFO_BASETYPES来获得。这些基类本身也是binfo。一个binfo对应的类类型则由BINFO_TYPE给出。BINFO_TYPE (TYPE_BINFO (x))总是得到x的类型(除去最上层的类型修饰)。但是TYPE_BINFO (BINFO_TYPE (y))不总是返回与y相同的binfo。原因是,如果y是一个代表派生类D中的基类B的binfo,那么BINFO_TYPE (y)将是B,而TYPE_BINFO (BINFO_TYPE (y))将是B作为自身基类的binfo,而不是作为D的基类的binfo(注:在后面,我们可以看到,D的基类B的binfo与B作为自身基类的binfo是不同的对象。Binfo可以看作base information的缩写)。
BINFO_BASETYPES是一个TREE_VEC。基类以由左到右的顺序出现。通过宏TREE_VIA_PUBLIC,TREE_VIA_PROTECTED和TREE_VIA_PRIVATE可以知道派生是否为public,protected或者private。每个宏都需要一个binfo节点,仅当指定的派生方式被应用了,才返回true。如果一个binfo的TREE_VIA_VIRTUAL返回true,那么它的 BINFO_TYPE(注:对应的类类型)是一个虚派生。
以下的宏被用于表示类类型节点。
LOCAL_CLASS_P:如果类是局部类,即定义于函数体内,返回true(注:这是GNU C++的扩展)。
TYPE_POLYMORPHIC_P:如果类包含至少一个虚函数(通过声明或继承),返回true。
TYPE_HAS_DEFAULT_CONSTRUCTOR:如果类具有缺省构造函数,返回true。
CLASSTYPE_HAS_MUTABLE,TYPE_HAS_MUTABLE_P:如果类含有mutable的数据对象,2者返回true。
CLASSTYPE_NON_POD_P:如果类不是POD(plain of data),返回true。
TYPE_HAS_NEW_OPERATOR:如果类定义了new操作符,返回true。
TYPE_HAS_ARRAY_NEW_OPERATOR:如果类定义了new[]操作符,返回true。
TYPE_OVERLOADS_CALL_EXPR:如果类重载了()操作符,返回true。
TYPE_OVERLOADS_ARRAY_REF:如果类重载了[]操作符,返回true。
TYPE_OVERLOADS_ARROW:如果类重载了->操作符,返回true。
聚集类型包括以下:
RECORD_TYPE [2]
² 用于表示struct和class类型,以及成员函数指针,还有其他语言中类似的构造。TYPE_FIELDS包含这个类所含有的项(item),它们可以是FIELD_DECL,VAR_DECL,CONST_DECL或者TYPE_DECL。不可以假定类中域在节点中的次序,也不可假定它们中有重叠(overlap)。
如果TYPE_PTRMEMFUNC_P成立,那么这个类型是一个指向成员的指针类型。在这种情况下,TYPE_PTRMEMFUNC_FN_TYPE是一个指向一个METHOD_TYPE 的POINTER_TYPE。METHOD_TYPE是被这个指向成员函数指针指向的函数类型。如果TYPE_PTRMEMFUNC_P不成立,这个类是类类型。
UNION_TYPE [2]
² 用于表示union类型。类似于RECORD_TYPE,除了在TYPE_FIELD中所有的FIELD_DECL节点都位于起始位置0(注:见后面的类布局)。
QUAL_UNION_TYPE [2]
² 用于表示Ada中的可变基类(variant record)。类似于UNION_TYPE除了每个FIELD_DECL拥有DECL_QUALIFIER域,其中包含一个指示域是否出现在对象中的布尔表达式。这个类型只能有一个有效域,因此只有当,在TYPE_FIELDS中,之前的域都不出现时,域的DECL_QUALIFIER才被求值。通常这些表达式通过PLACEHOLDER_EXPR来引用外部对象(outer object)的一个域。
layout_type (continue)
1725 case RECORD_TYPE:
1726 case UNION_TYPE:
1727 case QUAL_UNION_TYPE:
1728 {
1729 tree field;
1730 record_layout_info rli;
1731
1732 /* Initialize the layout information. */
1733 rli = start_record_layout (type);
1734
1735 /* If this is a QUAL_UNION_TYPE, we want to process the fields
1736 in the reverse order in building the COND_EXPR that denotes
1737 its size. We reverse them again later. */
1738 if (TREE_CODE (type) == QUAL_UNION_TYPE)
1739 TYPE_FIELDS (type) = nreverse (TYPE_FIELDS (type));
1740
1741 /* Place all the fields. */
1742 for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
1743 place_field (rli, field);
1744
1745 if (TREE_CODE (type) == QUAL_UNION_TYPE)
1746 TYPE_FIELDS (type) = nreverse (TYPE_FIELDS (type));
1747
1748 if (lang_adjust_rli)
1749 (*lang_adjust_rli) (rli);
1750
1751 /* Finish laying out the record. */
1752 finish_record_layout (rli, /*free_p=*/true);
1753 }
1754 break;
以上就是前端中用于布局聚集类型的代码片段。需要指出,这只是前端用来对自己人工(artificial)构造的聚集对象布局的方法。使用者定义的聚集类需要复杂得多的方法(见后面的layout_class_type)。
2.2.3.1.5.2.1. 保存信息的结构体
构建RECORD_TYPE/UNION_TYPE/QUAL_UNION_TYPE节点的信息,需要保存在结构体中。下面是它的定义。
2332 typedef struct record_layout_info_s in tree.h
2333 {
2334 /* The RECORD_TYPE that we are laying out. */
2335 tree t;
2336 /* The offset into the record so far, in bytes, not including bits in
2337 BITPOS. */
2338 tree offset;
2339 /* The last known alignment of SIZE. */
2340 unsigned int offset_align;
2341 /* The bit position within the last OFFSET_ALIGN bits, in bits. */
2342 tree bitpos;
2343 /* The alignment of the record so far, in bits. */
2344 unsigned int record_align;
2345 /* The alignment of the record so far, ignoring #pragma pack and
2346 __attribute__ ((packed)), in bits. */
2347 unsigned int unpacked_align;
2348 /* The previous field layed out. */
2349 tree prev_field;
2350 /* The static variables (i.e., class variables, as opposed to
2351 instance variables) encountered in T. */
2352 tree pending_statics;
2353 /* Bits remaining in the current alignment group */
2354 int remaining_in_alignment;
2355 /* True if we've seen a packed field that didn't have normal
2356 alignment anyway. */
2357 int packed_maybe_necessary;
2358 } *record_layout_info;
函数start_record_layout创建和初始化了record_layout_info。如果目标平台对这些类型有特殊的对齐要求,在下面564行的STRUCTURE_SIZE_BOUNDARY就会被定义。对于x86/Linux平台,这个宏没有定义。
550 record_layout_info
551 start_record_layout (tree t) in stor-layout.c
552 {
553 record_layout_info rli = xmalloc (sizeof (struct record_layout_info_s));
554
555 rli->t = t;
556
557 /* If the type has a minimum specified alignment (via an attribute
558 declaration, for example) use it -- otherwise, start with a
559 one-byte alignment. */
560 rli->record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (t));
561 rli->unpacked_align = rli->record_align;
562 rli->offset_align = MAX (rli->record_align, BIGGEST_ALIGNMENT);
563
564 #ifdef STRUCTURE_SIZE_BOUNDARY
565 /* Packed structures don't need to have minimum size. */
566 if (!TYPE_PACKED (t))
567 rli->record_align = MAX (rli->record_align, (unsigned) STRUCTURE_SIZE_BOUNDARY);
568 #endif
569
570 rli->offset = size_zero_node;
571 rli->bitpos = bitsize_zero_node;
572 rli->prev_field = 0;
573 rli->pending_statics = 0;
574 rli->packed_maybe_necessary = 0;
575
576 return rli;
577 }
另外注意,在562行,在具有非常量大小的布局中,offset_align记录着已布局部分的对齐量。在布局的开始,offset_align具有最大的对齐量。
2.2.3.1.5.2.2. 收集域的信息
2.2.3.1.5.2.2.1. tree_decl节点
在上面layout_type的1742 行,TYPE_FIELDS是一条由FIELD_DECL节点组成的链。FIELD_DECL节点的类型是下面的tree_decl。
1647 struct tree_decl GTY(()) in tree.h
1648 {
1649 struct tree_common common;
1650 location_t locus;
1651 unsigned int uid;
1652 tree size;
1653 ENUM_BITFIELD(machine_mode) mode : 8;
1654
1655 unsigned external_flag : 1;
1656 unsigned nonlocal_flag : 1;
1657 unsigned regdecl_flag : 1;
1658 unsigned inline_flag : 1;
1659 unsigned bit_field_flag : 1;
1660 unsigned virtual_flag : 1;
1661 unsigned ignored_flag : 1;
1662 unsigned abstract_flag : 1;
1663
1664 unsigned in_system_header_flag : 1;
1665 unsigned common_flag : 1;
1666 unsigned defer_output : 1;
1667 unsigned transparent_union : 1;
1668 unsigned static_ctor_flag : 1;
1669 unsigned static_dtor_flag : 1;
1670 unsigned artificial_flag : 1;
1671 unsigned weak_flag : 1;
1672
1673 unsigned non_addr_const_p : 1;
1674 unsigned no_instrument_function_entry_exit : 1;
1675 unsigned comdat_flag : 1;
1676 unsigned malloc_flag : 1;
1677 unsigned no_limit_stack : 1;
1678 ENUM_BITFIELD (built_in_class) built_in_class : 2;
1679 unsigned pure_flag : 1;
1680
1681 unsigned non_addressable : 1;
1682 unsigned user_align : 1;
1683 unsigned uninlinable : 1;
1684 unsigned thread_local_flag : 1;
1685 unsigned declared_inline_flag : 1;
1686 ENUM_BITFIELD (symbol_visibility) visibility : 2;
1687 unsigned unused : 1;
1688 /* one unused bit. */
1689
1690 unsigned lang_flag_0 : 1;
1691 unsigned lang_flag_1 : 1;
1692 unsigned lang_flag_2 : 1;
1693 unsigned lang_flag_3 : 1;
1694 unsigned lang_flag_4 : 1;
1695 unsigned lang_flag_5 : 1;
1696 unsigned lang_flag_6 : 1;
1697 unsigned lang_flag_7 : 1;
1698
1699 union tree_decl_u1 {
1700 /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
1701 DECL_FUNCTION_CODE. */
1702 enum built_in_function f;
1703 /* In a FUNCTION_DECL for which DECL_BUILT_IN does not hold, this
1704 is used by language-dependent code. */
1705 HOST_WIDE_INT i;
1706 /* DECL_ALIGN and DECL_OFFSET_ALIGN. (These are not used for
1707 FUNCTION_DECLs). */
1708 struct tree_decl_u1_a {
1709 unsigned int align : 24;
1710 unsigned int off_align : 8;
1711 } a;
1712 } GTY ((skip (""))) u1;
1713
1714 tree size_unit;
1715 tree name;
1716 tree context;
1717 tree arguments; /* Also used for DECL_FIELD_OFFSET */
1718 tree result; /* Also used for DECL_BIT_FIELD_TYPE */
1719 tree initial; /* Also used for DECL_QUALIFIER */
1720 tree abstract_origin;
1721 tree assembler_name;
1722 tree section_name;
1723 tree attributes;
1724 rtx rtl; /* RTL representation for object. */
1725
1726 /* In FUNCTION_DECL, if it is inline, holds the saved insn chain.
1727 In FIELD_DECL, is DECL_FIELD_BIT_OFFSET.
1728 In PARM_DECL, holds an RTL for the stack slot
1729 of register where the data was actually passed.
1730 Used by Chill and Java in LABEL_DECL and by C++ and Java in VAR_DECL. */
1731 union tree_decl_u2 {
1732 struct function * GTY ((tag ("FUNCTION_DECL"))) f;
1733 rtx GTY ((tag ("PARM_DECL"))) r;
1734 tree GTY ((tag ("FIELD_DECL"))) t;
1735 int GTY ((tag ("VAR_DECL"))) i;
1736 } GTY ((desc ("TREE_CODE((tree) &(%0))"))) u2;
1737
1738 /* In a FUNCTION_DECL, this is DECL_SAVED_TREE. */
1739 tree saved_tree;
1740
1741 /* In a FUNCTION_DECL, these are function data which is to be kept
1742 as long as FUNCTION_DECL is kept. */
1743 tree inlined_fns;
1744
1745 tree vindex;
1746 HOST_WIDE_INT pointer_alias_set;
1747 /* Points to a structure whose details depend on the language in use. */
1748 struct lang_decl *lang_specific;
1749 };
在同一个文件,定义了一系列以DECL开头的宏用于访问tree_decl的域(红色部分为定义)[2]。
DECL_SECTION_NAME (DECL_CHECK (NODE)->decl.section_name):记录在一个段(section)属性中指定的名字(GNU C++允许在变量声明中使用段属性,来指定目标文件中变量存放的段)。用于从decl_attributes把这个名字传递到make_function_rtl和make_decl_rtl。 DECL_CONTEXT (DECL_CHECK (NODE)->decl.context) |
DECL_CONTEXT (DECL_CHECK (NODE)->decl.context) DECL_FIELD_CONTEXT (FIELD_DECL_CHECK (NODE)->decl.context):对于FIELD_DECL,是这个域所属类的RECORD_TYPE,UNION_TYPE或QUAL_UNION_TYPE节点。对于VAR_DECL,PARM_DECL,FUNCTION_DECL,LABEL_DECL和CONST_DECL节点,它指向包含函数的FUNCTION_DECL节点,或者指向包含类的RECORD_TYPE或UNION_TYPE节点,或者如果给定的声明是具有文件作用域的,指向NULL_TREE或一个TRANSLATION_UNIT_DECL节点。 |
DECL_ATTRIBUTES (DECL_CHECK (NODE)->decl.attributes):这是存放属性的地方。 |
DECL_FIELD_OFFSET (FIELD_DECL_CHECK (NODE)->decl.arguments):对于FIELD_DECL节点,这是域以字节为单位的偏移,它根据最靠近结构体头的字节来计算。 |
DECL_FIELD_BIT_OFFSET (FIELD_DECL_CHECK (NODE)->decl.u2.t):对于FIELD_DECL节点,这是域以比特为单位的偏移,它根据最靠近结构体头的比特位来计算。 |
DECL_BIT_FIELD_TYPE (FIELD_DECL_CHECK (NODE)->decl.result) :对于FIELD_DECL节点,如果域是位域(bit-field), 则是其对应的原始类型。节点的TREE_TYPE可能已被更改(通过函数finish_struct)。 |
DECL_ARGUMENTS (DECL_CHECK (NODE)->decl.arguments):在FUNCTION_DECL节点中,是一个DECL节点链。在VAR_DECL和PARM_DECL节点中,保留作语言相关的用途。 |
DECL_RESULT_FLD (DECL_CHECK (NODE)->decl.result):对于TEMPLATE_DECL节点,这是对应的TYPE_DECL。在语句(statement)中声明的变量的VAR_DECL节点中,这是被屏蔽的局部变量。 |
DECL_RESULT (FUNCTION_DECL_CHECK (NODE)->decl.result):在FUNCTION_DECL节点中,保存了返回值。 |
DECL_ORIGINAL_TYPE (TYPE_DECL_CHECK (NODE)->decl.result):对于TYPE_DECL节点,保存“原始”类型。(TREE_TYPE拥有拷贝) |
DECL_ARG_TYPE_AS_WRITTEN (PARM_DECL_CHECK (NODE)->decl.result):在PARM_DECL节点,保存声明时的类型(the type as written)(可能是函数或数组)。 |
DECL_INITIAL (DECL_CHECK (NODE)->decl.initial) :对于FUNCTION_DECL,保存BINDINGS树。对于TRANSLATION_UNIT_DECL,保存名字空间块。对于VAR_DECL,保存初始化值。 |
DECL_ARG_TYPE (PARM_DECL_CHECK (NODE)->decl.initial):对于PARM_DECL,记录传递实参的数据类型,它可能与程序中看到的类型不同。 |
DECL_QUALIFIER (FIELD_DECL_CHECK (NODE)->decl.initial):对于在QUAL_UNION_TYPE 中的FIELD_DECL,记录一个表达式,如果这个表达式不为0,表明该域在类型里有效。 |
DECL_SOURCE_LOCATION (DECL_CHECK (NODE)->decl.locus):这个域描述了这个声明在源代码中的位置。如果声明出现在多个地方(比如一个C函数先声明,然后再定义),这部分指向定义。 |
DECL_SIZE (DECL_CHECK (NODE)->decl.size):保存数据以比特衡量的大小。它是个树形式,不需要为常量。 |
DECL_SIZE_UNIT (DECL_CHECK (NODE)->decl.size_unit):以字节衡量的数据大小。 |
DECL_ALIGN (DECL_CHECK (NODE)->decl.u1.a.align):以比特衡量的对齐量。 |
DECL_ALIGN_UNIT (DECL_ALIGN (NODE) / BITS_PER_UNIT):以字节衡量的对齐量。 |
DECL_OFFSET_ALIGN (((unsigned HOST_WIDE_INT)1) << FIELD_DECL_CHECK (NODE)-> decl.u1.a.off_align):对于FIELD_DECL,off_align保存了DECL_FIELD_OFFSET中为0的低位比特的数目。因此DECL_OFFSET_ALIGN返回了DECL_FIELD_OFFSET所持有的对齐量。 |
SET_DECL_OFFSET_ALIGN (NODE, X) (FIELD_DECL_CHECK (NODE)->decl.u1.a.off_align = exact_log2 ((X) & -(X))) DECL_USER_ALIGN (DECL_CHECK (NODE)->decl.user_align):如果类型的对齐量由”aligned”的属性指定,其值为1。如果为这个类型的默认值,则为0。 |
DECL_MODE (DECL_CHECK (NODE)->decl.mode) :保存变量或者域声明的机器模式。它永远等于TYPE_MODE (TREE_TYPE (decl)),除FIELD_DECL外。 |
DECL_RTL (DECL_CHECK (NODE)->decl.rtl / ? (NODE)->decl.rtl : (make_decl_rtl (NODE, NULL), (NODE)->decl.rtl)):保存对应变量值或函数的RTL表达式。对于函数,拥有静态存储的变量和标签(label),这个值会被延后评估(evaluated lazily)。 |
DECL_RTL_SET_P (DECL_CHECK (NODE)->decl.rtl != NULL):如果NODE节点中DECL_RTL已设置,返回非零值。 |
COPY_DECL_RTL(DECL_CHECK (NODE2)->decl.rtl = DECL_CHECK (NODE1)->decl.rtl):从NODE1拷贝RTL到NODE2。如果NODE1的RTL未设定,NODE2也不会设定,这是一个迟缓拷贝(lazy copy)。 |
DECL_INCOMING_RTL (PARM_DECL_CHECK (NODE)->decl.u2.r):对于PARM_DECL,保存用于传递数据的栈位置(stack slot)或寄存器的对应的RTL。 |
DECL_SAVED_INSNS (FUNCTION_DECL_CHECK (NODE)->decl.u2.f) :对于 FUNCTION_DECL,如果它是内联的,保存函数体语句链。 |
DECL_FUNCTION_CODE (FUNCTION_DECL_CHECK (NODE)->decl.u1.f):对于 FUNCTION_DECL,如果它是内建函数(built-in),表明它为何种内建操作。 |
DECL_VINDEX (DECL_CHECK (NODE)->decl.vindex):对于FUNCTION_DECL,它有两种用途。在包含该函数的结构体被布局前,DECL_VINDEX可能指向基类中的FUNCTION_DECL,它是虚函数,被当前虚函数覆盖。当类布局完成后,这个指针将变为INTEGER_CST,它作为虚函数表的索引。 |
DECL_FCONTEXT (FIELD_DECL_CHECK (NODE)->decl.vindex):对于 FIELD_DECL,DECL_FCONTEXT是第一个定义这个域的基类。当为虚基类和虚函数准备调试信息时,这是必要的信息。 |
DECL_UID (DECL_CHECK (NODE)->decl.uid):对每个DECL节点,它是唯一的数字(a unique number)。 |
DECL_ABSTRACT_ORIGIN (DECL_CHECK (NODE)->decl.abstract_origin):对于各种DECL节点,它指向该节点作为一个(内联或者模板展开)实例的原始抽象声明节点(original (abstract) decl node),否则它是NULL。例如,对于内联函数的一个嵌套声明,它指向函数定义。 |
DECL_ORIGIN (DECL_ABSTRACT_ORIGIN(NODE) ? DECL_ABSTRACT_ORIGIN(NODE): (NODE)):类似DECL_ABSTRACT_ORIGIN,但如果没有抽象源头(no abstract origin),返回NODE。当设置DECL_ABSTRACT_ORIGIN时,它有用。 |
DECL_FROM_INLINE (DECL_ABSTRACT_ORIGIN (NODE) != NULL_TREE / && DECL_ABSTRACT_ORIGIN (NODE) != (NODE)):对于各种DECL节点,非零值表示该节点代表了一个内联函数的若干个抽象声明中的一个内联实例。并抑制变量屏蔽的警告。FUNCTION_DECL节点也会把自己设为自身的抽象源头(abstract origin)。 |
DECL_IGNORED_P (DECL_CHECK (NODE)->decl.ignored_flag):对于DECL节点,非零值表示该节点的名字,在符号调试的目的下,应该忽略。 |
DECL_ABSTRACT (DECL_CHECK (NODE)->decl.abstract_flag):对给定的DECL节点,非零值表示该节点代表给定声明的“抽象实例”(abstract instance)(例如一个内联函数的原始声明(original declaration))。当生成符号调试信息时,我们不要尝试为标记为“抽象实例”的节点产生地址信息,因为对这种实例为其分配空间的代码不会产生。 |
DECL_IN_SYSTEM_HEADER (DECL_CHECK (NODE)->decl.in_system_header_flag):非零值表示,如果该声明没有被使用,不要产生警告。 |
DECL_COMMON (DECL_CHECK (NODE)->decl.common_flag):对给定的DECL节点,非零值表示该节点应该被尽可能放入.common段。如果给定一个DECL_INITIAL,而且它不是error_mark_node,那么该节点不能放入.common段。 |
DECL_LANG_SPECIFIC (DECL_CHECK (NODE)->decl.lang_specific):语言特定的信息。 |
DECL_EXTERNAL (DECL_CHECK (NODE)->decl.external_flag):在VAR_DECL或FUNCTION_DECL节点中,非零值表示外部引用:不需要分配存储,其定义在其他地方。 |
TYPE_DECL_SUPPRESS_DEBUG (TYPE_DECL_CHECK (NODE)->decl.external_flag):在TYPE_DECL节点中,非零值表示该类型的详细信息不被转储到块(stab)中。相反它会产生名字的交叉引用(cross reference)。它和DECL_EXTERNAL一起使用。 |
DECL_REGISTER (DECL_CHECK (NODE)->decl.regdecl_flag):在VAR_DECL和PARM_DECL节点中,非零值表示声明为`register'。 |
DECL_PACKED (FIELD_DECL_CHECK (NODE)->decl.regdecl_flag):在FIELD_DECL节点,表示该域是紧凑的。 |
DECL_NO_STATIC_CHAIN (FUNCTION_DECL_CHECK (NODE)->decl.regdecl_flag):在含有非0的DECL_CONTEXT 的FUNCTION_DECL节点中,表示函数不需要静态链。 |
DECL_INLINE (FUNCTION_DECL_CHECK (NODE)->decl.inline_flag):在FUNCTION_DECL节点中,非零值表示在调用处,函数体被代入。 |
DECL_DECLARED_INLINE_P (FUNCTION_DECL_CHECK (NODE)->decl.declared_inline_flag):在FUNCTION_DECL节点中,非零值表示函数通过关键字inline被声明为内联。这个标记控制inline的链接语义;但函数是否内联通过DECL_INLINE来决定。 |
DECL_VISIBILITY (DECL_CHECK (NODE)->decl.visibility):是声明的可见属性。 |
DECL_UNINLINABLE (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable):在FUNCTION_DECL节点中,非零值表示函数不能被内联。 |
DECL_THREAD_LOCAL (VAR_DECL_CHECK (NODE)->decl.thread_local_flag):在VAR_DECL节点中,非零值表示该数据不能被分配在线程的局部储存。 |
DECL_SAVED_TREE (FUNCTION_DECL_CHECK (NODE)->decl.saved_tree):在FUNCTION_DECL节点中,保存了整个函数体。通常是一个COMPOUND_STMT,但在C++这也可能是一个RETURN_INIT,CTOR_INITIALIZER或TRY_BLOCK。 |
DECL_INLINED_FNS (FUNCTION_DECL_CHECK (NODE)->decl.inlined_fns):内联到该函数体的FUNCTION_DECL链。 |
DECL_IS_MALLOC (FUNCTION_DECL_CHECK (NODE)->decl.malloc_flag):在FUNCTION_DECL节点中,非零值表示该函数应该象malloc那样处理,这意味着它返回一个没有别名的指针(注,参见后面关于别名的章节,或者在wikipedia)。 |
DECL_IS_PURE (FUNCTION_DECL_CHECK (NODE)->decl.pure_flag):在FUNCTION_DECL节点2,非零值表示函数应被视为纯函数(象常量函数,但可能读全局内存)。 |
DECL_BIT_FIELD (FIELD_DECL_CHECK (NODE)->decl.bit_field_flag):在FIELD_DECL节点中,非零值表示它是一个位域,需要特殊的访问方式。 |
DECL_IN_TEXT_SECTION (VAR_DECL_CHECK (NODE)->decl.bit_field_flag):在静态的VAR_DECL节点中,非零值表示其空间分配在代码段。 |
DECL_BUILT_IN (DECL_BUILT_IN_CLASS (NODE) != NOT_BUILT_IN):在FUNCTION_DECL节点中,非零值表示它是一个内建函数。 |
DECL_BUILT_IN_CLASS (FUNCTION_DECL_CHECK (NODE)->decl.built_in_class):对于内建函数,这代表编译器的哪部分定义它。 |
DECL_VIRTUAL_P (DECL_CHECK (NODE)->decl.virtual_flag):用在VAR_DECL节点中,表示该变量为虚函数表。用在FIELD_DECL节点中,表示它为虚函数表指针。用在FUNCTION_DECL节点中表示该函数是虚函数。 |
DECL_DEFER_OUTPUT (DECL_CHECK (NODE)->decl.defer_output):用于表示这个DECL节点的链接状态尚不清楚,因此它现在不能被输出。 |
DECL_TRANSPARENT_UNION (PARM_DECL_CHECK (NODE)->decl.transparent_union):用在类型为union的PARM_DECL节点中,表示该参数可以用传递第一个union 成员的方式来传递。 |
DECL_STATIC_CONSTRUCTOR (FUNCTION_DECL_CHECK (NODE)->decl.static_ctor_flag): DECL_STATIC_DESTRUCTOR (FUNCTION_DECL_CHECK (NODE)->decl.static_dtor_flag):用在FUNCTION_DECL节点中,表示它们需要在程序执行前自动运行。 |
DECL_ARTIFICIAL (DECL_CHECK (NODE)->decl.artificial_flag):用于表示该DECL节点是编译器声明的。 |
DECL_WEAK (DECL_CHECK (NODE)->decl.weak_flag) :用于表示该DECL拥有弱链接性(weak linkage)。 |
DECL_ONE_ONLY (DECL_CHECK (NODE)->decl.transparent_union):用在标记为TREE_PUBLIC的声明节点中,表示该节点的在不同编译单元的拷贝需要被合并。 |
DECL_COMDAT (DECL_CHECK (NODE)->decl.comdat_flag):用在DECL节点中,表示就算该节点是TREE_PUBLIC的,它也不需要被输出,除非在这个编译单元被用到。这些实体被编译单元所共享(象弱实体,weak entity),而且保证它们被需要它们的编译单元输出,而不被其他编译单元输出。DECL_COMDAT只是对后端的暗示,由前端设定。前端必须保证,如果输出DECL_COMDAT实体,除了使代码膨胀外,没有别的坏处。 |
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (FUNCTION_DECL_CHECK (NODE)->decl.no_instrument_function_entry_exit) :用于FUNCTION_DECL节点中,表示该函数的进入退出需要加入调用支持例程的代码。 |
DECL_NO_LIMIT_STACK (FUNCTION_DECL_CHECK (NODE)->decl.no_limit_stack):用在FUNCTION_DECL节点中,表示该函数没有栈大小的限制。 |
DECL_NON_ADDR_CONST_P (DECL_CHECK (NODE)->decl.non_addr_const_p):用于表示该DECL的指针不能被作为地址常量。 |
DECL_NONADDRESSABLE_P (FIELD_DECL_CHECK (NODE)->decl.non_addressable):用在FIELD_DECL节点中,表示我们不能构建该部分的地址。 |
DECL_POINTER_ALIAS_SET (DECL_CHECK (NODE)->decl.pointer_alias_set):用于表示有指针或者引用类型的FIELD_DECL,PARM_DECL或VAR_DECL所指向的内存的别名集。 |
DECL_POINTER_ALIAS_SET_KNOWN_P (DECL_POINTER_ALIAS_SET (NODE) != - 1):非零值,如果该声明已设置了别名集。 |
DECL_FILE_SCOPE_P (! DECL_CONTEXT (EXP) / || TREE_CODE (DECL_CONTEXT (EXP)) == TRANSLATION_UNIT_DECL):如果声明具有文件作用域,为非零值。 |
列表3: 用于TREE_DECL的宏
2.2.3.1.5.2.2.2. 域的布局
在layout_type的742行,在同一绑定上下文中的声明都通过TREE_CHAIN 域来连接。因此函数place_field的参数field 依次指向这些声明。
821 void
822 place_field (record_layout_info rli, tree field) in stor-layout.c
823 {
824 /* The alignment required for FIELD. */
825 unsigned int desired_align;
826 /* The alignment FIELD would have if we just dropped it into the
827 record as it presently stands. */
828 unsigned int known_align;
829 unsigned int actual_align;
830 /* The type of this field. */
831 tree type = TREE_TYPE (field);
832
833 if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
834 return;
835
836 /* If FIELD is static, then treat it like a separate variable, not
837 really like a structure field. If it is a FUNCTION_DECL, it's a
838 method. In both cases, all we do is lay out the decl, and we do
839 it *after* the record is laid out. */
840 if (TREE_CODE (field) == VAR_DECL)
841 {
842 rli->pending_statics = tree_cons (NULL_TREE, field,
843 rli->pending_statics);
844 return;
845 }
2.2.3.1.5.2.2.3. VAR_DECL类型
我们已经看到VAR_DECL可以代表类的静态数据成员,它详细的描述如下:
VAR_DECL[2]
² 这些节点表示在名字空间或块(block)范围内的变量,以及类的静态数据成员。其中 DECL_SIZE和DECL_ALIGN类似于TYPE_SIZE和TYPE_ALIGN。对于一个声明,应该使用DECL_SIZE和DECL_ALIGN,而不是由TREE_TYPE中得到的TYPE_SIZE和TYPE_ALIGN,因为该变量可能应用了特定的属性,从而具有特定的尺寸和对齐量。可以使用判定DECL_THIS_STATIC或DECL_THIS_EXTERN来检查,变量声明是否应用了存储类别符(storage class specifiers)static或extern。
如果这个变量是需要初始化的(但不需要构造函数),DECL_INITIAL将是初始化值的表达式。这个初始化值会被求值并按位拷贝入变量。如果DECL_INITIAL是error_mark_node,表明有初始化值,但它由后续代码中的显式语句(即非编译器添加)给出,不需要按位拷贝。
GCC提供一个扩展,允许自动变量或全局变量被放入特定的寄存器。如果对该VAR_DECL,DECL_REGISTER成立而且DECL_ASSEMBLER_NAME不等于 DECL_NAME,表明该扩展被用于这个VAR_DECL。在这种情况下, DECL_ASSEMBLER_NAME是变量将被放入的寄存器名。
在842行,函数tree_cons创建一个tree_list节点,并将这个VAR_DECL对象链入rli的pending_statics域。这些链入pending_statics的对象会在类布局的最后阶段才被处理,其原因是这些对象可能会引用类本身(例如单件模式)。
1039 tree
1040 tree_cons (tree purpose, tree value, tree chain) in tree.c
1041 {
1042 tree node;
1043
1044 node = ggc_alloc_tree (sizeof (struct tree_list));
1045
1046 memset (node, 0, sizeof (struct tree_common));
1047
1048 #ifdef GATHER_STATISTICS
1049 tree_node_counts[(int) x_kind]++;
1050 tree_node_sizes[(int) x_kind] += sizeof (struct tree_list);
1051 #endif
1052
1053 TREE_SET_CODE (node, TREE_LIST);
1054 TREE_CHAIN (node) = chain;
1055 TREE_PURPOSE (node) = purpose;
1056 TREE_VALUE (node) = value;
1057 return node;
1058 }
节点tree_list有域TREE_VALUE和TREE_PURPOSE。tree_list节点通过TREE_CHAIN域连接构成链表。TREE_VALUE域保存需要链接起来的值,而TREE_PURPOSE域偶尔也会使用来实现Lisp中的关联链表(association lists)。
767 struct tree_list GTY(()) in tree.h
768 {
769 struct tree_common common;
770 tree purpose;
771 tree value;
772 };
2.2.3.1.5.2.2.4. CONST_DECL及TYPE_DECL类型
在一个类中,只会出现VAR_DECL,FIELD_DECL,CONST_DECL和TYPE_DECL,因此下面849行的条件语句筛选出CONST_DECL和TYPE_DECL。CONST_DECL和TYPE_DECL的细节如下:
CONST_DECL[2]
² 这些节点用于表示枚举常量。常量的值由DECL_INITIAL给出,它必须是与CONST_DECL的TREE_TYPE类型相同的INTEGER_CST,即一个ENUMERAL_TYPE类型。
TYPE_DECL[2]
² 这些节点表示typedef声明。TREE_TYPE是被声明为有由DECL_NAME指定名字的类型。在某些情况下,会没有关联的名字。
place_field (continue)
847 /* Enumerators and enum types which are local to this class need not
848 be laid out. Likewise for initialized constant fields. */
849 else if (TREE_CODE (field) != FIELD_DECL)
850 return;
851
852 /* Unions are laid out very differently than records, so split
853 that code off to another function. */
854 else if (TREE_CODE (rli->t) != RECORD_TYPE)
855 {
856 place_union_field (rli, field);
857 return;
858 }
在C/C++,常量被保持在bss段,不占用类实例的空间。同样typedef声明创建了新的类型,也不会占用类实例空间。因此它们不需要被place_field处理。