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

5.12.5.2.2.2.1.3.7.            完成派生类的 RECORD_TYPE 验证方法

接着,如果 t 是该派生类,就需要执行某些修正。回忆在 C++ 中,一旦把一个方法在基类中声明为虚函数,随后不管你是否把重载函数声明为虚函数,这些重载都被视为虚函数。而因为现在我们能同时看到派生类及基类,特定的语义检查是被期望的。

 

check_bases_and_members (continue)

 

4175     /* Check all the method declarations.  */

4176     check_methods (t);

4177      

4178     /* A nearly-empty class has to be vptr-containing; a nearly empty

4179       class contains just a vptr.  */

4180     if (!TYPE_CONTAINS_VPTR_P (t))

4181       CLASSTYPE_NEARLY_EMPTY_P (t) = 0;

4182  

4183     /* Do some bookkeeping that will guide the generation of implicitly

4184       declared member functions.  */

4185     TYPE_HAS_COMPLEX_INIT_REF (t)

4186         |= (TYPE_HAS_INIT_REF (t)

4187            || TYPE_USES_VIRTUAL_BASECLASSES (t)

4188            || TYPE_POLYMORPHIC_P (t));

4189     TYPE_NEEDS_CONSTRUCTING (t)

4190         |= (TYPE_HAS_CONSTRUCTOR (t)

4191            || TYPE_USES_VIRTUAL_BASECLASSES (t)

4192            || TYPE_POLYMORPHIC_P (t));

4193     CLASSTYPE_NON_AGGREGATE (t) |= (TYPE_HAS_CONSTRUCTOR (t)

4194                                         || TYPE_POLYMORPHIC_P (t));

4195     CLASSTYPE_NON_POD_P (t)

4196       |= (CLASSTYPE_NON_AGGREGATE (t) || TYPE_HAS_DESTRUCTOR (t)

4197          || TYPE_HAS_ASSIGN_REF (t));

4198     TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);

4199     TYPE_HAS_COMPLEX_ASSIGN_REF (t)

4200       |= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t);

4201  

4202     /* Synthesize any needed methods. Note that methods will be synthesized

4203       for anonymous unions; grok_x_components undoes that.  */

4204     add_implicitly_declared_members (t, cant_have_default_ctor,

4205                                  cant_have_const_ctor,

4206                                 no_const_asn_ref);

 

下面的 DECL_VINDEX ,如果是非 0 值,指向在一个基类中的一个 FUNCTION_DECL ,它将被该 FUNCTION_DECL (即 x )作为一个虚函数来替换。那么对于该类,应该设置 TYPE_POLYMORPHIC_P 来表示它包含了虚函数。进一步的如果该方法是纯虚的( DECL_PURE_VIRTUAL_P 返回非 0 值),因为这种类型的类不能被具现,它应该被串接入 CLASSTYPE_PURE_VIRTUALS 域的链表中。

 

3770   static void

3771   check_methods (tree t)                                                                            in class.c

3772   {

3773     tree x;

3774  

3775     for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))

3776     {

3777       /* If this was an evil function, don't keep it in class.  */

3778       if (DECL_ASSEMBLER_NAME_SET_P (x)

3779           && IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x)))

3780         continue ;

3781  

3782       check_for_override (x, t);

3783       if (DECL_PURE_VIRTUAL_P (x) && ! DECL_VINDEX (x))

3784         cp_error_at ("initializer specified for non-virtual method `%D'", x);

3785  

3786       /* The name of the field is the original field name

3787          Save this in auxiliary field for later overloading.  */

3788       if (DECL_VINDEX (x))

3789       {

3790          TYPE_POLYMORPHIC_P (t) = 1;

3791          if (DECL_PURE_VIRTUAL_P (x))

3792            CLASSTYPE_PURE_VIRTUALS (t)

3793                = tree_cons (NULL_TREE, x, CLASSTYPE_PURE_VIRTUALS (t));

3794       }

3795     }

3796   }

 

对于普通的方法,在其解析期间的语义检查是足够好的。不过这里有一个例外,在 C++ 中,如果一个方法在基类中被声明为虚函数,在派生类中其重载亦被视为虚函数,而不管其是否被声明为虚函数。这里通过 check_for_override 进行这个修正。

 

2423   static void

2424   check_for_override (tree decl, tree ctype)                                                         in class.c

2425   {

2426     if (TREE_CODE (decl) == TEMPLATE_DECL)

2427       /* In [temp.mem] we have:

2428  

2429         A specialization of a member function template does not

2430         override a virtual function from a base class.  */

2431       return ;

2432     if ((DECL_DESTRUCTOR_P (decl)

2433          || IDENTIFIER_VIRTUAL_P (DECL_NAME (decl))

2434          || DECL_CONV_FN_P (decl))

2435        && look_for_overrides (ctype, decl)

2436        && !DECL_STATIC_FUNCTION_P (decl))

2437       /* Set DECL_VINDEX to a value that is neither an INTEGER_CST nor

2438         the error_mark_node so that we know it is an overriding

2439         function.  */

2440       DECL_VINDEX (decl) = decl;

2441  

2442     if (DECL_VIRTUAL_P (decl))

2443     {

2444       if (!DECL_VINDEX (decl))

2445         DECL_VINDEX (decl) = error_mark_node;

2446       IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;

2447     }

2448   }

 

DECL_DESTRUCTOR_P 是非 0 值,如果该节点是一个析构函数; DECL_CONV_FN_P 是非 0 值,如果该节点是一个用户定义的转换操作符;而 IDENTIFIER_VIRTUAL_P 是非 0 值,如果该标识符在某些地方被用作一个虚函数的名字。我们需要检查这 3 种情形是因为不像普通虚函数的名字在派生的过程中是不变的,并且一旦某个声明被说明为虚函数就设置 IDENTIFIER_VIRTUAL_P ;析构函数与用户定义转换操作符在派生类中必须使用不同的名字。

 

1849   int

1850   look_for_overrides (tree type, tree fndecl)                                                        in search.c

1851   {

1852     tree binfo = TYPE_BINFO (type);

1853     tree basebinfos = BINFO_BASETYPES (binfo);

1854     int nbasebinfos = basebinfos ? TREE_VEC_LENGTH (basebinfos) : 0;

1855     int ix;

1856     int found = 0;

1857       

1858     for (ix = 0; ix != nbasebinfos; ix++)

1859     {

1860       tree basetype = BINFO_TYPE (TREE_VEC_ELT (basebinfos, ix));

1861       

1862       if (TYPE_POLYMORPHIC_P (basetype))

1863         found += look_for_overrides_r (basetype, fndecl);

1864     }

1865     return found;

1866   }

 

TYPE_POLYMORPHIC_P 不为 0 当且仅当一个类声明或继承了一个虚函数。它告诉我们查找虚函数声明时应该查询哪些基类。

 

1909   static int

1910   look_for_overrides_r (tree type, tree fndecl)                                              in search.c

1911   {

1912     tree fn = look_for_overrides_here (type, fndecl);

1913     if (fn)

1914     {

1915       if (DECL_STATIC_FUNCTION_P (fndecl))

1916       {

1917         /* A static member function cannot match an inherited

1918           virtual member function.  */

1919         cp_error_at ("`%#D' cannot be declared", fndecl);

1920         cp_error_at ("  since `%#D' declared in base class", fn);

1921       }

1922       else

1923       {

1924         /* It's definitely virtual, even if not explicitly set.  */

1925         DECL_VIRTUAL_P (fndecl) = 1;

1926         check_final_overrider (fndecl, fn);

1927       }

1928       return 1;

1929     }

1930  

1931     /* We failed to find one declared in this class. Look in its bases.  */

1932     return look_for_overrides (type, fndecl);

1933   }

 

看到如果 look_for_overrides_here 在基类中找出所指定的虚函数声明,在 1925 行这个目标声明被标记为虚( virtual )。

 

1871   tree

1872   look_for_overrides_here (tree type, tree fndecl)                                          in search.c

1873   {

1874     int ix;

1875  

1876     if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fndecl))

1877       ix = CLASSTYPE_DESTRUCTOR_SLOT;

1878     else

1879       ix = lookup_fnfields_1 (type, DECL_NAME (fndecl));

1880     if (ix >= 0)

1881     {

1882       tree fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix);

1883    

1884       for (; fns; fns = OVL_NEXT (fns))

1885       {

1886         tree fn = OVL_CURRENT (fns);

1887  

1888         if (!DECL_VIRTUAL_P (fn))

1889           /* Not a virtual.  */;

1890         else if (DECL_CONTEXT (fn) != type)

1891            /* Introduced with a using declaration.  */;

1892         else if (DECL_STATIC_FUNCTION_P (fndecl))

1893         {

1894           tree btypes = TYPE_ARG_TYPES (TREE_TYPE (fn));

1895           tree dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl));

1896           if (compparms (TREE_CHAIN (btypes), dtypes))

1897             return fn;

1898         }

1899         else if (same_signature_p (fndecl, fn))

1900           return fn;

1901       }

1902     }

1903     return NULL_TREE;

1904   }

 

用户可能在基类中定义一个虚函数,然后在派生类中把它重载为静态方法。对于这种情形, look_for_overrides_here 必须能找出这个基类的虚函数。不过,这样的定义在 C++ 中是不被允许的,在 look_for_overrides_here 的调用之后, look_for_overrides_r 立即给出出错消息。

即便对于非静态方法,要成为基类虚函数的一个有效的重载也需要遵守某些规则。首先,两者的返回类型必须兼容。它们要么是相同的,要么基类方法返回的类型也是派生类方法返回类型的基类,并且两者具有相同的 c-v 限定词及引用层次,两者应该抛出兼容的异常。

 

1743   int

1744   check_final_overrider (tree overrider, tree basefn)                                      in search.c

1745   {

1746     tree over_type = TREE_TYPE (overrider);

1747     tree base_type = TREE_TYPE (basefn);

1748     tree over_return = TREE_TYPE (over_type);

1749     tree base_return = TREE_TYPE (base_type);

1750     tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);

1751     tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);

1752     int fail = 0;

1753    

1754     if (same_type_p (base_return, over_return))

1755        /* OK */;

1756     else if ((CLASS_TYPE_P (over_return) && CLASS_TYPE_P (base_return))

1757            || (TREE_CODE (base_return) == TREE_CODE (over_return)

1758               && POINTER_TYPE_P (base_return)))

1759     {

1760        /* Potentially covariant.  */

1761       unsigned base_quals, over_quals;

1762        

1763       fail = !POINTER_TYPE_P (base_return);

1764       if (!fail)

1765       {

1766         fail = cp_type_quals (base_return) != cp_type_quals (over_return);

1767         

1768         base_return = TREE_TYPE (base_return);

1769         over_return = TREE_TYPE (over_return);

1770       }

1771       base_quals = cp_type_quals (base_return);

1772       over_quals = cp_type_quals (over_return);

1773  

1774       if ((base_quals & over_quals) != over_quals)

1775         fail = 1;

1776        

1777       if (CLASS_TYPE_P (base_return) && CLASS_TYPE_P (over_return))

1778       {

1779         tree binfo = lookup_base (over_return, base_return,

1780                              ba_check | ba_quiet, NULL);

1781  

1782         if (!binfo)

1783           fail = 1;

1784       }

1785       else if (!pedantic

1786              && can_convert (TREE_TYPE (base_type), TREE_TYPE (over_type)))

1787       /* GNU extension, allow trivial pointer conversions such as

1788         converting to void *, or qualification conversion.  */

1789       {

1790         /* can_convert will permit user defined conversion from a

1791           (reference to) class type. We must reject them.  */

1792         over_return = non_reference (TREE_TYPE (over_type));

1793         if (CLASS_TYPE_P (over_return))

1794           fail = 2;

1795       }

1796       else

1797          fail = 2;

1798     }

1799     else

1800       fail = 2;

1801     if (!fail)

1802        /* OK */;

1803     else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)))

1804       return 0;

1805     else

1806     {

1807       if (fail == 1)

1808       {

1809         cp_error_at ("invalid covariant return type for `%#D'", overrider);

1810         cp_error_at ("  overriding `%#D'", basefn);

1811       }

1812       else

1813       {

1814          cp_error_at ("conflicting return type specified for `%#D'",

1815                    overrider);

1816         cp_error_at ("  overriding `%#D'", basefn);

1817       }

1818       SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),

1819                                        DECL_CONTEXT (overrider));

1820       return 0;

1821     }

1822    

1823     /* Check throw specifier is at least as strict.  */

1824     if (!comp_except_specs (base_throw, over_throw, 0))

1825     {

1826       if (!IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)))

1827       {

1828          cp_error_at ("looser throw specifier for `%#F'", overrider);

1829          cp_error_at ("  overriding `%#F'", basefn);

1830          SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),

1831                                           DECL_CONTEXT (overrider));

1832       }

1833       return 0;

1834     }

1835    

1836     return 1;

1837   }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值