回到 cxx_init_decl_processing ,接下来 GCC 将最终确定的内联函数的选项置入 flag_inline_trees 。 2983 行的 ptrmemfunc_vbit_in_pfn 是枚举类型 ptrmemfunc_vbit_where_t 。
2048 enum ptrmemfunc_vbit_where_t in tree.h
2049 {
2050 ptrmemfunc_vbit_in_pfn,
2051 ptrmemfunc_vbit_in_delta
2052 };
它之所以需要,是因为 GCC 需要编译使用了不同语言的程序,因此在系统中一个指向方法的指针看上去就像:
struct {
__P __pfn;
ptrdiff_t __delta;
};
如果 __pfn 为 NULL ,那么它是一个为 NULL 的方法指针。(因为 vtable 总是对象中位于第一的,我们不需要它的偏移。)如果函数是虚函数,那么 PFN 是 1 加上 2 倍其在 vtable 中的索引( PFN 为距 vtable 头的“偏移”,其最低位将是 1 );否则就是指向函数的指针(通常,函数地址有对齐要求,其最低位将是 0 ,这样由这个最低位就可以知道函数是否是虚函数)。
不过,这样使用 PFN 的最低位在不要求函数地址对齐的机器上不能奏效;或者,例如使用最低位来区分不同的指令集架构( ISA )。对于这样的机器,我们使用 DELTA 的最低位,而不是 PFN 的,并且 DELTA 的值将加倍。
毫无疑问宏 TARGET_PTRMEMFUNC_VBIT_LOCATION 即记录了这个区分虚函数与普通函数的比特位在何处。对于 x86 ,这个宏就是 ptrmemfunc_vbit_in_pfn 。全局变量 force_align_functions_log 则记录了对函数地址对齐的强制要求(以 2 为底的对数)。显然如果它为 0 ,则没有对齐要求,那些需要将其调整至 1 (对齐至偶数字节处)。
cxx_init_decl_processing (continue)
2967 /* Adjust various flags based on command-line settings. */
2968 if (!flag_permissive )
2969 flag_pedantic_errors = 1;
2970 if (!flag_no_inline )
2971 {
2972 flag_inline_trees = 1;
2973 flag_no_inline = 1;
2974 }
2975 if (flag_inline_functions )
2976 {
2977 flag_inline_trees = 2;
2978 flag_inline_functions = 0;
2979 }
2980
2981 /* Force minimum function alignment if using the least significant
2982 bit of function pointers to store the virtual bit. */
2983 if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
2984 && force_align_functions_log < 1)
2985 force_align_functions_log = 1;
2986
2987 /* Initially, C. */
2988 current_lang_name = lang_name_c;
2989
2990 build_common_tree_nodes (flag_signed_char );
2991
2992 error_mark_list = build_tree_list (error_mark_node, error_mark_node);
2993 TREE_TYPE (error_mark_list ) = error_mark_node;
在 内建类型的树节点 一节,已经看过相关内建类型节点的创建。这些节点正是在下面的函数中构建的。
4834 void
4835 build_common_tree_nodes (int signed_char) in tree.c
4836 {
4837 error_mark_node = make_node (ERROR_MARK);
4838 TREE_TYPE (error_mark_node) = error_mark_node;
4839
4840 initialize_sizetypes ();
4841
4842 /* Define both `signed char' and `unsigned char'. */
4843 signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
4844 unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
4845
4846 /* Define `char', which is like either `signed char' or `unsigned char'
4847 but not the same as either. */
4848 char_type_node
4849 = (signed_char
4850 ? make_signed_type (CHAR_TYPE_SIZE)
4851 : make_unsigned_type (CHAR_TYPE_SIZE));
4852
4853 short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
4854 short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
4855 integer_type_node = make_signed_type (INT_TYPE_SIZE);
4856 unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
4857 long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
4858 long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
4859 long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
4860 long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
4861
4862 /* Define a boolean type. This type only represents boolean values but
4863 may be larger than char depending on the value of BOOL_TYPE_SIZE.
4864 Front ends which want to override this size (i.e. Java) can redefine
4865 boolean_type_node before calling build_common_tree_nodes_2. */
4866 boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE);
4867 TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE);
4868 TYPE_MAX_VALUE (boolean_type_node) = build_int_2 (1, 0);
4869 TREE_TYPE (TYPE_MAX_VALUE (boolean_type_node)) = boolean_type_node;
4870 TYPE_PRECISION (boolean_type_node) = 1;
4871
4872 /* Fill in the rest of the sized types. Reuse existing type nodes
4873 when possible. */
4874 intQI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (QImode), 0);
4875 intHI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (HImode), 0);
4876 intSI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (SImode), 0);
4877 intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 0);
4878 intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 0);
4879
4880 unsigned_intQI_type_node =make_or_reuse_type(GET_MODE_BITSIZE (QImode), 1);
4881 unsigned_intHI_type_node =make_or_reuse_type(GET_MODE_BITSIZE (HImode), 1);
4882 unsigned_intSI_type_node = make_or_reuse_type(GET_MODE_BITSIZE (SImode), 1);
4883 unsigned_intDI_type_node =make_or_reuse_type(GET_MODE_BITSIZE (DImode), 1);
4884 unsigned_intTI_type_node = make_or_reuse_type(GET_MODE_BITSIZE (TImode), 1);
4885
4886 access_public_node = get_identifier ("public");
4887 access_protected_node = get_identifier ("protected");
4888 access_private_node = get_identifier ("private");
4889 }
在 C++ 中,内建类型 short , unsighed short , int 等,其大小与所运行的平台有关。因此,在编译器的实现中,需要把这些类型的节点与标准尺寸节点关联。这些标准尺寸节点就是上面的 intQI_type_node , intHI_type_node 等。关联由 make_or_reuse_type 建立。其意义在于能快速确定内建类型的模式(即其内存使用),例如,如果知道 short_integer_type_node 就 intHI_type_node ,即可知 short 是 HI 模式。
4809 static tree
4810 make_or_reuse_type (unsigned size, int unsignedp) in tree.c
4811 {
4812 if (size == INT_TYPE_SIZE)
4813 return unsignedp ? unsigned_type_node : integer_type_node;
4814 if (size == CHAR_TYPE_SIZE)
4815 return unsignedp ? unsigned_char_type_node : signed_char_type_node;
4816 if (size == SHORT_TYPE_SIZE)
4817 return unsignedp ? short_unsigned_type_node : short_integer_type_node;
4818 if (size == LONG_TYPE_SIZE)
4819 return unsignedp ? long_unsigned_type_node : long_integer_type_node;
4820 if (size == LONG_LONG_TYPE_SIZE)
4821 return (unsignedp ? long_long_unsigned_type_node
4822 : long_long_integer_type_node);
4823
4824 if (unsignedp)
4825 return make_unsigned_type (size);
4826 else
4827 return make_signed_type (size);
4828 }
另, 4886 行至 4888 行创建的是关键字: public , protected , private 的树节点。