This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH]:Fix 13118


Hi,
I've installed this patch to fix 13118, a missing covariant thunk. When
overriding a virtual covaraint thunk, we need to find the equivalent virtual
base within the return type of the overriding function. Unfortunately
I was overloading the VIRTUAL_OFFSET slot with the THUNK_ALIAS slot, but
this patch requires both to be present.  Luckily I found another spare slot.

This also simplifies the complexity I just added when fixing 12881. Ho hum.

booted & tested on i686-pc-linux-gnu.

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
         The voices in my head said this was stupid too
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

2003-12-12  Nathan Sidwell  <nathan@codesourcery.com>

	PR c++/13118
	* cp-tree.h (lang_decl_u): Add thunk_alias member.
	(THUNK_VIRTUAL_OFFSET): Must be a FUNCTION_DECL.
	(THUNK_ALIAS_P): Remove.
	(THUNK_ALIAS): Adjust.
	* class.c (update_vtable_entry_for_fn): Get the vbase within the
	overriding function's return type.
	(dump_thunk): Adjust THUNK_ALIAS printing.
	(build_vtbl_initializer): Adjust THUNK_ALIAS use.
	* method.c (make_thunk): Revert 12881 test change. Clear
	THUNK_ALIAS.
	(finish_thunk): Adjust THUNK_ALIAS setting.
	(use_thunk): Adjust THUNK_ALIAS use.
	* semantics.c (emit_associated_thunks): Likewise.

Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.585
diff -c -3 -p -r1.585 class.c
*** cp/class.c	12 Dec 2003 14:48:30 -0000	1.585
--- cp/class.c	12 Dec 2003 16:50:14 -0000
*************** update_vtable_entry_for_fn (tree t, tree
*** 2168,2180 ****
        
        if (DECL_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)
  	{
  	  /* There was no existing virtual thunk (which takes
  	     precedence).  */
--- 2168,2189 ----
        
        if (DECL_THUNK_P (fn))
  	{
+ 	  my_friendly_assert (DECL_RESULT_THUNK_P (fn), 20031211);
  	  fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
  	  virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
  	}
        else
  	fixed_offset = virtual_offset = NULL_TREE;
  
!       if (virtual_offset)
! 	/* Find the equivalent binfo within the return type of the
! 	   overriding function. We will want the vbase offset from
! 	   there.  */
! 	virtual_offset =
! 	  TREE_VALUE (purpose_member
! 		      (BINFO_TYPE (virtual_offset),
! 		       CLASSTYPE_VBASECLASSES (TREE_TYPE (over_return))));
!       else
  	{
  	  /* There was no existing virtual thunk (which takes
  	     precedence).  */
*************** dump_thunk (FILE *stream, int indent, tr
*** 6715,6725 ****
  	   !DECL_THUNK_P (thunk) ? "function"
  	   : DECL_THIS_THUNK_P (thunk) ? "this-thunk" : "covariant-thunk",
  	   name ? IDENTIFIER_POINTER (name) : "<unset>");
!   if (!DECL_THUNK_P (thunk))
!     /*NOP*/;
!   else if (THUNK_ALIAS_P (thunk))
!     fprintf (stream, " alias to %p", (void *)THUNK_ALIAS (thunk));
!   else
      {
        HOST_WIDE_INT fixed_adjust = THUNK_FIXED_OFFSET (thunk);
        tree virtual_adjust = THUNK_VIRTUAL_OFFSET (thunk);
--- 6724,6730 ----
  	   !DECL_THUNK_P (thunk) ? "function"
  	   : DECL_THIS_THUNK_P (thunk) ? "this-thunk" : "covariant-thunk",
  	   name ? IDENTIFIER_POINTER (name) : "<unset>");
!   if (DECL_THUNK_P (thunk))
      {
        HOST_WIDE_INT fixed_adjust = THUNK_FIXED_OFFSET (thunk);
        tree virtual_adjust = THUNK_VIRTUAL_OFFSET (thunk);
*************** dump_thunk (FILE *stream, int indent, tr
*** 6734,6739 ****
--- 6739,6746 ----
  	fprintf (stream, " vbase=" HOST_WIDE_INT_PRINT_DEC "(%s)",
  		 tree_low_cst (BINFO_VPTR_FIELD (virtual_adjust), 0),
  		 type_as_string (BINFO_TYPE (virtual_adjust), TFF_SCOPE));
+       if (THUNK_ALIAS (thunk))
+ 	fprintf (stream, " alias to %p", (void *)THUNK_ALIAS (thunk));
      }
    fprintf (stream, "\n");
    for (thunks = DECL_THUNKS (thunk); thunks; thunks = TREE_CHAIN (thunks))
*************** build_vtbl_initializer (tree binfo,
*** 7406,7412 ****
  	{
  	  if (!DECL_NAME (fn))
  	    finish_thunk (fn);
! 	  if (THUNK_ALIAS_P (fn))
  	    {
  	      fn = THUNK_ALIAS (fn);
  	      BV_FN (v) = fn;
--- 7413,7419 ----
  	{
  	  if (!DECL_NAME (fn))
  	    finish_thunk (fn);
! 	  if (THUNK_ALIAS (fn))
  	    {
  	      fn = THUNK_ALIAS (fn);
  	      BV_FN (v) = fn;
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.938
diff -c -3 -p -r1.938 cp-tree.h
*** cp/cp-tree.h	10 Dec 2003 14:06:21 -0000	1.938
--- cp/cp-tree.h	12 Dec 2003 16:50:27 -0000
*************** struct lang_decl_flags GTY(())
*** 1634,1645 ****
    unsigned this_thunk_p : 1;
  
    union lang_decl_u {
!     /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
!        is DECL_TEMPLATE_INFO.  */
      tree GTY ((tag ("0"))) template_info;
  
      /* In a NAMESPACE_DECL, this is NAMESPACE_LEVEL.  */
      struct cp_binding_level * GTY ((tag ("1"))) level;
    } GTY ((desc ("%1.u1sel"))) u;
  
    union lang_decl_u2 {
--- 1634,1650 ----
    unsigned this_thunk_p : 1;
  
    union lang_decl_u {
!     /* In a FUNCTION_DECL for which DECL_THUNK_P does not hold,
!        VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this is
!        DECL_TEMPLATE_INFO.  */
      tree GTY ((tag ("0"))) template_info;
  
      /* In a NAMESPACE_DECL, this is NAMESPACE_LEVEL.  */
      struct cp_binding_level * GTY ((tag ("1"))) level;
+ 
+     /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
+        THUNK_ALIAS.  */
+     tree GTY ((tag ("2"))) thunk_alias;
    } GTY ((desc ("%1.u1sel"))) u;
  
    union lang_decl_u2 {
*************** struct lang_decl GTY(())
*** 2859,2870 ****
     for the result pointer adjustment.
  
     The constant adjustment is given by THUNK_FIXED_OFFSET.  If the
!    vcall or vbase offset is required, the index into the vtable is given by
!    THUNK_VIRTUAL_OFFSET.
! 
!    Due to ordering constraints in class layout, it is possible to have
!    equivalent covariant thunks. THUNK_ALIAS_P and THUNK_ALIAS are used
!    in those cases.  */
  
  /* An integer indicating how many bytes should be subtracted from the
     this or result pointer when this function is called.  */
--- 2864,2880 ----
     for the result pointer adjustment.
  
     The constant adjustment is given by THUNK_FIXED_OFFSET.  If the
!    vcall or vbase offset is required, THUNK_VIRTUAL_OFFSET is
!    used. For this pointer adjusting thunks, it is the vcall offset
!    into the vtable.  For result pointer adjusting thunks it is the
!    binfo of the virtual base to convert to.  Use that binfo's vbase
!    offset.
! 
!    It is possible to have equivalent covariant thunks.  These are
!    distinct virtual covariant thunks whose vbase offsets happen to
!    have the same value.  THUNK_ALIAS is used to pick one as the
!    canonical thunk, which will get all the this pointer adjusting
!    thunks attached to it.  */
  
  /* An integer indicating how many bytes should be subtracted from the
     this or result pointer when this function is called.  */
*************** struct lang_decl GTY(())
*** 2882,2896 ****
     binfos.)  */
  
  #define THUNK_VIRTUAL_OFFSET(DECL) \
!   (LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
  
  /* A thunk which is equivalent to another thunk. */
! #define THUNK_ALIAS_P(DECL) \
!   (THUNK_VIRTUAL_OFFSET (DECL) && DECL_P (THUNK_VIRTUAL_OFFSET (DECL)))
! 
! /* When THUNK_ALIAS_P is true, this indicates the thunk which is
!    aliased.  */
! #define THUNK_ALIAS(DECL) THUNK_VIRTUAL_OFFSET (DECL)
  
  /* For thunk NODE, this is the FUNCTION_DECL thunked to.  */
  #define THUNK_TARGET(NODE)				\
--- 2892,2902 ----
     binfos.)  */
  
  #define THUNK_VIRTUAL_OFFSET(DECL) \
!   (LANG_DECL_U2_CHECK (FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
  
  /* A thunk which is equivalent to another thunk. */
! #define THUNK_ALIAS(DECL) \
!   (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.u.thunk_alias)
  
  /* For thunk NODE, this is the FUNCTION_DECL thunked to.  */
  #define THUNK_TARGET(NODE)				\
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.272
diff -c -3 -p -r1.272 method.c
*** cp/method.c	12 Dec 2003 14:06:51 -0000	1.272
--- cp/method.c	12 Dec 2003 16:50:32 -0000
*************** make_thunk (tree function, bool this_adj
*** 124,174 ****
       thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
       will be a BINFO.  */
    for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
!     {
!       if (DECL_THIS_THUNK_P (thunk) != this_adjusting
! 	  || THUNK_FIXED_OFFSET (thunk) != d)
! 	/*not me*/;
!       else if (this_adjusting)
! 	{
! 	  if (!virtual_offset)
! 	    {
! 	      /* We want a non-virtual covariant thunk.  */
! 	      if (!THUNK_VIRTUAL_OFFSET (thunk))
! 		return thunk;
! 	    }
! 	  else if (THUNK_VIRTUAL_OFFSET (thunk))
! 	    {
! 	      if (tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
! 				      virtual_offset))
! 		return thunk;
! 	    }
! 	}
!       else
! 	{
! 	  if (!virtual_offset)
! 	    {
! 	      /* We want a non-virtual covariant thunk.  */
! 	      if (!THUNK_VIRTUAL_OFFSET (thunk))
! 		return thunk;
! 	    }
! 	  else if (!THUNK_VIRTUAL_OFFSET (thunk))
! 	    /*not me*/;
! 	  else if (THUNK_ALIAS_P (thunk))
! 	    {
! 	      /* We have already determined the thunks for FUNCTION,
! 	         and there is a virtual covariant thunk alias.  We
! 	         must compare the vbase offsets of the binfo we have
! 	         been given, and the binfo of the thunk.  */
! 	      tree binfo = THUNK_VIRTUAL_OFFSET (THUNK_ALIAS (thunk));
! 	      
! 	      if (tree_int_cst_equal (BINFO_VPTR_FIELD (virtual_offset),
! 				      BINFO_VPTR_FIELD (binfo)))
! 		return THUNK_ALIAS (thunk);
! 	    }
! 	  else if (THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)
! 	    return thunk;
! 	}
!     }
    
    /* All thunks must be created before FUNCTION is actually emitted;
       the ABI requires that all thunks be emitted together with the
--- 124,138 ----
       thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
       will be a BINFO.  */
    for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
!     if (DECL_THIS_THUNK_P (thunk) == this_adjusting
! 	&& THUNK_FIXED_OFFSET (thunk) == d
! 	&& !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)
! 	&& (!virtual_offset
! 	    || (this_adjusting
! 		? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
! 				      virtual_offset)
! 		: THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
!       return thunk;
    
    /* All thunks must be created before FUNCTION is actually emitted;
       the ABI requires that all thunks be emitted together with the
*************** make_thunk (tree function, bool this_adj
*** 195,200 ****
--- 159,165 ----
    THUNK_TARGET (thunk) = function;
    THUNK_FIXED_OFFSET (thunk) = d;
    THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
+   THUNK_ALIAS (thunk) = NULL_TREE;
    
    /* The thunk itself is not a constructor or destructor, even if
       the thing it is thunking to is.  */
*************** finish_thunk (tree thunk)
*** 254,260 ****
  	if (DECL_NAME (cov_probe) == name)
  	  {
  	    my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
! 	    THUNK_ALIAS (thunk) = (THUNK_ALIAS_P (cov_probe)
  				   ? THUNK_ALIAS (cov_probe) : cov_probe);
  	    break;
  	  }
--- 219,225 ----
  	if (DECL_NAME (cov_probe) == name)
  	  {
  	    my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
! 	    THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
  				   ? THUNK_ALIAS (cov_probe) : cov_probe);
  	    break;
  	  }
*************** use_thunk (tree thunk_fndecl, bool emit_
*** 376,382 ****
  
    /* We should never be using an alias, always refer to the
       aliased thunk.  */
!   my_friendly_assert (!THUNK_ALIAS_P (thunk_fndecl), 20031023);
  
    if (TREE_ASM_WRITTEN (thunk_fndecl))
      return;
--- 341,347 ----
  
    /* We should never be using an alias, always refer to the
       aliased thunk.  */
!   my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023);
  
    if (TREE_ASM_WRITTEN (thunk_fndecl))
      return;
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.374
diff -c -3 -p -r1.374 semantics.c
*** cp/semantics.c	4 Dec 2003 05:02:18 -0000	1.374
--- cp/semantics.c	12 Dec 2003 16:50:40 -0000
*************** emit_associated_thunks (tree fn)
*** 2836,2842 ****
        
        for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
  	{
! 	  if (!THUNK_ALIAS_P (thunk))
  	    {
  	      use_thunk (thunk, /*emit_p=*/1);
  	      if (DECL_RESULT_THUNK_P (thunk))
--- 2836,2842 ----
        
        for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
  	{
! 	  if (!THUNK_ALIAS (thunk))
  	    {
  	      use_thunk (thunk, /*emit_p=*/1);
  	      if (DECL_RESULT_THUNK_P (thunk))
// { dg-do run }

// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 12 Dec 2003 <nathan@codesourcery.com>
// Origin:  grigory@stl.sarov.ru

// PR c++/13118. Missing covariant thunk.

struct c0 {};
struct c1 : virtual c0 {
  virtual c0* f6();
};

struct c5 {
    virtual void foo();
};

struct c10 : virtual c1 {
    virtual void foo();
};

struct c1a : c1 {}; // disambiguation

struct c11 : virtual c10, c1a {
  int i;
  virtual c1* f6 () = 0;
};

struct c18 : c5, virtual c1 {
    virtual void bar();
};

struct c28 : virtual c0, virtual c11 {
    virtual c18* f6();
};

c0 *c1::f6 () {}
void c5::foo () {}
void c10::foo () {}
void c18::bar () {}

c18 ret;

c18 *c28::f6 ()
{
  return &ret;
}

bool check_c1 (c1 *ptr)
{
  c0 *r = ptr->f6 ();
  return r != &ret;
}
bool check_c10 (c10 *ptr)
{
  c0 *r = ptr->f6 ();
  return r != &ret;
}
bool check_c11 (c11 *ptr)
{
  c1 *r = ptr->f6 ();
  return r != &ret;
}
bool check_c28 (c28 *ptr)
{
  c18 *r = ptr->f6 ();
  return r != &ret;
}

int main ()
{
  c28 obj;
  
  if (check_c1 (static_cast<c1a *> (&obj)))
    return 1;
  if (check_c1 (static_cast<c10 *> (&obj)))
    return 2;
  if (check_c10 (&obj))
    return 3;
  if (check_c11 (&obj))
    return 4;
  if (check_c28 (&obj))
    return 5;
  return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]