diff options
Diffstat (limited to 'gcc')
| -rw-r--r-- | gcc/cp/ChangeLog | 11 | ||||
| -rw-r--r-- | gcc/cp/class.c | 42 | ||||
| -rw-r--r-- | gcc/cp/cp-tree.h | 23 | ||||
| -rw-r--r-- | gcc/cp/decl.c | 9 | ||||
| -rw-r--r-- | gcc/cp/method.c | 107 | ||||
| -rw-r--r-- | gcc/cp/semantics.c | 32 | ||||
| -rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
| -rw-r--r-- | gcc/testsuite/g++.dg/abi/vthunk2.C | 16 | 
8 files changed, 116 insertions, 128 deletions
| diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 119bdc1..35251df 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2002-10-25  Mark Mitchell  <mark@codesourcery.com> + +	* class.c (build_vtbl_initializer): Don't use build_vtable_entry. +	(build_vtable_entry): Remove. +	* cp-tree.h (BINFO_VIRTUALS): Expand documentation. +	(lang_decl): Add thunks. +	(DECL_THUNKS): New macro. +	* decl.c (duplicate_decls): Copy it. +	* method.c (make_thunk): Simplify, and add thunks to DECL_THUNKS. +	* semantics.c (emit_associated_thunks): Simplify. +	  2002-10-24  David Edelsohn  <edelsohn@gnu.org>  	PR c++/7228 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f4b9beb..a11ad7b 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -103,7 +103,6 @@ varray_type local_classes;  static tree get_vfield_name PARAMS ((tree));  static void finish_struct_anon PARAMS ((tree)); -static tree build_vtable_entry PARAMS ((tree, tree, tree));  static tree get_vtable_name PARAMS ((tree));  static tree get_basefndecls PARAMS ((tree, tree));  static int build_primary_vtable PARAMS ((tree, tree)); @@ -7673,7 +7672,6 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)        tree delta;        tree vcall_index;        tree fn; -      tree pfn;        tree init = NULL_TREE;        fn = BV_FN (v); @@ -7724,15 +7722,13 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)  	     So, we replace these functions with __pure_virtual.  */  	  if (DECL_PURE_VIRTUAL_P (fn))  	    fn = abort_fndecl; - +	  else if (!integer_zerop (delta) || vcall_index) +	    fn = make_thunk (fn, delta, vcall_index);  	  /* Take the address of the function, considering it to be of an  	     appropriate generic type.  */ -	  pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn); +	  init = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);  	  /* The address of a function can't change.  */ -	  TREE_CONSTANT (pfn) = 1; - -	  /* Enter it in the vtable.  */ -	  init = build_vtable_entry (delta, vcall_index, pfn); +	  TREE_CONSTANT (init) = 1;  	}        /* And add it to the chain of initializers.  */ @@ -8164,33 +8160,3 @@ build_rtti_vtbl_entries (binfo, vid)    *vid->last_init = build_tree_list (NULL_TREE, init);    vid->last_init = &TREE_CHAIN (*vid->last_init);  } - -/* Build an entry in the virtual function table.  DELTA is the offset -   for the `this' pointer.  VCALL_INDEX is the vtable index containing -   the vcall offset; NULL_TREE if none.  ENTRY is the virtual function -   table entry itself.  It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE, -   but it may not actually be a virtual function table pointer.  (For -   example, it might be the address of the RTTI object, under the new -   ABI.)  */ - -static tree -build_vtable_entry (delta, vcall_index, entry) -     tree delta; -     tree vcall_index; -     tree entry; -{ -  tree fn = TREE_OPERAND (entry, 0); -   -  if ((!integer_zerop (delta) || vcall_index != NULL_TREE) -      && fn != abort_fndecl) -    { -      entry = make_thunk (entry, delta, vcall_index); -      entry = build1 (ADDR_EXPR, vtable_entry_type, entry); -      TREE_READONLY (entry) = 1; -      TREE_CONSTANT (entry) = 1; -    } -#ifdef GATHER_STATISTICS -  n_vtable_entries += 1; -#endif -  return entry; -} diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 40c4ab5..5b30d39 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -121,11 +121,15 @@ struct diagnostic_context;       For a FUNCTION_TYPE or METHOD_TYPE, this is TYPE_RAISES_EXCEPTIONS    BINFO_VIRTUALS -     For a binfo, this is a TREE_LIST.  The BV_DELTA of each node -     gives the amount by which to adjust the `this' pointer when -     calling the function.  If the method is an overriden version of a -     base class method, then it is assumed that, prior to adjustment, -     the this pointer points to an object of the base class. +     For a binfo, this is a TREE_LIST.  There is an entry for each +     virtual function declared either in BINFO or its direct and +     indirect primary bases. + +     The BV_DELTA of each node gives the amount by which to adjust the +     `this' pointer when calling the function.  If the method is an +     overriden version of a base class method, then it is assumed +     that, prior to adjustment, the this pointer points to an object +     of the base class.       The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable       index of the vcall offset for this entry.  If @@ -1766,6 +1770,10 @@ struct lang_decl GTY(())  	   non-virtual FUNCTION_DECL, this is DECL_FRIEND_CONTEXT.  */  	tree context; +	/* In a FUNCTION_DECL for which DECL_THUNK_P does not hold, this +	   is DECL_THUNKS.  */ +	tree thunks; +  	/* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION.  */  	tree cloned_function; @@ -2049,6 +2057,11 @@ struct lang_decl GTY(())  #define DECL_NEEDS_FINAL_OVERRIDER_P(NODE) \    (DECL_LANG_SPECIFIC (NODE)->decl_flags.needs_final_overrider) +/* The thunks associated with NODE, a FUNCTION_DECL that is not itself +   a thunk.  */ +#define DECL_THUNKS(NODE) \ +  (DECL_LANG_SPECIFIC (NODE)->u.f.thunks) +  /* Nonzero if NODE is a thunk, rather than an ordinary function.  */  #define DECL_THUNK_P(NODE)			\    (TREE_CODE (NODE) == FUNCTION_DECL		\ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 97ab946..7459c87 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3594,9 +3594,12 @@ duplicate_decls (newdecl, olddecl)        /* Only functions have DECL_BEFRIENDING_CLASSES.  */        if (TREE_CODE (newdecl) == FUNCTION_DECL  	  || DECL_FUNCTION_TEMPLATE_P (newdecl)) -	DECL_BEFRIENDING_CLASSES (newdecl) -	  = chainon (DECL_BEFRIENDING_CLASSES (newdecl), -		     DECL_BEFRIENDING_CLASSES (olddecl)); +	{ +	  DECL_BEFRIENDING_CLASSES (newdecl) +	    = chainon (DECL_BEFRIENDING_CLASSES (newdecl), +		       DECL_BEFRIENDING_CLASSES (olddecl)); +	  DECL_THUNKS (newdecl) = DECL_THUNKS (olddecl); +	}      }    if (TREE_CODE (newdecl) == FUNCTION_DECL) diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 60a0dce..8a905b2 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -278,10 +278,11 @@ make_thunk (function, delta, vcall_index)  {    tree thunk_id;    tree thunk; -  tree func_decl;    tree vcall_offset;    HOST_WIDE_INT d; +  my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025); +    /* Scale the VCALL_INDEX to be in terms of bytes.  */    if (vcall_index)      vcall_offset  @@ -294,59 +295,59 @@ make_thunk (function, delta, vcall_index)    d = tree_low_cst (delta, 0); -  if (TREE_CODE (function) != ADDR_EXPR) -    abort (); -  func_decl = TREE_OPERAND (function, 0); -  if (TREE_CODE (func_decl) != FUNCTION_DECL) -    abort (); +  /* See if we already have the thunk in question.  */ +  for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk)) +    if (THUNK_DELTA (thunk) == d +	&& ((THUNK_VCALL_OFFSET (thunk) != NULL_TREE) +	    == (vcall_offset != NULL_TREE)) +	&& (THUNK_VCALL_OFFSET (thunk) +	    ? tree_int_cst_equal (THUNK_VCALL_OFFSET (thunk),  +				  vcall_offset) +	    : true)) +      return thunk; + +  /* All thunks must be created before FUNCTION is actually emitted; +     the ABI requires that all thunks be emitted together with the +     function to which they transfer control.  */ +  my_friendly_assert (!TREE_ASM_WRITTEN (function), 20021025); + +  thunk_id = mangle_thunk (function, delta, vcall_offset); +  thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (function)); +  DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function); +  cxx_dup_lang_specific_decl (function); +  SET_DECL_ASSEMBLER_NAME (thunk, thunk_id); +  DECL_CONTEXT (thunk) = DECL_CONTEXT (function); +  TREE_READONLY (thunk) = TREE_READONLY (function); +  TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function); +  TREE_PUBLIC (thunk) = TREE_PUBLIC (function); +  if (flag_weak) +    comdat_linkage (thunk); +  SET_DECL_THUNK_P (thunk); +  DECL_INITIAL (thunk) = build1 (ADDR_EXPR, vfunc_ptr_type_node, function); +  THUNK_DELTA (thunk) = d; +  THUNK_VCALL_OFFSET (thunk) = vcall_offset; +  /* The thunk itself is not a constructor or destructor, even if +     the thing it is thunking to is.  */ +  DECL_INTERFACE_KNOWN (thunk) = 1; +  DECL_NOT_REALLY_EXTERN (thunk) = 1; +  DECL_SAVED_FUNCTION_DATA (thunk) = NULL; +  DECL_DESTRUCTOR_P (thunk) = 0; +  DECL_CONSTRUCTOR_P (thunk) = 0; +  /* And neither is it a clone.  */ +  DECL_CLONED_FUNCTION (thunk) = NULL_TREE; +  DECL_EXTERNAL (thunk) = 1; +  DECL_ARTIFICIAL (thunk) = 1; +  /* Even if this thunk is a member of a local class, we don't +     need a static chain.  */ +  DECL_NO_STATIC_CHAIN (thunk) = 1; +  /* The THUNK is not a pending inline, even if the FUNCTION is.  */ +  DECL_PENDING_INLINE_P (thunk) = 0; +  /* Nor has it been deferred.  */ +  DECL_DEFERRED_FN (thunk) = 0; +  /* Add it to the list of thunks associated with FUNCTION.  */ +  TREE_CHAIN (thunk) = DECL_THUNKS (function); +  DECL_THUNKS (function) = thunk; -  thunk_id = mangle_thunk (TREE_OPERAND (function, 0),  -			   delta, vcall_offset); -  thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id); -  if (thunk && !DECL_THUNK_P (thunk)) -    { -      error ("implementation-reserved name `%D' used", thunk_id); -      thunk = NULL_TREE; -      SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk); -    } -  if (thunk == NULL_TREE) -    { -      thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl)); -      DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (func_decl); -      cxx_dup_lang_specific_decl (func_decl); -      SET_DECL_ASSEMBLER_NAME (thunk, thunk_id); -      DECL_CONTEXT (thunk) = DECL_CONTEXT (func_decl); -      TREE_READONLY (thunk) = TREE_READONLY (func_decl); -      TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl); -      TREE_PUBLIC (thunk) = TREE_PUBLIC (func_decl); -      if (flag_weak) -	comdat_linkage (thunk); -      SET_DECL_THUNK_P (thunk); -      DECL_INITIAL (thunk) = function; -      THUNK_DELTA (thunk) = d; -      THUNK_VCALL_OFFSET (thunk) = vcall_offset; -      /* The thunk itself is not a constructor or destructor, even if -         the thing it is thunking to is.  */ -      DECL_INTERFACE_KNOWN (thunk) = 1; -      DECL_NOT_REALLY_EXTERN (thunk) = 1; -      DECL_SAVED_FUNCTION_DATA (thunk) = NULL; -      DECL_DESTRUCTOR_P (thunk) = 0; -      DECL_CONSTRUCTOR_P (thunk) = 0; -      /* And neither is it a clone.  */ -      DECL_CLONED_FUNCTION (thunk) = NULL_TREE; -      DECL_EXTERNAL (thunk) = 1; -      DECL_ARTIFICIAL (thunk) = 1; -      /* Even if this thunk is a member of a local class, we don't -	 need a static chain.  */ -      DECL_NO_STATIC_CHAIN (thunk) = 1; -      /* The THUNK is not a pending inline, even if the FUNC_DECL is.  */ -      DECL_PENDING_INLINE_P (thunk) = 0; -      /* Nor has it been deferred.  */ -      DECL_DEFERRED_FN (thunk) = 0; -      /* So that finish_file can write out any thunks that need to be: */ -      pushdecl_top_level (thunk); -      SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk); -    }    return thunk;  } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c561a66..e2428a9 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2271,35 +2271,9 @@ emit_associated_thunks (fn)       enabling you to output all the thunks with the function itself.  */    if (DECL_VIRTUAL_P (fn))      { -      tree binfo; -      tree v; - -      for (binfo = TYPE_BINFO (DECL_CONTEXT (fn)); -	   binfo; -	   binfo = TREE_CHAIN (binfo)) -	for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v)) -	  if (BV_FN (v) == fn -	      && (!integer_zerop (BV_DELTA (v)) -		  || BV_USE_VCALL_INDEX_P (v))) -	    { -	      tree thunk; -	      tree vcall_index; - -	      if (BV_USE_VCALL_INDEX_P (v)) -		{ -		  vcall_index = BV_VCALL_INDEX (v); -		  my_friendly_assert (vcall_index != NULL_TREE, 20000621); -		} -	      else -		vcall_index = NULL_TREE; - -	      thunk = make_thunk (build1 (ADDR_EXPR, -					  vfunc_ptr_type_node, -					  fn), -				  BV_DELTA (v), -				  vcall_index); -	      use_thunk (thunk, /*emit_p=*/1); -	    } +      tree thunk; +      for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk)) +	use_thunk (thunk, /*emit_p=*/1);      }  } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e7e3cff..a073e68 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2002-10-25  Mark Mitchell  <mark@codesourcery.com> + +	* g++.dg/abi/vthunk2.C: New test. +  2002-10-25  Zack Weinberg  <zack@codesourcery.com>  	* g++.dg/ext/vla1.C, gcc.dg/vla-2.c: New tests. diff --git a/gcc/testsuite/g++.dg/abi/vthunk2.C b/gcc/testsuite/g++.dg/abi/vthunk2.C new file mode 100644 index 0000000..2499749 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/vthunk2.C @@ -0,0 +1,16 @@ +// { dg-do compile { target i?86-*-* } } + +struct c0 { +  virtual void f (); +}; + +struct c1 : virtual public c0 { +}; + +struct c2 : virtual public c0, public c1 { +  virtual void f (); +}; + +void c2::f () {} + +// { dg-final { scan-assembler _ZTv0_n12_N2c21fEv } } | 
