5.12.3.2.1.1.3.5.3. 完成
根据返回的 arg_types 及 parms ,在 grokdeclarator 的 7601 行, build_function_type 构建了如下的 FUNCTION_TYPE 节点。
( 点此打开 )
图 81 :构建的 FUNCTION_TYPE 节点
现在与 CALL_EXPR 相关的节点都没用了,因为已经没有到 CALL_EXPR 节点的引用。那么在 grokdeclarator 的 8240 行, build_method_type_directly 构建了如下的 METHOD_TYPE 节点。
( 点此打开 )
图 82 :构建的 METHOD_TYPE 节点
紧接着在 grokdeclarator 的 8250 行, grokfndecl 则构建了如下的 FUNCTION_DECL 节点。
( 点此打开 )
图 83 :构建的 FUNCTION_DECL 节点
当返回到 start_method 时,在加入对应于目标声明的节点后,得到如下的中间树。
( 点此打开 )
图 84 :构建的 TEMPLATE_DECL 节点
接着在 start_method 的 11087 行,在 grok_special_member_properties 中, copy_fn_p 返回表示构造函数或者赋值操作符特性的值。
假定 D 是一个构造函数或重载的 `operator=' 。而 T 是包含 D 的声明的类。那么这个函数返回:
-1 ,如果 D 的声明是一个错误形式的构造函数或拷贝赋值操作符,其第一个参数具有类型 `T' 。
0 ,如果 D 不是拷贝构造函数或拷贝赋值操作符。
1 ,如果 D 是一个拷贝构造函数或拷贝赋值操作符,其第一个参数的类型是 const 限定的 T 的引用。
2 ,如果 D 是一个拷贝构造函数或拷贝赋值操作符,其第一个参数的类型非 const 限定的 T 的引用。
8853 int
8854 copy_fn_p (tree d) in decl.c
8855 {
8856 tree args;
8857 tree arg_type;
8858 int result = 1;
8859
8860 my_friendly_assert (DECL_FUNCTION_MEMBER_P (d), 20011208);
8861
8862 if (DECL_TEMPLATE_INFO (d) && is_member_template (DECL_TI_TEMPLATE (d)))
8863 /* Instantiations of template member functions are never copy
8864 functions. Note that member functions of templated classes are
8865 represented as template functions internally, and we must
8866 accept those as copy functions. */
8867 return 0;
8868
8869 args = FUNCTION_FIRST_USER_PARMTYPE (d);
8870 if (!args)
8871 return 0;
8872
8873 arg_type = TREE_VALUE (args);
8874
8875 if (TYPE_MAIN_VARIANT (arg_type) == DECL_CONTEXT (d))
8876 {
8877 /* Pass by value copy assignment operator. */
8878 result = -1;
8879 }
8880 else if (TREE_CODE (arg_type) == REFERENCE_TYPE
8881 && TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d))
8882 {
8883 if (CP_TYPE_CONST_P (TREE_TYPE (arg_type)))
8884 result = 2;
8885 }
8886 else
8887 return 0;
8888
8889 args = TREE_CHAIN (args);
8890
8891 if (args && args != void_list_node && !TREE_PURPOSE (args))
8892 /* There are more non-optional args. */
8893 return 0;
8894
8895 return result;
8896 }
毫无疑问,对于我们的拷贝构造函数,这个结果将是 0 ,因为其参数的类型不是“ Lock ”。因此在 grok_special_member_properties 中不做任何事。
5.12.3.2.1.1.3.1. 完成解析
在解析了非默认构造函数后,我们来到了类的末尾。它必须是“ }; ”来结束定义。因为 GNU 扩展允许为类在符号“ } ”及“ ; ”之间声明属性,需要尝试解析这个可选的属性。
cp_parser_class_specifier (continue)
11913 cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
11914 /* We get better error messages by noticing a common problem: a
11915 missing trailing `;'. */
11916 token = cp_lexer_peek_token (parser->lexer);
11917 has_trailing_semicolon = (token->type == CPP_SEMICOLON);
11918 /* Look for trailing attributes to apply to this class. */
11919 if (cp_parser_allow_gnu_extensions_p (parser))
11920 {
11921 tree sub_attr = cp_parser_attributes_opt (parser);
11922 attributes = chainon (attributes, sub_attr);
11923 }
11924 if (type != error_mark_node)
11925 type = finish_struct (type, attributes);
11926 if (pop_p)
11927 pop_scope (scope);
如果运行顺利,就可以结束对该类的解析,同时安装上为类声明的属性。
5228 tree
5229 finish_struct (tree t, tree attributes) in class.c
5230 {
5231 location_t saved_loc = input_location ;
5232
5233 /* Now that we've got all the field declarations, reverse everything
5234 as necessary. */
5235 unreverse_member_declarations (t);
5236
5237 cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
5238
5239 /* Nadger the current location so that diagnostics point to the start of
5240 the struct, not the end. */
5241 input_location = DECL_SOURCE_LOCATION (TYPE_NAME (t));
正如我们前面看到的,构成该方法声明符的节点按声明的相反顺序串接起来,因此现在需要再反序一次来恢复其次序。
5197 void
5198 unreverse_member_declarations (tree t) in class.c
5199 {
5200 tree next;
5201 tree prev;
5202 tree x;
5203
5204 /* The following lists are all in reverse order. Put them in
5205 declaration order now. */
5206 TYPE_METHODS (t) = nreverse (TYPE_METHODS (t));
5207 CLASSTYPE_DECL_LIST (t) = nreverse (CLASSTYPE_DECL_LIST (t));
5208
5209 /* Actually, for the TYPE_FIELDS, only the non TYPE_DECLs are in
5210 reverse order, so we can't just use nreverse. */
5211 prev = NULL_TREE;
5212 for (x = TYPE_FIELDS (t);
5213 x && TREE_CODE (x) != TYPE_DECL;
5214 x = next)
5215 {
5216 next = TREE_CHAIN (x);
5217 TREE_CHAIN (x) = prev;
5218 prev = x;
5219 }
5220 if (prev)
5221 {
5222 TREE_CHAIN (TYPE_FIELDS (t)) = x;
5223 if (prev)
5224 TYPE_FIELDS (t) = prev;
5225 }
5226 }
在 5237 行, cplus_decl_attributes 安装类的可选的属性,对于“ struct Lock ”,类级别的属性没有出现。
finish_struct (continue)
5243 if (processing_template_decl )
5244 {
5245 finish_struct_methods (t);
5246 TYPE_SIZE (t) = bitsize_zero_node;
5247 TYPE_SIZE_UNIT (t) = size_zero_node;
5248 }
5249 else
5250 finish_struct_1 (t);
5251
5252 input_location = saved_loc;
5253
5254 TYPE_BEING_DEFINED (t) = 0;
5255
5256 if (current_class_type )
5257 popclass ();
5258 else
5259 error ("trying to finish struct, but kicked out due to previous parse errors");
5260
5261 if (processing_template_decl && at_function_scope_p ())
5262 add_stmt (build_min (TAG_DEFN, t));
5263
5264 return t;
5265 }
如果我们处理 类模板,类的细节将在具现( instantiation )那点上才能确定(例如,如果 从一个类模板派生,派生类只有在具现点才能生成)。 因此,仅有有限的操作需要被 finish_struct_methods 执行,并且甚至类的大小也,在 5264 及 5267 行,临时地声明为 0 。
1718 static void
1719 finish_struct_methods (tree t) in class.c
1720 {
1721 tree fn_fields;
1722 tree method_vec;
1723 int slot, len;
1724
1725 if (!TYPE_METHODS (t))
1726 {
1727 /* Clear these for safety; perhaps some parsing error could set
1728 these incorrectly. */
1729 TYPE_HAS_CONSTRUCTOR (t) = 0;
1730 TYPE_HAS_DESTRUCTOR (t) = 0;
1731 CLASSTYPE_METHOD_VEC (t) = NULL_TREE;
1732 return ;
1733 }
1734
1735 method_vec = CLASSTYPE_METHOD_VEC (t);
1736 my_friendly_assert (method_vec != NULL_TREE, 19991215);
1737 len = TREE_VEC_LENGTH (method_vec);
1738
1739 /* First fill in entry 0 with the constructors, entry 1 with destructors,
1740 and the next few with type conversion operators (if any). */
1741 for (fn_fields = TYPE_METHODS (t); fn_fields;
1742 fn_fields = TREE_CHAIN (fn_fields))
1743 /* Clear out this flag. */
1744 DECL_IN_AGGR_P (fn_fields) = 0;
1745
1746 if (TYPE_HAS_DESTRUCTOR (t) && !CLASSTYPE_DESTRUCTORS (t))
1747 /* We thought there was a destructor, but there wasn't. Some
1748 parse errors cause this anomalous situation. */
1749 TYPE_HAS_DESTRUCTOR (t) = 0;
1750
1751 /* Issue warnings about private constructors and such. If there are
1752 no methods, then some public defaults are generated. */
1753 maybe_warn_about_overly_private_class (t);
1754
1755 /* Now sort the methods. */
1756 while (len > 2 && TREE_VEC_ELT (method_vec, len-1) == NULL_TREE)
1757 len--;
1758 TREE_VEC_LENGTH (method_vec) = len;
1759
1760 /* The type conversion ops have to live at the front of the vec, so we
1761 can't sort them. */
1762 for (slot = 2; slot < len; ++slot)
1763 {
1764 tree fn = TREE_VEC_ELT (method_vec, slot);
1765
1766 if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
1767 break ;
1768 }
1769 if (len - slot > 1)
1770 qsort (&TREE_VEC_ELT (method_vec, slot), len-slot, sizeof (tree),
1771 method_name_cmp);
1772 }
看到这个有限的处理仅包括修正被错误语句错误设置的标记。有时候,当写下一个如同“ Lock ”的简单类时,它可能被错误地写作:
cass Lock {
Lock();
Lock(const Host&);
};
因为它遗失了访问控制符“ public ”,这个构造函数不能被调用。解析器可以为此给出警告。不过,当类有友元,或者其它公有方法(静态或非静态),这就很难判断构造函数是否能够从外部调用。解析器就假定可以,并且如果在随后的代码中它不能被调用,将给出错误。在 1753 行, maybe_warn_about_overly_private_class 执行这个检查。
现在类的所有方法都已知,为了加快对方法检索速度,方法需要被排序使得可以应用二分查找( 1770 行)。