Studying note of GCC-3.4.6 source (140)

5.12.5.2.2.2.1.3.10.        Finish the RECORD_TYPE – build vtable

Remember in determine_primary_base , if we find a primary base we just remember its vtable (recall that it must contain vtable, else we wouldn’t have primary base), now we need our own. Note the assertions from line 5057 to 5064, they can help us to find out inconsistency as early as posssible.

 

finish_struct_1 (continue)

 

5051     /* Make sure that we get our own copy of the vfield FIELD_DECL.  */

5052     vfield = TYPE_VFIELD (t);

5053     if (vfield && CLASSTYPE_HAS_PRIMARY_BASE_P (t))

5054     {

5055       tree primary = CLASSTYPE_PRIMARY_BINFO (t);

5056  

5057       my_friendly_assert (same_type_p (DECL_FIELD_CONTEXT (vfield),

5058                        BINFO_TYPE (primary)),

5059                        20010726);

5060       /* The vtable better be at the start.  */

5061       my_friendly_assert (integer_zerop (DECL_FIELD_OFFSET (vfield)),

5062                        20010726);

5063       my_friendly_assert (integer_zerop (BINFO_OFFSET (primary)),

5064                        20010726);

5065        

5066       vfield = copy_decl (vfield);

5067       DECL_FIELD_CONTEXT (vfield) = t;

5068       TYPE_VFIELD (t) = vfield;

5069     }

5070     else

5071       my_friendly_assert (!vfield || DECL_FIELD_CONTEXT (vfield) == t, 20010726);

5072  

5073     virtuals = modify_all_vtables (t, nreverse (virtuals));

5074  

5075     /* If we created a new vtbl pointer for this class, add it to the

5076       list.  */

5077     if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))

5078       CLASSTYPE_VFIELDS (t)

5079         = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));

 

Remember virtuals above records the virtual functions in t if there is any. But it is in reverse order, so first uses nreverse to restore it. Note that t is the current class type, and it is passed as data for dfs_walk . And virtuals gets its content via transving TYPE_METHOD chain and selects out virtuals (see create_vtable_ptr ), then what is in BINFO_VIRTUAL of the binfo of current type? In set_primary_base , at determining primary base, TYPE_BINFO_VIRTUALS of current type is set as TYPE_BINFO_VIRTUALS of the primary base (TYPE_BINFO_VIRTUALS (t) is defined as BINFO_VIRTUALS (TYPE_BINFO (t)) ). So what is TYPE_BINFO_VIRTUALS of B1 (the primary base)? In turn, originally it gets its content from TYPE_BINFO_VIRTUALS of A (see example 1 & 2 at beginning of the section).

Let’s go back to early time, at which class A being finished. No doubt, at first, A has empty TYPE_BINFO_VIRTUALS. Below dfs_modify_vtables does nothing for the type, and modify_all_vtables in turn returns A::f as virtuals . Next back finish_struct_1 in below, primary vtable is created for A at line 5086 via build_primary_vtable ; and its TYPE_BINFO_VIRTUALS contains A::f by line 5106.

So, when finishing B1, its TYPE_BINFO_VIRTUALS also contains that of A, i.e. A::f. Then in dfs_modify_vtables below, at line 2314, the secondary vtable is prepared for A. Note that dfs_modify_vtables visits binfo of bases in the hierarchy tree from bottom up (B1 is the root), so first under processing is A within B1. It is discovered in later that A::f would be replaced by B1::f with a thunk. Next is B1 itself, its A::f is also replaced by B1::f with thunk (these 2 replacements occur in different places, the former is in base A’s secondary vtable, the rear is in B1’s primary vtable). Then in modify_all_vtables below, as DECL_VINDEX of B1::f in vrituals is not error_mark_node (see check_for_override , if it is error_mark_node , it means the function is not an overrider), and now BINFO_VIRTUALS (B1) contains B1::f with thunk, and since value_member returns true only if fn has the same address with any entity in the chain, so B1::f in virutals is kept and appended to TYPE_BINFO_VIRTUALS at line 5106. So this list contains B1::f with thunk, followed by B1::f.

Now comes to handle C, we know in TYPE_BINFO_VIRTUALS of C, it contains B1::f with result adjustment thunk, followed by B1::f; also C holds the copied binfo of B1. Following we will see the procedure in detail now.

 

2344   static tree

2345   modify_all_vtables (tree t, tree virtuals)                                                     in class.c

2346   {

2347     tree binfo = TYPE_BINFO (t);

2348     tree *fnsp;

2349  

2350     /* Update all of the vtables.  */

2351     dfs_walk (binfo, dfs_modify_vtables , unmarkedp , t);

2352     dfs_walk (binfo, dfs_unmark, markedp, t);

2353  

2354     /* Add virtual functions not already in our primary vtable. These

2355       will be both those introduced by this class, and those overridden

2356       from secondary bases. It does not include virtuals merely

2357       inherited from secondary bases.  */

2358     for (fnsp = &virtuals; *fnsp; )

2359     {

2360       tree fn = TREE_VALUE (*fnsp);

2361  

2362       if (!value_member (fn, BINFO_VIRTUALS (binfo))

2363           || DECL_VINDEX (fn) == error_mark_node)

2364       {

2365          /* We don't need to adjust the `this' pointer when

2366            calling this function.  */

2367          BV_DELTA (*fnsp) = integer_zero_node;

2368          BV_VCALL_INDEX (*fnsp) = NULL_TREE;

2369  

2370          /* This is a function not already in our vtable. Keep it.  */

2371          fnsp = &TREE_CHAIN (*fnsp);

2372       }

2373       else

2374         /* We've already got an entry for this function. Skip it.  */

2375         *fnsp = TREE_CHAIN (*fnsp);

2376     }

2377  

2378     return virtuals;

2379   }

 

Routine dfs_modfiy_vtables is executed in post-order during traversing the inherient tree by dfs_walk . Note that the function returns NULL to force the full walk, and during the walk bases get handled are those virtual bases or non-primary bases, and not include current type itself if it contains no vtable (in CLASSTYPE_VFIELDS which may be set in determine_primary_base ). For example 1 and 2, class C, B2 and A would be processed here by order A, B2, and C. Also needs to point out that, when handling A, all changes are made in copied binfo of A in C; and when handling B2, the changes confined in copied binfo of B2 in C; both handling in fact are very similar with B1. Below we just see the processing for C, remember BINFO_VIRTUALS of C at line 2319 contains B::f with thunk (this-adjustment and result-adjustment for A to B1).

 

2298   static tree

2299   dfs_modify_vtables (tree binfo, void* data)                                                in class.c

2300   {

2301     if (/* There's no need to modify the vtable for a non-virtual

2302          primary base; we're not going to use that vtable anyhow.

2303           We do still need to do this for virtual primary bases, as they

2304           could become non-primary in a construction vtable.  */

2305        (!BINFO_PRIMARY_P (binfo) || TREE_VIA_VIRTUAL (binfo))

2306        /* Similarly, a base without a vtable needs no modification.  */

2307        && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))

2308     {

2309       tree t = (tree) data;

2310       tree virtuals;

2311       tree old_virtuals;

2312       unsigned ix;

2313        

2314       make_new_vtable (t, binfo);

2315        

2316       /* Now, go through each of the virtual functions in the virtual

2317          function table for BINFO. Find the final overrider, and

2318          update the BINFO_VIRTUALS list appropriately.  */

2319       for (ix = 0, virtuals = BINFO_VIRTUALS (binfo),

2320              old_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));

2321             virtuals;

2322            ix++, virtuals = TREE_CHAIN (virtuals),

2323                old_virtuals = TREE_CHAIN (old_virtuals))

2324         update_vtable_entry_for_fn (t,

2325                                 binfo,

2326                                 BV_FN (old_virtuals),

2327                                 &virtuals, ix);

2328     }

2329  

2330     BINFO_MARKED (binfo) = 1;

2331  

2332     return NULL_TREE;

2333   }

 

Note that argument t is unchanged during this procedure, and always refers to the current class type being finished. And binfo is of base that visited currently. First, it creates vtable if it is needed. Here it will create vtable for A, B2, and C.

 

658    static int

659    make_new_vtable (tree t, tree binfo)                                                                in class.c

660    {

661      if (binfo == TYPE_BINFO (t))

662        /* In this case, it is *type*'s vtable we are modifying. We start

663          with the approximation that its vtable is that of the

664          immediate base class.  */

665        /* ??? This actually passes TYPE_BINFO (t), not the primary base binfo,

666          since we've updated DECL_CONTEXT (TYPE_VFIELD (t)) by now.  */

667        return build_primary_vtable (TYPE_BINFO (DECL_CONTEXT (TYPE_VFIELD (t))),

668                                 t);

669      else

670        /* This is our very own copy of `basetype' to play with. Later,

671          we will fill in all the virtual functions that override the

672          virtual functions in these base classes which are not defined

673          by the current type.  */

674        return build_secondary_vtable (binfo);

675    }

 

For A and B2, as their binfo is different from TYPE_BINFO (C), build_secondary_vtable is invoked. And because virtuals of these binfos are borrowed from binfos of the types (see copy_base_binfos in xref_basetypes ). Now it is time to have own copy.

 

634    static int

635    build_secondary_vtable (tree binfo)                                                            in class.c

636    {

637      if (BINFO_NEW_VTABLE_MARKED (binfo))

638        /* We already created a vtable for this base. There's no need to

639          do it again.  */

640        return 0;

641   

642      /* Remember that we've created a vtable for this BINFO, so that we

643        don't try to do so again.  */

644      SET_BINFO_NEW_VTABLE_MARKED (binfo);

645     

646      /* Make fresh virtual list, so we can smash it later.  */

647      BINFO_VIRTUALS (binfo) = copy_virtuals (binfo);

648   

649      /* Secondary vtables are laid out as part of the same structure as

650        the primary vtable.  */

651      BINFO_VTABLE (binfo) = NULL_TREE;

652      return 1;

653    }

 

BV_VCALL_INDEX if non-NULL, holds the vtable index at which to find the vcall offset when calling this virtual function (by adding the value to the this pointer). It must be cleaned to be reindexed.

 

562    static tree

563    copy_virtuals (tree binfo)                                                                         in class.c

564    {

565      tree copies;

566      tree t;

567   

568      copies = copy_list (BINFO_VIRTUALS (binfo));

569      for (t = copies; t; t = TREE_CHAIN (t))

570        BV_VCALL_INDEX (t) = NULL_TREE;

571   

572      return copies;

573    }

 

But for class C, build_primary_vtable is invoked as argument binfo here is the binfo of class C. Remember C now still uses TYPE_BINFO_VTABLE and TYPE_BINFO_VIRTUALS from its primary base, the class now needs its own copy.

 

581    static int

582    build_primary_vtable (tree binfo, tree type)                                                in class.c

583    {

584      tree decl;

585      tree virtuals;

586   

587      decl = get_vtable_decl (type, /*complete=*/ 0);

588     

589      if (binfo)

590      {

591        if (BINFO_NEW_VTABLE_MARKED (binfo))

592          /* We have already created a vtable for this base, so there's

593             no need to do it again.  */

594          return 0;

595         

596        virtuals = copy_virtuals (binfo);

597        TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo));

598        DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));

599        DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl));

600      }

601      else

602      {

603        my_friendly_assert (TREE_TYPE (decl) == vtbl_type_node, 20000118);

604        virtuals = NULL_TREE;

605      }

606   

607    #ifdef GATHER_STATISTICS

608      n_vtables += 1;

609      n_vtable_elems += list_length (virtuals);

610    #endif

611    

612      /* Initialize the association list for this type, based

613        on our first approximation.  */

614      TYPE_BINFO_VTABLE (type) = decl;

615      TYPE_BINFO_VIRTUALS (type) = virtuals;

616      SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type));

617      return 1;

618    }

 

If vtable has been created, CLASSTYPE_VTABLES field holds it; otherwise this field should be empty. Argument complete if nonzero means completing the definition of the vtable created in the function – by invoking cp_finish_decl which we are currently within to finish the variable of instantiation of class template “SmallObject”.

 

539    tree

540    get_vtable_decl (tree type, int complete)                                                     in class.c

541    {

542      tree decl;

543   

544      if (CLASSTYPE_VTABLES (type))

545        return CLASSTYPE_VTABLES (type);

546     

547      decl = build_vtable (type, get_vtable_name (type), vtbl_type_node );

548      CLASSTYPE_VTABLES (type) = decl;

549   

550      if (complete)

551      {

552        DECL_EXTERNAL (decl) = 1;

553        cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);

554      }

555   

556      return decl;

557    }

 

Vtable should be shared by all instances of the type (base is the exception, see BINFO_VTABLE is created in build_secondary_vtable ), so it should be created as static data member. Above get_vtable_name gets the mangled name for the vtable (GCC output of example 1 and 2 gives some examples of the mangled name), and vtbl_type_node is the type of constant array of vtable_entry_type (built in cxx_init_decl_processing ).

 

506    static tree

507    build_vtable (tree class_type, tree name, tree vtable_type)                            in class.c

508    {

509      tree decl;

510   

511       decl = build_lang_decl (VAR_DECL, name, vtable_type);

512      /* vtable names are already mangled; give them their DECL_ASSEMBLER_NAME

513        now to avoid confusion in mangle_decl.  */

514      SET_DECL_ASSEMBLER_NAME (decl, name);

515      DECL_CONTEXT (decl) = class_type;

516      DECL_ARTIFICIAL (decl) = 1;

517      TREE_STATIC (decl) = 1;

518      TREE_READONLY (decl) = 1;

519      DECL_VIRTUAL_P (decl) = 1;

520      DECL_ALIGN (decl) = TARGET_VTABLE_ENTRY_ALIGN;

521      DECL_VTABLE_OR_VTT_P (decl) = 1;

522   

523      /* At one time the vtable info was grabbed 2 words at a time. This

524        fails on sparc unless you have 8-byte alignment. (tiemann) */

525      DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),

526                                 DECL_ALIGN (decl));

527   

528      import_export_vtable (decl, class_type, 0);

529   

530      return decl;

531    }

 

At line 528, import_export_vtable sets TREE_PUBLIC and DECL_EXTERNAL for the VARL_DECL created. Note that at line 614 in build_primary_vtable , TYPE_BINFO_VIRTUALS accesses BINFO_VIRTUALS of binfo of the type passed as its argument.

At line 597 in build_primary_vtabl , get_vtbl_decl_for_binfo fetches the VAR_DECL of vtable of binfo .

 

6446   tree

6447   get_vtbl_decl_for_binfo (tree binfo)                                                           in class.c

6448   {

6449     tree decl;

6450  

6451     decl = BINFO_VTABLE (binfo);

6452     if (decl && TREE_CODE (decl) == PLUS_EXPR)

6453     {

6454       my_friendly_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR,

6455                        2000403);

6456       decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);

6457     }

6458     if (decl)

6459       my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20000403);

6460     return decl;

6461   }

 

Now back to dfs_modify_vtables , pay attention to virtuals and orig_virtuals ; virtuals comes from binfo in current class hierarhcy tree, while orig_virtuals comes from binfo in the type of the base. They are different now, as corresponding BINFO_VIRTUALS has been copied above.

Then for every virtual function that defined in the type, necessary thunks and adjustments they carry would be worked out and recorded in update_vtable_entry_for_fn .

 

2071   static void

2072   update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,            in class.c

2073                           unsigned ix)

2074   {

2075     tree b;

2076     tree overrider;

2077     tree delta;

2078     tree virtual_base;

2079     tree first_defn;

2080     tree overrider_fn, overrider_target;

2081     tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn;

2082     tree over_return, base_return;

2083     bool lost = false;

2084  

2085     /* Find the nearest primary base (possibly binfo itself) which defines

2086       this function; this is the class the caller will convert to when

2087       calling FN through BINFO.  */

2088     for (b = binfo; ; b = get_primary_binfo (b))

2089     {

2090       my_friendly_assert (b, 20021227);

2091       if (look_for_overrides_here (BINFO_TYPE (b), target_fn))

2092         break ;

2093  

2094        /* The nearest definition is from a lost primary.  */

2095       if (BINFO_LOST_PRIMARY_P (b))

2096         lost = true;

2097     }

2098     first_defn = b;

2099  

2100     /* Find the final overrider.  */

2101     overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn);

2102     if (overrider == error_mark_node)

2103     {

2104       error ("no unique final overrider for `%D' in `%T'", target_fn, t);

2105       return ;

2106     }

2107     overrider_target = overrider_fn = TREE_PURPOSE (overrider);

 

As dfs_modify_vtables is used as postfn of dfs_walk_real , it handles the bases from bottom up in the hierarhcy tree with the non-derived base first. This order is important for virtual primary base (but not required by non-vitural primary base, as every derived class own its copy of base’s info).

So for class C, dfs_modify_vtables first processes binfo of A in C. In FOR loop at line 2088 above, for specified function (i.e, B1::f with thunk), it steps down the primary bases chain of the specified base, and selects out the nearest primary base that defines the function. For B1::f with thunk in our example, b found out is B1, and lost is false.

When invoking find_final_overrider , note that if the function being processed is a thunk, the real function should be retrieved and referred by fn below. Here fn holds B1::f for A in C.

 

1194   static tree

1195   find_final_overrider (tree derived, tree binfo, tree fn)                                          in class.c

1196   {

1197     find_final_overrider_data ffod;

1198     count_depth_data cd;

1199  

1200     /* Getting this right is a little tricky. This is valid:

1201  

1202        struct S { virtual void f (); };

1203        struct T { virtual void f (); };

1204        struct U : public S, public T { };

1205  

1206       even though calling `f' in `U' is ambiguous. But,

1207  

1208        struct R { virtual void f(); };

1209         struct S : virtual public R { virtual void f (); };

1210        struct T : virtual public R { virtual void f (); };

1211        struct U : public S, public T { };

1212  

1213       is not -- there's no way to decide whether to put `S::f' or

1214       `T::f' in the vtable for `R'. 

1215       

1216       The solution is to look at all paths to BINFO. If we find

1217       different overriders along any two, then there is a problem.  */

1218     if (DECL_THUNK_P (fn))

1219       fn = THUNK_TARGET (fn);

1220  

1221     /* Determine the depth of the hierarchy.  */

1222     cd.depth = 0;

1223     cd.max_depth = 0;

1224     dfs_walk (derived, dfs_depth_post , dfs_depth_q , &cd);

1225  

1226     ffod.fn = fn;

1227     ffod.declaring_base = binfo;

1228     ffod.most_derived_type = BINFO_TYPE (derived);

1229     ffod.candidates = NULL_TREE;

1230     ffod.vpath_list = (tree *) xcalloc (cd.max_depth, sizeof (tree));

1231     ffod.vpath = ffod.vpath_list;

1232  

1233     dfs_walk_real (derived,

1234                 dfs_find_final_overrider ,

1235                  dfs_find_final_overrider_post ,

1236                  dfs_find_final_overrider_q ,

1237                 &ffod);

1238  

1239     free (ffod.vpath_list);

1240  

1241     /* If there was no winner, issue an error message.  */

1242     if (!ffod.candidates || TREE_CHAIN (ffod.candidates))

1243       return error_mark_node;

1244  

1245     return ffod.candidates;

1246   }

 

Variable cd of type count_depth_data having following definition is used in the traversal of the hierachy tree.

 

1856   typedef struct count_depth_data {                                                             in class.c

1857     /* The depth of the current subobject, with "1" as the depth of the

1858       most derived object in the hierarchy.  */

1859     size_t depth;

1860     /* The maximum depth found so far.  */

1861     size_t max_depth;

1862   } count_depth_data ;

 

Routine dfs_depth_q used as argument of qfn in dfs_walk_real , is executed top down and counts the level of derivation of the class (argument derived of find_final_overrider is current class type here, i.e. C).

 

1886   static tree

1887   dfs_depth_q (tree derived, int i, void *data)                                                in class.c

1888   {

1889     count_depth_data *cd = (count_depth_data *) data;

1890     cd->depth++;

1891     return BINFO_BASETYPE (derived, i);

1892   }

 

While dfs_depth_post used as argument of postfn in dfs_walk_real , is executed buttom up towards the most derived class. It finds the max level of derivation among the record made during visiting the tree down from the most derived class.

 

1886   static tree

1887   dfs_depth_post (tree binfo ATTRIBUTE_UNUSED, void *data)                   in class.c

1888   {

1889     count_depth_data *cd = (count_depth_data *) data;

1890     if (cd->depth > cd->max_depth)

1891       cd->max_depth = cd->depth;

1892     cd->depth--;

1893     return NULL_TREE;

1894   }

 

See at line 1230, this max_depth slot of cd is used as the dimension of vpath_list in ffod which is of type find_final_overrider_data below.

 

1893   typedef struct find_final_overrider_data_s {                                                in class.c

1894     /* The function for which we are trying to find a final overrider.  */

1895     tree fn;

1896     /* The base class in which the function was declared.  */

1897     tree declaring_base;

1898     /* The most derived class in the hierarchy.  */

1899     tree most_derived_type;

1900     /* The candidate overriders.   */

1901     tree candidates;

1902     /* Each entry in this array is the next-most-derived class for a

1903       virtual base class along the current path.  */

1904     tree *vpath_list;

1905     /* A pointer one past the top of the VPATH_LIST.  */

1906     tree *vpath;

1907   } find_final_overrider_data ;

 

In inner traversal, dfs_find_final_overrider is used as prefn in dfs_walk_real , which will be executed in pre-order and drop out the walk if it return nonzero value. Notice that the argument binfo is the variable derived in find_final_overrider , and original declaring_base slot of ffod passed as data is the binfo of the base visited by dfs_modify_vtables in post-order now, and most_derived_type slot refers to the most derived type (current class type).

 

1955   static tree

1956   dfs_find_final_overrider (tree binfo, void* data)                                         in class.c

1957   {

1958     find_final_overrider_data *ffod = (find_final_overrider_data *) data;

1959  

1960     if (binfo == ffod->declaring_base)

1961       dfs_find_final_overrider_1 (binfo, ffod->vpath, ffod);

1962  

1963     return NULL_TREE;

1964   }

 

Notice that dfs_find_final_overrider is executed in pre-order in the inner walk, while dfs_modify_vtables is executed in post-order in the outer walk, and binfo is of base being visited by the inner walk, and data records the snapshot of outer walk at point of running the inner walk. So dfs_find_final_overrider_1 is executed when inner pre-order walk finally arrives at the point it was triggered.

But before condition at line 1960 finally is met, dfs_find_final_overrider_q is executed for every base stepping into.

 

1966   static tree

1967   dfs_find_final_overrider_q (tree derived, int ix, void *data)                          in class.c

1968   {

1969     tree binfo = BINFO_BASETYPE (derived, ix);

1970     find_final_overrider_data *ffod = (find_final_overrider_data *) data;

1971  

1972     if (TREE_VIA_VIRTUAL (binfo))

1973       *ffod->vpath++ = derived;

1974    

1975     return binfo;

1976   }

 

As we expecting, the virutal base being probed is recorded as their appearing order within vpath of ffod . So when leaving the base, it should be removed by dfs_find_final_overrider_post .

 

1978   static tree

1979   dfs_find_final_overrider_post (tree binfo, void *data)                                  in class.c

1980   {

1981     find_final_overrider_data *ffod = (find_final_overrider_data *) data;

1982  

1983     if (TREE_VIA_VIRTUAL (binfo))

1984       ffod->vpath--;

1985    

1986     return NULL_TREE;

1987   }

 

In dfs_find_final_overrider_1, argument binfo is the base we are visiting in this inner walk, and declaring_base of ffod is the binfo we are visiting in the outer walk, in which we are determining the right override of the virutal fucntion specified by fn slot of ffod . And binfo and declaring_base are the same now.

 

1905   static bool

1906   dfs_find_final_overrider_1 (tree binfo,                                                       in class.c

1907                           tree *vpath,

1908                            find_final_overrider_data *ffod)

1909   {

1910     tree method;

1911         

1912     /* If BINFO is not the most derived type, try a more derived class.

1913       A definition there will overrider a definition here.  */

1914     if (!same_type_p (BINFO_TYPE (binfo), ffod->most_derived_type))

1915     {

1916       tree derived;

1917  

1918       if (TREE_VIA_VIRTUAL (binfo))

1919         derived = *--vpath;

1920       else

1921         derived = BINFO_INHERITANCE_CHAIN (binfo);

1922       if (dfs_find_final_overrider_1 (derived, vpath, ffod))

1923         return true;

1924     }

1925  

1926     method = look_for_overrides_here (BINFO_TYPE (binfo), ffod->fn);

1927     if (method)

1928     {

1929       tree *candidate = &ffod->candidates;

1930        

1931       /* Remove any candidates overridden by this new function.  */

1932       while (*candidate)

1933       {

1934          /* If *CANDIDATE overrides METHOD, then METHOD

1935            cannot override anything else on the list.  */

1936          if (base_derived_from (TREE_VALUE (*candidate), binfo))

1937            return true;

1938          /* If METHOD overrides *CANDIDATE, remove *CANDIDATE.  */

1939          if (base_derived_from (binfo, TREE_VALUE (*candidate)))

1940            *candidate = TREE_CHAIN (*candidate);

1941          else

1942            candidate = &TREE_CHAIN (*candidate);

1943       }

1944         

1945        /* Add the new function.  */

1946       ffod->candidates = tree_cons (method, binfo, ffod->candidates);

1947       return true;

1948     }

1949  

1950     return false;

1951   }

 

Pay attention to the recursion at line 1922 above, the routine gives the most derived class the priority over bases. So it can search out the most derived base that last overrides the function with the help of base_derived_from to determine from which it derives.

 

1836   static bool

1837   base_derived_from (tree derived, tree base)                                               in class.c

1838   {

1839     tree probe;

1840  

1841     for (probe = base; probe; probe = BINFO_INHERITANCE_CHAIN (probe))

1842     {

1843       if (probe == derived)

1844         return true;

1845       else if (TREE_VIA_VIRTUAL (probe))

1846         /* If we meet a virtual base, we can't follow the inheritance

1847            any more. See if the complete type of DERIVED contains

1848            such a virtual base.  */

1849         return purpose_member (BINFO_TYPE (probe),

1850                            CLASSTYPE_VBASECLASSES (BINFO_TYPE (derived)))

1851                              != NULL_TREE;

1852     }

1853     return false;

1854   }

 

This specified virtual function of most derived base is assigned to overrider_target below. For our example of B::f with thunk of A, overrider_target gets C::f. Now for the example, we get, target_fn : B* B::f(), and overrider_target : C* C::f(). Remember this B::f in A has a result-adjutment thunk with virutal-offset: A in B1, fix-offset: 0 (A -> B1).

See if the thunk contains virtual-offset, it should get it from the hierarchy class tree rooted by over_return at line 2140. So we can get the correct virtual offset.

 

update_vtable_entry_for_fn (continue)

 

2109     /* Check for adjusting covariant return types.  */

2110     over_return = TREE_TYPE (TREE_TYPE (overrider_target));

2111     base_return = TREE_TYPE (TREE_TYPE (target_fn));

2112    

2113     if (POINTER_TYPE_P (over_return)

2114        && TREE_CODE (over_return) == TREE_CODE (base_return)

2115        && CLASS_TYPE_P (TREE_TYPE (over_return))

2116        && CLASS_TYPE_P (TREE_TYPE (base_return)))

2117     {

2118       /* If FN is a covariant thunk, we must figure out the adjustment

2119         to the final base FN was converting to. As OVERRIDER_TARGET might

2120         also be converting to the return type of FN, we have to

2121         combine the two conversions here.  */

2122       tree fixed_offset, virtual_offset;

2123  

2124       over_return = TREE_TYPE (over_return);

2125       base_return = TREE_TYPE (base_return);

2126        

2127       if (DECL_THUNK_P (fn))

2128       {

2129          my_friendly_assert (DECL_RESULT_THUNK_P (fn), 20031211);

2130          fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));

2131          virtual_offset = THUNK_VIRTUAL_OFFSET (fn);

2132       }

2133       else

2134         fixed_offset = virtual_offset = NULL_TREE;

2135  

2136       if (virtual_offset)

2137         /* Find the equivalent binfo within the return type of the

2138            overriding function. We will want the vbase offset from

2139            there.  */

2140         virtual_offset =

2141             TREE_VALUE (purpose_member

2142                            (BINFO_TYPE (virtual_offset),

2143                            CLASSTYPE_VBASECLASSES (over_return)));

2144       else if (!same_type_ignoring_top_level_qualifiers_p

2145                   (over_return, base_return))

2146       {

2147          /* There was no existing virtual thunk (which takes

2148            precedence). So find the binfo of the base function's

2149            return type within the overriding function's return type.

2150            We cannot call lookup base here, because we're inside a

2151            dfs_walk, and will therefore clobber the BINFO_MARKED

2152            flags. Fortunately we know the covariancy is valid (it

2153            has already been checked), so we can just iterate along

2154            the binfos, which have been chained in inheritance graph

2155            order. Of course it is lame that we have to repeat the

2156            search here anyway -- we should really be caching pieces

2157            of the vtable and avoiding this repeated work.  */

2158          tree thunk_binfo, base_binfo;

2159  

2160          /* Find the base binfo within the overriding function's

2161            return type. We will always find a thunk_binfo, except

2162            when the covariancy is invalid (which we will have

2163            already diagnosed).  */

2164          for (base_binfo = TYPE_BINFO (base_return),

2165              thunk_binfo = TYPE_BINFO (over_return);

2166              thunk_binfo;

2167              thunk_binfo = TREE_CHAIN (thunk_binfo))

2168            if (same_type_p (BINFO_TYPE (thunk_binfo),

2169                           BINFO_TYPE (base_binfo)))

2170              break ;

2171         

2172           /* See if virtual inheritance is involved.  */

2173          for (virtual_offset = thunk_binfo;

2174              virtual_offset;

2175              virtual_offset = BINFO_INHERITANCE_CHAIN (virtual_offset))

2176            if (TREE_VIA_VIRTUAL (virtual_offset))

2177              break ;

2178         

2179          if (virtual_offset

2180             || (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))

2181          {

2182             tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));

2183  

2184            if (virtual_offset)

2185           {

2186              /* We convert via virtual base. Adjust the fixed

2187                offset to be from there.  */

2188              offset = size_diffop

2189                        (offset, convert

2190                                  (ssizetype, BINFO_OFFSET (virtual_offset)));

2191           }

2192             if (fixed_offset)

2193             /* There was an existing fixed offset, this must be

2194                   from the base just converted to, and the base the

2195                  FN was thunking to.  */

2196             fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset);

2197            else

2198             fixed_offset = offset;

2199            }

2200       }

2201        

2202       if (fixed_offset || virtual_offset)

2203         /* Replace the overriding function with a covariant thunk. We

2204            will emit the overriding function in its own slot as

2205            well.  */

2206         overrider_fn = make_thunk (overrider_target, /*this_adjusting=*/ 0,

2207                                 fixed_offset, virtual_offset);

2208     }

2209     else

2210       my_friendly_assert (!DECL_THUNK_P (fn), 20021231);

你可能感兴趣的:(function,struct,tree,Class,Build,inheritance)