FreeBSD/contrib/gcc/cp/class.c
/* Update an entry in the vtable for BINFO, which is in the hierarchy
   dominated by T.  FN has been overridden in BINFO; VIRTUALS points to the
   corresponding position in the BINFO_VIRTUALS list.  */
Update an entry in the vtable for BINFO, which is in the hierarchy
dominated by T.  FN has been overridden in BINFO; VIRTUALS points to the
corresponding position in the BINFO_VIRTUALS list.
Update an entry in the vtable for BINFO which is in the hierarchy dominated by T . FN has been overridden in BINFO ; VIRTUALS points to the corresponding position in the BINFO_VIRTUALS list .
static void
update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
			    unsigned ix)
{
  tree b;
  tree overrider;
  tree delta;
  tree virtual_base;
  tree first_defn;
  tree overrider_fn, overrider_target;
  tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn;
  tree over_return, base_return;
  bool lost = false;
  for (b = binfo; ; b = get_primary_binfo (b))
    {
      gcc_assert (b);
      if (look_for_overrides_here (BINFO_TYPE (b), target_fn))
	break;
      if (BINFO_LOST_PRIMARY_P (b))
	lost = true;
    }
  first_defn = b;
  overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn);
  if (overrider == error_mark_node)
    {
      error ("no unique final overrider for %qD in %qT", target_fn, t);
      return;
    }
  overrider_target = overrider_fn = TREE_PURPOSE (overrider);
  over_return = TREE_TYPE (TREE_TYPE (overrider_target));
  base_return = TREE_TYPE (TREE_TYPE (target_fn));
  if (POINTER_TYPE_P (over_return)
      && TREE_CODE (over_return) == TREE_CODE (base_return)
      && CLASS_TYPE_P (TREE_TYPE (over_return))
      && CLASS_TYPE_P (TREE_TYPE (base_return))
      && !DECL_INVALID_OVERRIDER_P (overrider_target))
    {
      tree fixed_offset, virtual_offset;
      over_return = TREE_TYPE (over_return);
      base_return = TREE_TYPE (base_return);
      if (DECL_THUNK_P (fn))
	{
	  gcc_assert (DECL_RESULT_THUNK_P (fn));
	  fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
	  virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
	}
      else
	fixed_offset = virtual_offset = NULL_TREE;
      if (virtual_offset)
	virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset),
					  over_return);
      else if (!same_type_ignoring_top_level_qualifiers_p
	       (over_return, base_return))
	{
	  tree thunk_binfo, base_binfo;
	  for (base_binfo = TYPE_BINFO (base_return),
	       thunk_binfo = TYPE_BINFO (over_return);
	       thunk_binfo;
	       thunk_binfo = TREE_CHAIN (thunk_binfo))
	    if (SAME_BINFO_TYPE_P (BINFO_TYPE (thunk_binfo),
				   BINFO_TYPE (base_binfo)))
	      break;
	  for (virtual_offset = thunk_binfo;
	       virtual_offset;
	       virtual_offset = BINFO_INHERITANCE_CHAIN (virtual_offset))
	    if (BINFO_VIRTUAL_P (virtual_offset))
	      break;
	  if (virtual_offset
	      || (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))
	    {
	      tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));
	      if (virtual_offset)
		{
		  offset = size_diffop
		    (offset, convert
		     (ssizetype, BINFO_OFFSET (virtual_offset)));
		}
	      if (fixed_offset)
		fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset);
	      else
		fixed_offset = offset;
	    }
	}
      if (fixed_offset || virtual_offset)
	overrider_fn = make_thunk (overrider_target, 0,
				   fixed_offset, virtual_offset);
    }
  else
    gcc_assert (!DECL_THUNK_P (fn));
  virtual_base = NULL_TREE;
  for (; b; b = BINFO_INHERITANCE_CHAIN (b))
    {
      if (SAME_BINFO_TYPE_P (BINFO_TYPE (b),
			     BINFO_TYPE (TREE_VALUE (overrider))))
	break;
      if (BINFO_VIRTUAL_P (b))
	{
	  virtual_base = b;
	  break;
	}
    }
  if (overrider_fn != overrider_target && !virtual_base)
    {
      tree probe = first_defn;
      while ((probe = get_primary_binfo (probe))
	     && (unsigned) list_length (BINFO_VIRTUALS (probe)) > ix)
	if (BINFO_VIRTUAL_P (probe))
	  virtual_base = probe;
      if (virtual_base)
	goto virtual_covariant;
    }
  if (virtual_base)
    delta = size_diffop (convert (ssizetype, BINFO_OFFSET (virtual_base)),
			 convert (ssizetype, BINFO_OFFSET (first_defn)));
  else if (lost)
    delta = size_zero_node;
  else
    virtual_covariant:
    delta = size_diffop (convert (ssizetype,
				  BINFO_OFFSET (TREE_VALUE (overrider))),
			 convert (ssizetype, BINFO_OFFSET (binfo)));
  modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
  if (virtual_base)
    BV_VCALL_INDEX (*virtuals)
      = get_vcall_index (overrider_target, BINFO_TYPE (virtual_base));
  else
    BV_VCALL_INDEX (*virtuals) = NULL_TREE;
}
static void update_vtable_entry_for_fn ( tree t , tree binfo , tree fn , tree * virtuals , unsigned ix ) { tree b ; tree overrider ; tree delta ; tree virtual_base ; tree first_defn ; tree overrider_fn , overrider_target ; tree target_fn = DECL_THUNK_P ( fn ) ? THUNK_TARGET ( fn ) : fn ; tree over_return , base_return ; bool lost = false ; for ( b = binfo ; ; b = get_primary_binfo ( b ) ) { gcc_assert ( b ) ; if ( look_for_overrides_here ( BINFO_TYPE ( b ) , target_fn ) ) break ; if ( BINFO_LOST_PRIMARY_P ( b ) ) lost = true ; } first_defn = b ; overrider = find_final_overrider ( TYPE_BINFO ( t ) , b , target_fn ) ; if ( overrider == error_mark_node ) { error ( " " , target_fn , t ) ; return ; } overrider_target = overrider_fn = TREE_PURPOSE ( overrider ) ; over_return = TREE_TYPE ( TREE_TYPE ( overrider_target ) ) ; base_return = TREE_TYPE ( TREE_TYPE ( target_fn ) ) ; if ( POINTER_TYPE_P ( over_return ) && TREE_CODE ( over_return ) == TREE_CODE ( base_return ) && CLASS_TYPE_P ( TREE_TYPE ( over_return ) ) && CLASS_TYPE_P ( TREE_TYPE ( base_return ) ) && ! DECL_INVALID_OVERRIDER_P ( overrider_target ) ) { tree fixed_offset , virtual_offset ; over_return = TREE_TYPE ( over_return ) ; base_return = TREE_TYPE ( base_return ) ; if ( DECL_THUNK_P ( fn ) ) { gcc_assert ( DECL_RESULT_THUNK_P ( fn ) ) ; fixed_offset = ssize_int ( THUNK_FIXED_OFFSET ( fn ) ) ; virtual_offset = THUNK_VIRTUAL_OFFSET ( fn ) ; } else fixed_offset = virtual_offset = NULL_TREE ; if ( virtual_offset ) virtual_offset = binfo_for_vbase ( BINFO_TYPE ( virtual_offset ) , over_return ) ; else if ( ! same_type_ignoring_top_level_qualifiers_p ( over_return , base_return ) ) { tree thunk_binfo , base_binfo ; for ( base_binfo = TYPE_BINFO ( base_return ) , thunk_binfo = TYPE_BINFO ( over_return ) ; thunk_binfo ; thunk_binfo = TREE_CHAIN ( thunk_binfo ) ) if ( SAME_BINFO_TYPE_P ( BINFO_TYPE ( thunk_binfo ) , BINFO_TYPE ( base_binfo ) ) ) break ; for ( virtual_offset = thunk_binfo ; virtual_offset ; virtual_offset = BINFO_INHERITANCE_CHAIN ( virtual_offset ) ) if ( BINFO_VIRTUAL_P ( virtual_offset ) ) break ; if ( virtual_offset || ( thunk_binfo && ! BINFO_OFFSET_ZEROP ( thunk_binfo ) ) ) { tree offset = convert ( ssizetype , BINFO_OFFSET ( thunk_binfo ) ) ; if ( virtual_offset ) { offset = size_diffop ( offset , convert ( ssizetype , BINFO_OFFSET ( virtual_offset ) ) ) ; } if ( fixed_offset ) fixed_offset = size_binop ( PLUS_EXPR , fixed_offset , offset ) ; else fixed_offset = offset ; } } if ( fixed_offset || virtual_offset ) overrider_fn = make_thunk ( overrider_target , 0 , fixed_offset , virtual_offset ) ; } else gcc_assert ( ! DECL_THUNK_P ( fn ) ) ; virtual_base = NULL_TREE ; for ( ; b ; b = BINFO_INHERITANCE_CHAIN ( b ) ) { if ( SAME_BINFO_TYPE_P ( BINFO_TYPE ( b ) , BINFO_TYPE ( TREE_VALUE ( overrider ) ) ) ) break ; if ( BINFO_VIRTUAL_P ( b ) ) { virtual_base = b ; break ; } } if ( overrider_fn != overrider_target && ! virtual_base ) { tree probe = first_defn ; while ( ( probe = get_primary_binfo ( probe ) ) && ( unsigned ) list_length ( BINFO_VIRTUALS ( probe ) ) > ix ) if ( BINFO_VIRTUAL_P ( probe ) ) virtual_base = probe ; if ( virtual_base ) goto virtual_covariant ; } if ( virtual_base ) delta = size_diffop ( convert ( ssizetype , BINFO_OFFSET ( virtual_base ) ) , convert ( ssizetype , BINFO_OFFSET ( first_defn ) ) ) ; else if ( lost ) delta = size_zero_node ; else virtual_covariant : delta = size_diffop ( convert ( ssizetype , BINFO_OFFSET ( TREE_VALUE ( overrider ) ) ) , convert ( ssizetype , BINFO_OFFSET ( binfo ) ) ) ; modify_vtable_entry ( t , binfo , overrider_fn , delta , virtuals ) ; if ( virtual_base ) BV_VCALL_INDEX ( * virtuals ) = get_vcall_index ( overrider_target , BINFO_TYPE ( virtual_base ) ) ; else BV_VCALL_INDEX ( * virtuals ) = NULL_TREE ; }
Update an entry in the vtable for BINFO, which is in the hierarchy
dominated by T.  FN has been overridden in BINFO; VIRTUALS points to the
corresponding position in the BINFO_VIRTUALS list.
Update an entry in the vtable for BINFO which is in the hierarchy dominated by T . FN has been overridden in BINFO ; VIRTUALS points to the corresponding position in the BINFO_VIRTUALS list .
/* Find the nearest primary base (possibly binfo itself) which defines
     this function; this is the class the caller will convert to when
     calling FN through BINFO.  */ /* The nearest definition is from a lost primary.  */ /* Find the final overrider.  */ /* Check for adjusting covariant return types.  */ /* If the overrider is invalid, don't even try.  */ /* If FN is a covariant thunk, we must figure out the adjustment
	 to the final base FN was converting to. As OVERRIDER_TARGET might
	 also be converting to the return type of FN, we have to
	 combine the two conversions here.  */ /* Find the equivalent binfo within the return type of the
	   overriding function. We will want the vbase offset from
	   there.  */ /* There was no existing virtual thunk (which takes
	     precedence).  So find the binfo of the base function's
	     return type within the overriding function's return type.
	     We cannot call lookup base here, because we're inside a
	     dfs_walk, and will therefore clobber the BINFO_MARKED
	     flags.  Fortunately we know the covariancy is valid (it
	     has already been checked), so we can just iterate along
	     the binfos, which have been chained in inheritance graph
	     order.  Of course it is lame that we have to repeat the
	     search here anyway -- we should really be caching pieces
	     of the vtable and avoiding this repeated work.  */ /* Find the base binfo within the overriding function's
	     return type.  We will always find a thunk_binfo, except
	     when the covariancy is invalid (which we will have
	     already diagnosed).  */ /* See if virtual inheritance is involved.  */ /* We convert via virtual base.  Adjust the fixed
		     offset to be from there.  */ /* There was an existing fixed offset, this must be
		   from the base just converted to, and the base the
		   FN was thunking to.  */ /* Replace the overriding function with a covariant thunk.  We
	   will emit the overriding function in its own slot as
	   well.  */ /*this_adjusting=*/ /* Assume that we will produce a thunk that convert all the way to
     the final overrider, and not to an intermediate virtual base.  */ /* See if we can convert to an intermediate virtual base first, and then
     use the vcall offset located there to finish the conversion.  */ /* If we find the final overrider, then we can stop
	 walking.  */ /* If we find a virtual base, and we haven't yet found the
	 overrider, then there is a virtual base between the
	 declaring base (first_defn) and the final overrider.  */ /* The ABI specifies that a covariant thunk includes a mangling
	 for a this pointer adjustment.  This-adjusting thunks that
	 override a function from a virtual base have a vcall
	 adjustment.  When the virtual base in question is a primary
	 virtual base, we know the adjustments are zero, (and in the
	 non-covariant case, we would not use the thunk).
	 Unfortunately we didn't notice this could happen, when
	 designing the ABI and so never mandated that such a covariant
	 thunk should be emitted.  Because we must use the ABI mandated
	 name, we must continue searching from the binfo where we
	 found the most recent definition of the function, towards the
	 primary binfo which first introduced the function into the
	 vtable.  If that enters a virtual base, we must use a vcall
	 this-adjusting thunk.  Bleah! */ /* Even if we find a virtual base, the correct delta is
	   between the overrider and the binfo we're building a vtable
	   for.  */ /* Compute the constant adjustment to the `this' pointer.  The
     `this' pointer, when this function is called, will point at BINFO
     (or one of its primary bases, which are at the same offset).  */ /* The `this' pointer needs to be adjusted from the declaration to
       the nearest virtual base.  */ /* If the nearest definition is in a lost primary, we don't need an
       entry in our vtable.  Except possibly in a constructor vtable,
       if we happen to get our primary back.  In that case, the offset
       will be zero, as it will be a primary base.  */ /* The `this' pointer needs to be adjusted from pointing to
       BINFO to pointing at the base where the final overrider
       appears.  */