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

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 行)。

 

你可能感兴趣的:(GCC-3.4.6源代码学习笔记 (104))