Studying note of GCC-3.4.6 source (137)

5.12.5.2.2.2.1.3.7.            Finish the derived RECORD_TYPE – verify methods

Next, some fix may need be done if t is the derived type. Recall that in C++, once declaring a method as virtual in the base class, later all overrides are considered as virtual too no matter you declare them as virtual or not. And certain semantic check is expected as now we can see both the derived class and base class.

 

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 below if nonzero, points to a FUNCTION_DECL in a base class by which the FUNCTION_DECL (i.e., x ) will replace as a virtual function. Then TYPE_POLYMORPHIC_P for the class should be set to indicate it contain virtual method. Further if the method is the pure virtual (DECL_PURE_VIRTUAL_P returns nonzero), the class should be chained by CLASSTYPE_PURE_VIRTUALS, as classes of this kind can’t be instantiated.

 

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   }

 

For normal method, semantic check carried during its parsing is good enough. However there is an exception, in C++, if a method is declared as virtual in base class, its overload is virtual one too in derived class even if it is not declared as virtual there. This fix is done by 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 is nonzero if the node is a destructor, and DECL_CONV_FN_P is nonzero if the node is a user-defined conversion operator, and IDENTIFIER_VIRTUAL_P is nonzero if this identifier is used as a virtual function name somewhere. We checks for these 3 cases is because unlike normal virtual method which name is same in during derivation, and has IDENTIFIER_VIRTUAL_P set as long as any declaration is declared as virtual; destructor and user-defined conversion operator must have different name in derived class.

 

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 is nonzero if and only if a class declares or inherits a virtual function. It tells us which base class should be looked into for searching the virtual declaration.

 

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   }

 

See that if look_for_overrides_here finds out the specified virtual function declaration in base, the declaration we interesting here is tagged as virtual at line 1925.

 

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   }

 

It is possible that user defines a virtual method in base class, and then overrides it as static method in derived one. For the case, look_for_overrides_here must be able to find out the base virtual one as requested. However, such definition is not allowed in C++, it is complained by look_for_overrides_r immediately after invoking look_for_overrides_here .

Even for non-static method, some rules should be obeyed to be a validate overrides for virtual base method. First, the returned type of both methods must be compatible. They are either the same, or the type returned by base method is also the base for the type returned by derived one, and both have the same cv-qualifier and reference level. Next, both should throw out the compatible exception.

 

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   }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值