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 3145


Hi,
this fixes 3145, one of the KDE virtual base bugs.

The core of the problem is how build_vbase_path and get_base_distance
behave. build_vbase_path was doing much more work than is now necessary,
so I replaced it with a new build_base_path function, which copes
with any kind of base binfo.  Then get_base_distance was called
via convert_pointer_to_real in various circumstances that lead it
to apparently locate the wrong base binfo.  I replaced get_base_distance
with a new function lookup_base, which has (IMO) a cleaner interface.
Following things through led to the elimination of convert_pointer_to
and convert_pointer_to_real.

I've not actually managed to reproduce the KDE arts problem with 3.1,
as its build keeps picking up some wrong (system) libraries.  However
this patch does fix all there remaining failures (4) in the 3145
testcases up to 50.

I've not tried this on the 3.0.2 tree, but I think it's rather large
for that tree anyway -- thoughts? get_base_distance is still in the
code. I believe those other uses can be removed, and I'll do that if
this patch is ok.

built & tested on i686-pc-linux-gnu, ok?

nathan
-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
2001-11-20  Nathan Sidwell  <nathan@codesourcery.com>

	PR g++/3145
	* class.c (build_vbase_pointer): Remove.
	(build_vbase_path): Remove.
	(build_base_path): New function.
	* cp-tree.h (base_access, base_kind): New enumerations.
	(build_base_path): Declare.
	(convert_pointer_to_real): Remove.
	(convert_pointer_to): Remove.
	(lookup_base): Declare.
	(convert_pointer_to_vbase): Remove.
	* call.c (build_scoped_method_call): Use lookup_base &
	build_base_path instead of convert_pointer_to_real,
	get_base_distance & get_binfo.
	(build_over_call): Likewise.
	* cvt.c (cp_convert_to_pointer): Likewise.
	(convert_to_pointer_force): Likewise.
	(build_up_reference): Likewise.
	(convert_pointer_to_real): Remove.
	(convert_pointer_to): Remove.
	* init.c (dfs_initialize_vtbl_ptrs): Use build_base_path
	instead of convert_pointer_to_vbase & build_vbase_path.
	(emit_base_init): Use build_base_path instead of
	convert_pointer_to_real.
	(expand_virtual_init): Lose unrequired conversions.
	(resolve_offset_ref): Use lookup_base and build_base_path
	instead of convert_pointer_to.
	*rtti.c (build_dynamic_cast_1): Use lookup_base &
	build_base_path instead of get_base_distance & build_vbase_path.
	*search.c (get_vbase_1): Remove.
	(get_vbase): Remove.
	(convert_pointer_to_vbase): Remove.
	(lookup_base_recursive): New function.
	(lookup_base): New function.
	* typeck.c (require_complete_type): Use lookup_base &
	build_base_path instead of convert_pointer_to.
	(build_component_ref): Likewise.
	(build_x_function_call): Likewise.
	(get_member_function_from_ptrfunc): Likewise.
	(build_component_addr): Likewise.
	* typeck2.c (build_scoped_ref): Likewise.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.286
diff -c -3 -p -r1.286 call.c
*** call.c	2001/11/15 15:09:34	1.286
--- call.c	2001/11/20 15:48:24
*************** build_scoped_method_call (exp, basetype,
*** 298,304 ****
  
    if (! binfo)
      {
!       binfo = get_binfo (basetype, type, 1);
        if (binfo == error_mark_node)
  	return error_mark_node;
        if (! binfo)
--- 298,304 ----
  
    if (! binfo)
      {
!       binfo = lookup_base (type, basetype, ba_check, NULL);
        if (binfo == error_mark_node)
  	return error_mark_node;
        if (! binfo)
*************** build_scoped_method_call (exp, basetype,
*** 308,316 ****
    if (binfo)
      {
        if (TREE_CODE (exp) == INDIRECT_REF)
! 	decl = build_indirect_ref
! 	  (convert_pointer_to_real
! 	   (binfo, build_unary_op (ADDR_EXPR, exp, 0)), NULL);
        else
  	decl = build_scoped_ref (exp, basetype);
  
--- 308,319 ----
    if (binfo)
      {
        if (TREE_CODE (exp) == INDIRECT_REF)
! 	{
! 	  decl = build_base_path (PLUS_EXPR,
! 				  build_unary_op (ADDR_EXPR, exp, 0),
! 				  binfo, 1);
! 	  decl = build_indirect_ref (decl, NULL);
! 	}
        else
  	decl = build_scoped_ref (exp, basetype);
  
*************** build_over_call (cand, args, flags)
*** 4155,4161 ****
           So we can assume that anything passed as 'this' is non-null, and
  	 optimize accordingly.  */
        my_friendly_assert (TREE_CODE (parmtype) == POINTER_TYPE, 19990811);
!       t = convert_pointer_to_real (TREE_TYPE (parmtype), TREE_VALUE (arg));
        converted_args = tree_cons (NULL_TREE, t, converted_args);
        parm = TREE_CHAIN (parm);
        arg = TREE_CHAIN (arg);
--- 4158,4166 ----
           So we can assume that anything passed as 'this' is non-null, and
  	 optimize accordingly.  */
        my_friendly_assert (TREE_CODE (parmtype) == POINTER_TYPE, 19990811);
!       t = lookup_base (TREE_TYPE (TREE_TYPE (TREE_VALUE (arg))),
! 		       TREE_TYPE (parmtype), ba_ignore, NULL);
!       t = build_base_path (PLUS_EXPR, TREE_VALUE (arg), t, 1);
        converted_args = tree_cons (NULL_TREE, t, converted_args);
        parm = TREE_CHAIN (parm);
        arg = TREE_CHAIN (arg);
*************** build_over_call (cand, args, flags)
*** 4305,4313 ****
    if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
      {
        tree t, *p = &TREE_VALUE (converted_args);
!       tree binfo = get_binfo
! 	(DECL_VIRTUAL_CONTEXT (fn), TREE_TYPE (TREE_TYPE (*p)), 0);
!       *p = convert_pointer_to_real (binfo, *p);
        if (TREE_SIDE_EFFECTS (*p))
  	*p = save_expr (*p);
        t = build_pointer_type (TREE_TYPE (fn));
--- 4310,4321 ----
    if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
      {
        tree t, *p = &TREE_VALUE (converted_args);
!       tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (*p)),
! 				DECL_VIRTUAL_CONTEXT (fn),
! 				ba_any, NULL);
!       my_friendly_assert (binfo && binfo != error_mark_node, 20010730);
!       
!       *p = build_base_path (PLUS_EXPR, *p, binfo, 1);
        if (TREE_SIDE_EFFECTS (*p))
  	*p = save_expr (*p);
        t = build_pointer_type (TREE_TYPE (fn));
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.416
diff -c -3 -p -r1.416 class.c
*** class.c	2001/11/09 23:08:36	1.416
--- class.c	2001/11/20 15:48:26
*************** varray_type local_classes;
*** 106,112 ****
  
  static tree get_vfield_name PARAMS ((tree));
  static void finish_struct_anon PARAMS ((tree));
- static tree build_vbase_pointer PARAMS ((tree, tree));
  static tree build_vtable_entry PARAMS ((tree, tree, tree));
  static tree get_vtable_name PARAMS ((tree));
  static tree get_basefndecls PARAMS ((tree, tree));
--- 106,111 ----
*************** int n_build_method_call = 0;
*** 236,425 ****
  int n_inner_fields_searched = 0;
  #endif
  
! /* Virtual base class layout.  */
  
- /* Returns a pointer to the virtual base class of EXP that has the
-    indicated TYPE.  EXP is of class type, not a pointer type.  */
- 
- static tree
- build_vbase_pointer (exp, type)
-      tree exp, type;
- {
-   tree vbase;
-   tree vbase_ptr;
- 
-   /* Find the shared copy of TYPE; that's where the vtable offset is
-      recorded.  */
-   vbase = binfo_for_vbase (type, TREE_TYPE (exp));
-   /* Find the virtual function table pointer.  */
-   vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp));
-   /* Compute the location where the offset will lie.  */
-   vbase_ptr = build (PLUS_EXPR, 
- 		     TREE_TYPE (vbase_ptr),
- 		     vbase_ptr,
- 		     BINFO_VPTR_FIELD (vbase));
-   vbase_ptr = build1 (NOP_EXPR, 
- 		      build_pointer_type (ptrdiff_type_node),
- 		      vbase_ptr);
-   /* Add the contents of this location to EXP.  */
-   return build (PLUS_EXPR,
- 		build_pointer_type (type),
- 		build_unary_op (ADDR_EXPR, exp, /*noconvert=*/0),
- 		build1 (INDIRECT_REF, ptrdiff_type_node, vbase_ptr));
- }
- 
- /* Build multi-level access to EXPR using hierarchy path PATH.
-    CODE is PLUS_EXPR if we are going with the grain,
-    and MINUS_EXPR if we are not (in which case, we cannot traverse
-    virtual baseclass links).
- 
-    TYPE is the type we want this path to have on exit.
- 
-    NONNULL is non-zero if  we know (for any reason) that EXPR is
-    not, in fact, zero.  */
- 
  tree
! build_vbase_path (code, type, expr, path, nonnull)
       enum tree_code code;
!      tree type, expr, path;
       int nonnull;
  {
!   register int changed = 0;
!   tree last = NULL_TREE, last_virtual = NULL_TREE;
    int fixed_type_p;
!   tree null_expr = 0, nonnull_expr;
!   tree basetype;
!   tree offset = integer_zero_node;
  
!   if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
!     return build1 (NOP_EXPR, type, expr);
  
-   /* We could do better if we had additional logic to convert back to the
-      unconverted type (the static type of the complete object), and then
-      convert back to the type we want.  Until that is done, we only optimize
-      if the complete type is the same type as expr has.  */
    fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
    if (fixed_type_p < 0)
      /* Virtual base layout is not fixed, even in ctors and dtors. */
      fixed_type_p = 0;
- 
    if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
      expr = save_expr (expr);
!   nonnull_expr = expr;
! 
!   path = reverse_path (path);
! 
!   basetype = BINFO_TYPE (path);
! 
!   while (path)
      {
!       if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
! 	{
! 	  last_virtual = BINFO_TYPE (TREE_VALUE (path));
! 	  if (code == PLUS_EXPR)
! 	    {
! 	      changed = ! fixed_type_p;
! 
! 	      if (changed)
! 		{
! 		  tree ind;
! 
! 		  /* We already check for ambiguous things in the caller, just
! 		     find a path.  */
! 		  if (last)
! 		    {
! 		      tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
! 		      nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr);
! 		    }
! 		  ind = build_indirect_ref (nonnull_expr, NULL);
! 		  nonnull_expr = build_vbase_pointer (ind, last_virtual);
! 		  if (nonnull == 0
! 		      && TREE_CODE (type) == POINTER_TYPE
! 		      && null_expr == NULL_TREE)
! 		    {
! 		      null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node);
! 		      expr = build (COND_EXPR, build_pointer_type (last_virtual),
! 				    build (EQ_EXPR, boolean_type_node, expr,
! 					   integer_zero_node),
! 				    null_expr, nonnull_expr);
! 		    }
! 		}
! 	      /* else we'll figure out the offset below.  */
  
! 	      /* Happens in the case of parse errors.  */
! 	      if (nonnull_expr == error_mark_node)
! 		return error_mark_node;
! 	    }
! 	  else
! 	    {
! 	      cp_error ("cannot cast up from virtual baseclass `%T'",
! 			  last_virtual);
! 	      return error_mark_node;
! 	    }
! 	}
!       last = TREE_VALUE (path);
!       path = TREE_CHAIN (path);
      }
-   /* LAST is now the last basetype assoc on the path.  */
  
!   /* A pointer to a virtual base member of a non-null object
!      is non-null.  Therefore, we only need to test for zeroness once.
!      Make EXPR the canonical expression to deal with here.  */
!   if (null_expr)
!     {
!       TREE_OPERAND (expr, 2) = nonnull_expr;
!       TREE_TYPE (expr) = TREE_TYPE (TREE_OPERAND (expr, 1))
! 	= TREE_TYPE (nonnull_expr);
!     }
!   else
!     expr = nonnull_expr;
  
!   /* If we go through any virtual base pointers, make sure that
!      casts to BASETYPE from the last virtual base class use
!      the right value for BASETYPE.  */
!   if (changed)
!     {
!       tree intype = TREE_TYPE (TREE_TYPE (expr));
! 
!       if (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last))
! 	offset
! 	  = BINFO_OFFSET (get_binfo (last, TYPE_MAIN_VARIANT (intype), 0));
!     }
    else
!     offset = BINFO_OFFSET (last);
! 
!   if (! integer_zerop (offset))
!     {
!       /* Bash types to make the backend happy.  */
!       offset = cp_convert (type, offset);
! 
!       /* If expr might be 0, we need to preserve that zeroness.  */
!       if (nonnull == 0)
! 	{
! 	  if (null_expr)
! 	    TREE_TYPE (null_expr) = type;
! 	  else
! 	    null_expr = build1 (NOP_EXPR, type, integer_zero_node);
! 	  if (TREE_SIDE_EFFECTS (expr))
! 	    expr = save_expr (expr);
! 
! 	  return build (COND_EXPR, type,
! 			build (EQ_EXPR, boolean_type_node, expr, integer_zero_node),
! 			null_expr,
! 			build (code, type, expr, offset));
! 	}
!       else return build (code, type, expr, offset);
!     }
  
!   /* Cannot change the TREE_TYPE of a NOP_EXPR here, since it may
!      be used multiple times in initialization of multiple inheritance.  */
!   if (null_expr)
!     {
!       TREE_TYPE (expr) = type;
!       return expr;
!     }
!   else
!     return build1 (NOP_EXPR, type, expr);
  }
  
  
--- 235,353 ----
  int n_inner_fields_searched = 0;
  #endif
  
! /* Build an access from EXPR to or from a base BINFO. CODE is
!    PLUS_EXPR if we're going from derived to base BINFO and MINUS_EXPR
!    if we're going from base BINFO to most derived. For that latter
!    case we cannot cross virtual bases. NONNULL is true if we know that
!    EXPR is not null.  EXPR may have pointer or class type and a
!    correctly qualifed pointer or class type is returned. */
  
  tree
! build_base_path (code, expr, binfo, nonnull)
       enum tree_code code;
!      tree expr;
!      tree binfo;
       int nonnull;
  {
!   tree v_binfo = NULL_TREE;
!   tree t;
!   tree probe;
!   tree offset;
!   tree target_type;
!   tree null_test = NULL;
!   tree ptr_target_type;
    int fixed_type_p;
!   int want_pointer = TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE;
  
!   if (expr == error_mark_node || binfo == error_mark_node || !binfo)
!     return error_mark_node;
!   
!   for (probe = binfo; probe;
!        t = probe, probe = BINFO_INHERITANCE_CHAIN (probe))
!     if (!v_binfo && TREE_VIA_VIRTUAL (probe))
!       v_binfo = probe;
! 
!   probe = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
!   if (want_pointer)
!     probe = TYPE_MAIN_VARIANT (TREE_TYPE (probe));
!   
!   my_friendly_assert (code == MINUS_EXPR
! 		      ? same_type_p (BINFO_TYPE (binfo), probe)
! 		      : code == PLUS_EXPR
! 		      ? same_type_p (BINFO_TYPE (t), probe)
! 		      : false, 20010723);
!   
!   if (code == MINUS_EXPR && v_binfo)
!     {
!       cp_error ("cannot convert from base `%T' to derived type `%T' via virtual base `%T'",
! 		BINFO_TYPE (binfo), BINFO_TYPE (t), BINFO_TYPE (v_binfo));
!       return error_mark_node;
!     }
  
    fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
    if (fixed_type_p < 0)
      /* Virtual base layout is not fixed, even in ctors and dtors. */
      fixed_type_p = 0;
    if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
      expr = save_expr (expr);
!     
!   if (!want_pointer)
!     expr = build_unary_op (ADDR_EXPR, expr, 0);
!   else if (!nonnull)
!     null_test = build (EQ_EXPR, boolean_type_node, expr, integer_zero_node);
!   
!   offset = BINFO_OFFSET (binfo);
!   
!   if (v_binfo && !fixed_type_p)
      {
!       /* Going via virtual base V_BINFO. We need the static offset from
!          V_BINFO to BINFO, and the dynamic offset from T to V_BINFO.
!          Under the 3.0 ABI, that offset is an entry in T's vtable.  */
!       tree v_offset = build_vfield_ref (build_indirect_ref (expr, NULL),
! 					TREE_TYPE (TREE_TYPE (expr)));
!       
!       v_binfo = binfo_for_vbase (BINFO_TYPE (v_binfo), BINFO_TYPE (t));
!       
!       v_offset = build (PLUS_EXPR, TREE_TYPE (v_offset),
! 			v_offset,  BINFO_VPTR_FIELD (v_binfo));
!       v_offset = build1 (NOP_EXPR, 
! 			 build_pointer_type (ptrdiff_type_node),
! 			 v_offset);
!       v_offset = build_indirect_ref (v_offset, NULL);
!       
!       offset = cp_convert (ptrdiff_type_node,
! 			   size_diffop (offset, BINFO_OFFSET (v_binfo)));
  
!       if (!integer_zerop (offset))
! 	offset = build (code, ptrdiff_type_node, v_offset, offset);
!       else
! 	offset = v_offset;
      }
  
!   target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (t);
!   
!   target_type = cp_build_qualified_type
!     (target_type, CP_TYPE_QUALS (TREE_TYPE (TREE_TYPE (expr))));
!   ptr_target_type = build_pointer_type (target_type);
!   if (want_pointer)
!     target_type = ptr_target_type;
!   
!   expr = build1 (NOP_EXPR, ptr_target_type, expr);
  
!   if (!integer_zerop (offset))
!     expr = build (code, ptr_target_type, expr, offset);
    else
!     null_test = NULL;
!   
!   if (!want_pointer)
!     expr = build_indirect_ref (expr, NULL);
  
!   if (null_test)
!     expr = build (COND_EXPR, target_type, null_test,
! 		  build1 (NOP_EXPR, target_type, integer_zero_node),
! 		  expr);
!   
!   return expr;
  }
  
  
*************** fixed_type_or_null (instance, nonnull, c
*** 5468,5478 ****
      }
  }
  
! /* Return non-zero if the dynamic type of INSTANCE is known, and equivalent
!    to the static type.  We also handle the case where INSTANCE is really
!    a pointer. Return negative if this is a ctor/dtor. There the dynamic type
!    is known, but this might not be the most derived base of the original object,
!    and hence virtual bases may not be layed out according to this type.
  
     Used to determine whether the virtual function table is needed
     or not.
--- 5396,5407 ----
      }
  }
  
! /* Return non-zero if the dynamic type of INSTANCE is known, and
!    equivalent to the static type.  We also handle the case where
!    INSTANCE is really a pointer. Return negative if this is a
!    ctor/dtor. There the dynamic type is known, but this might not be
!    the most derived base of the original object, and hence virtual
!    bases may not be layed out according to this type.
  
     Used to determine whether the virtual function table is needed
     or not.
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.654
diff -c -3 -p -r1.654 cp-tree.h
*** cp-tree.h	2001/11/15 10:00:56	1.654
--- cp-tree.h	2001/11/20 15:48:27
*************** typedef enum instantiate_type_flags {
*** 3022,3027 ****
--- 3022,3049 ----
    itf_ptrmem_ok = 1 << 2,     /* pointers to member ok (internal use) */
  } instantiate_type_flags;
  
+ /* The kind of checking we can do looking in a class heirarchy. */
+ typedef enum base_access {
+   ba_any = -2,     /* Do not check access, allow an ambiguous base */
+   ba_ignore = -1,  /* Do not check access */
+   ba_check = 0,    /* Check access */
+   ba_not_special   /* Do not consider special privilege
+ 		      current_class_type might give. */
+ } base_access;
+ 
+ /* The kind of base we can find, looking in a class heirarchy.
+    values <0 indicate we failed. */
+ typedef enum base_kind {
+   bk_inaccessible = -3,   /* the base is inaccessible */
+   bk_ambig = -2,          /* the base is ambiguous */
+   bk_not_base = -1,       /* it is not a base */
+   bk_same_type = 0,       /* it is the same type */
+   bk_proper_base = 1,     /* it is a proper base */
+   bk_via_virtual = 2      /* it is a proper base, but via a virtual
+ 			     path. This might not be the canonical
+ 			     binfo. */
+ } base_kind;
+ 
  /* Nonzero means allow Microsoft extensions without a pedwarn.  */
  extern int flag_ms_extensions;
  
*************** extern tree strip_top_quals             
*** 3512,3517 ****
--- 3534,3540 ----
  extern tree perform_implicit_conversion         PARAMS ((tree, tree));
  
  /* in class.c */
+ extern tree build_base_path			PARAMS ((enum tree_code, tree, tree, int));
  extern tree build_vbase_path			PARAMS ((enum tree_code, tree, tree, tree, int));
  extern tree build_vtbl_ref			PARAMS ((tree, tree));
  extern tree build_vfn_ref			PARAMS ((tree, tree));
*************** extern tree get_primary_binfo           
*** 3557,3564 ****
  extern tree convert_to_reference		PARAMS ((tree, tree, int, int, tree));
  extern tree convert_from_reference		PARAMS ((tree));
  extern tree convert_lvalue			PARAMS ((tree, tree));
- extern tree convert_pointer_to_real		PARAMS ((tree, tree));
- extern tree convert_pointer_to			PARAMS ((tree, tree));
  extern tree ocp_convert				PARAMS ((tree, tree, int, int));
  extern tree cp_convert				PARAMS ((tree, tree));
  extern tree convert_to_void			PARAMS ((tree, const char */*implicit context*/));
--- 3580,3585 ----
*************** extern int tinfo_decl_p                 
*** 3983,3988 ****
--- 4004,4010 ----
  extern int emit_tinfo_decl                      PARAMS((tree *, void *));
  
  /* in search.c */
+ extern tree lookup_base PARAMS ((tree, tree, base_access, base_kind *));
  extern int types_overlap_p			PARAMS ((tree, tree));
  extern tree get_vbase				PARAMS ((tree, tree));
  extern tree get_binfo				PARAMS ((tree, tree, int));
*************** extern tree dfs_marked_real_bases_queue_
*** 4033,4039 ****
  extern tree dfs_skip_vbases                     PARAMS ((tree, void *));
  extern tree marked_vtable_pathp                 PARAMS ((tree, void *));
  extern tree unmarked_vtable_pathp               PARAMS ((tree, void *));
- extern tree convert_pointer_to_vbase            PARAMS ((tree, tree));
  extern tree find_vbase_instance                 PARAMS ((tree, tree));
  extern tree binfo_for_vbase                     PARAMS ((tree, tree));
  extern tree binfo_via_virtual                   PARAMS ((tree, tree));
--- 4055,4060 ----
Index: cp/cvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v
retrieving revision 1.106
diff -c -3 -p -r1.106 cvt.c
*** cvt.c	2001/11/15 15:09:35	1.106
--- cvt.c	2001/11/20 15:48:28
*************** cp_convert_to_pointer (type, expr, force
*** 141,184 ****
  	  && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
  	  && IS_AGGR_TYPE (TREE_TYPE (type))
  	  && IS_AGGR_TYPE (TREE_TYPE (intype))
! 	  && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE
! 	  /* If EXPR is NULL, then we don't need to do any arithmetic
! 	     to convert it:
! 
! 	       [conv.ptr]
! 
! 	       The null pointer value is converted to the null pointer
! 	       value of the destination type.  */
! 	  && !integer_zerop (expr))
  	{
  	  enum tree_code code = PLUS_EXPR;
! 	  tree binfo = get_binfo (TREE_TYPE (type), TREE_TYPE (intype), 1);
! 	  if (binfo == error_mark_node)
! 	    return error_mark_node;
! 	  if (binfo == NULL_TREE)
  	    {
! 	      binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 1);
! 	      if (binfo == error_mark_node)
! 		return error_mark_node;
  	      code = MINUS_EXPR;
  	    }
  	  if (binfo)
  	    {
! 	      if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (type))
! 		  || TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (intype))
! 		  || ! BINFO_OFFSET_ZEROP (binfo))
  		{
! 		  /* Need to get the path we took.  */
! 		  tree path;
! 
! 		  if (code == PLUS_EXPR)
! 		    get_base_distance (TREE_TYPE (type), TREE_TYPE (intype),
! 				       0, &path);
! 		  else
! 		    get_base_distance (TREE_TYPE (intype), TREE_TYPE (type),
! 				       0, &path);
! 		  return build_vbase_path (code, type, expr, path, 0);
  		}
  	    }
  	}
  
--- 141,175 ----
  	  && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
  	  && IS_AGGR_TYPE (TREE_TYPE (type))
  	  && IS_AGGR_TYPE (TREE_TYPE (intype))
! 	  && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
  	{
  	  enum tree_code code = PLUS_EXPR;
! 	  tree binfo;
! 
! 	  /* Try derived to base conversion. */
! 	  binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type),
! 			       ba_check, NULL);
! 	  if (!binfo)
  	    {
! 	      /* Try base to derived conversion. */
! 	      binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
! 				   ba_check, NULL);
  	      code = MINUS_EXPR;
  	    }
+ 	  if (binfo == error_mark_node)
+ 	    return error_mark_node;
  	  if (binfo)
  	    {
! 	      expr = build_base_path (code, expr, binfo, 0);
! 	      /* Add any qualifier conversions. */
! 	      if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)),
! 				TREE_TYPE (type)))
  		{
! 		  expr = build1 (NOP_EXPR, type, expr);
! 		  TREE_CONSTANT (expr) =
! 		    TREE_CONSTANT (TREE_OPERAND (expr, 0));
  		}
+ 	      return expr;
  	    }
  	}
  
*************** cp_convert_to_pointer (type, expr, force
*** 187,222 ****
  	  tree b1; 
  	  tree b2;
  	  tree binfo;
! 	  tree virt_binfo;
! 	  enum tree_code code;
  
  	  b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
  	  b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
! 	  binfo = get_binfo (b2, b1, 1);
! 
! 	  if (binfo == NULL_TREE)
  	    {
! 	      binfo = get_binfo (b1, b2, 1);
  	      code = MINUS_EXPR;
  	    }
- 	  else
- 	    code = PLUS_EXPR;
- 
  	  if (binfo == error_mark_node)
  	    return error_mark_node;
  
!           virt_binfo = binfo_from_vbase (binfo);
!           if (virt_binfo)
  	    {
  	      if (force)
! 	        cp_warning ("pointer to member cast via virtual base `%T' of `%T'",
! 	                    BINFO_TYPE (virt_binfo),
!                             BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
                else
                  {
! 	          cp_error ("pointer to member cast via virtual base `%T' of `%T'",
! 	                    BINFO_TYPE (virt_binfo),
!                             BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
  	          return error_mark_node;
  	        }
  	      /* This is a reinterpret cast, whose result is unspecified.
--- 178,206 ----
  	  tree b1; 
  	  tree b2;
  	  tree binfo;
! 	  enum tree_code code = PLUS_EXPR;
! 	  base_kind bk;
  
  	  b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
  	  b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
! 	  binfo = lookup_base (b1, b2, ba_check, &bk);
! 	  if (!binfo)
  	    {
! 	      binfo = lookup_base (b2, b1, ba_check, &bk);
  	      code = MINUS_EXPR;
  	    }
  	  if (binfo == error_mark_node)
  	    return error_mark_node;
  
!           if (bk == bk_via_virtual)
  	    {
  	      if (force)
! 	        cp_warning ("pointer to member cast from `%T' to `%T' is via virtual base",
! 	                    TREE_TYPE (intype), TREE_TYPE (type));
                else
                  {
! 		  cp_error ("pointer to member cast from `%T' to `%T' is via virtual base",
! 			    TREE_TYPE (intype), TREE_TYPE (type));
  	          return error_mark_node;
  	        }
  	      /* This is a reinterpret cast, whose result is unspecified.
*************** convert_to_pointer_force (type, expr)
*** 319,352 ****
  	  && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
  	{
  	  enum tree_code code = PLUS_EXPR;
! 	  tree path;
! 	  int distance = get_base_distance (TREE_TYPE (type),
! 					    TREE_TYPE (intype), 0, &path);
! 	  if (distance == -2)
  	    {
! 	      cp_error ("type `%T' is ambiguous base of `%T'",
! 			TREE_TYPE (type),
! 			TREE_TYPE (intype));
! 	      return error_mark_node;
  	    }
! 	  if (distance == -1)
  	    {
! 	      distance = get_base_distance (TREE_TYPE (intype),
! 					    TREE_TYPE (type), 0, &path);
! 	      if (distance == -2)
! 	        {
! 	          cp_error ("type `%T' is ambiguous base of `%T'",
! 			    TREE_TYPE (intype),
! 			    TREE_TYPE (type));
! 	          return error_mark_node;
! 	        }
! 	      if (distance < 0)
! 		/* Doesn't need any special help from us.  */
! 		return build1 (NOP_EXPR, type, expr);
! 
! 	      code = MINUS_EXPR;
  	    }
! 	  return build_vbase_path (code, type, expr, path, 0);
  	}
      }
  
--- 303,334 ----
  	  && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
  	{
  	  enum tree_code code = PLUS_EXPR;
! 	  tree binfo;
! 
! 	  binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type),
! 			       ba_ignore, NULL);
! 	  if (!binfo)
  	    {
! 	      binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
! 				   ba_ignore, NULL);
! 	      code = MINUS_EXPR;
  	    }
! 	  if (binfo == error_mark_node)
! 	    return error_mark_node;
! 	  if (binfo)
  	    {
! 	      expr = build_base_path (code, expr, binfo, 0);
! 	      /* Add any qualifier conversions. */
! 	      if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)),
! 				TREE_TYPE (type)))
! 		{
! 		  expr = build1 (NOP_EXPR, type, expr);
! 		  TREE_CONSTANT (expr) =
! 		    TREE_CONSTANT (TREE_OPERAND (expr, 0));
! 		}
! 	      return expr;
  	    }
! 	  
  	}
      }
  
*************** build_up_reference (type, arg, flags, de
*** 420,431 ****
        && IS_AGGR_TYPE (target_type))
      {
        /* We go through get_binfo for the access control.  */
!       tree binfo = get_binfo (target_type, argtype, 1);
        if (binfo == error_mark_node)
  	return error_mark_node;
        if (binfo == NULL_TREE)
  	return error_not_base_type (target_type, argtype);
!       rval = convert_pointer_to_real (binfo, rval);
      }
    else
      rval
--- 402,413 ----
        && IS_AGGR_TYPE (target_type))
      {
        /* We go through get_binfo for the access control.  */
!       tree binfo = lookup_base (argtype, target_type, ba_check, NULL);
        if (binfo == error_mark_node)
  	return error_mark_node;
        if (binfo == NULL_TREE)
  	return error_not_base_type (target_type, argtype);
!       rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
      }
    else
      rval
*************** convert_lvalue (totype, expr)
*** 624,710 ****
    expr = convert_to_reference (totype, expr, CONV_IMPLICIT, LOOKUP_NORMAL,
  			       NULL_TREE);
    return convert_from_reference (expr);
- }
- 
- /* Call this when we know (for any reason) that expr is not, in fact,
-    zero.  This routine is like convert_pointer_to, but it pays
-    attention to which specific instance of what type we want to
-    convert to.  This routine should eventually become
-    convert_to_pointer after all references to convert_to_pointer
-    are removed.  */
- 
- tree
- convert_pointer_to_real (binfo, expr)
-      tree binfo, expr;
- {
-   register tree intype = TREE_TYPE (expr);
-   tree ptr_type;
-   tree type, rval;
- 
-   if (intype == error_mark_node)
-     return error_mark_node;
- 
-   if (TREE_CODE (binfo) == TREE_VEC)
-     type = BINFO_TYPE (binfo);
-   else if (IS_AGGR_TYPE (binfo))
-     {
-       type = binfo;
-     }
-   else
-     {
-       type = binfo;
-       binfo = NULL_TREE;
-     }
- 
-   ptr_type = cp_build_qualified_type (type,
- 				      CP_TYPE_QUALS (TREE_TYPE (intype)));
-   ptr_type = build_pointer_type (ptr_type);
-   if (same_type_p (ptr_type, TYPE_MAIN_VARIANT (intype)))
-     return expr;
- 
-   my_friendly_assert (!integer_zerop (expr), 191);
- 
-   intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype));
-   if (TREE_CODE (type) == RECORD_TYPE
-       && TREE_CODE (intype) == RECORD_TYPE
-       && type != intype)
-     {
-       tree path;
-       int distance
- 	= get_base_distance (binfo, intype, 0, &path);
- 
-       /* This function shouldn't be called with unqualified arguments
- 	 but if it is, give them an error message that they can read.  */
-       if (distance < 0)
- 	{
- 	  cp_error ("cannot convert a pointer of type `%T' to a pointer of type `%T'",
- 		    intype, type);
- 
- 	  if (distance == -2)
- 	    cp_error ("because `%T' is an ambiguous base class", type);
- 	  return error_mark_node;
- 	}
- 
-       return build_vbase_path (PLUS_EXPR, ptr_type, expr, path, 1);
-     }
-   rval = build1 (NOP_EXPR, ptr_type,
- 		 TREE_CODE (expr) == NOP_EXPR ? TREE_OPERAND (expr, 0) : expr);
-   TREE_CONSTANT (rval) = TREE_CONSTANT (expr);
-   return rval;
- }
- 
- /* Call this when we know (for any reason) that expr is
-    not, in fact, zero.  This routine gets a type out of the first
-    argument and uses it to search for the type to convert to.  If there
-    is more than one instance of that type in the expr, the conversion is
-    ambiguous.  This routine should eventually go away, and all
-    callers should use convert_to_pointer_real.  */
- 
- tree
- convert_pointer_to (binfo, expr)
-      tree binfo, expr;
- {
-   return convert_pointer_to_real (binfo, expr);
  }
  
  /* C++ conversions, preference to static cast conversions.  */
--- 606,611 ----
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.250
diff -c -3 -p -r1.250 init.c
*** init.c	2001/11/15 10:03:37	1.250
--- init.c	2001/11/20 15:48:28
*************** finish_init_stmts (stmt_expr, compound_s
*** 130,136 ****
  
  /* Constructors */
  
! /* Called from initialize_vtbl_ptrs via dfs_walk.  */
  
  static tree
  dfs_initialize_vtbl_ptrs (binfo, data)
--- 130,138 ----
  
  /* Constructors */
  
! /* Called from initialize_vtbl_ptrs via dfs_walk.  BINFO is the base
!    which we want to initialize the vtable pointer for, DATA is
!    TREE_LIST whose TREE_VALUE is the this ptr expression.  */
  
  static tree
  dfs_initialize_vtbl_ptrs (binfo, data)
*************** dfs_initialize_vtbl_ptrs (binfo, data)
*** 142,157 ****
      {
        tree base_ptr = TREE_VALUE ((tree) data);
  
!       if (TREE_VIA_VIRTUAL (binfo))
! 	base_ptr = convert_pointer_to_vbase (BINFO_TYPE (binfo),
! 					     base_ptr);
!       else
! 	base_ptr 
! 	  = build_vbase_path (PLUS_EXPR, 
! 			      build_pointer_type (BINFO_TYPE (binfo)),
! 			      base_ptr,
! 			      binfo,
! 			      /*nonnull=*/1);
  
        expand_virtual_init (binfo, base_ptr);
      }
--- 144,150 ----
      {
        tree base_ptr = TREE_VALUE ((tree) data);
  
!       base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1);
  
        expand_virtual_init (binfo, base_ptr);
      }
*************** emit_base_init (mem_init_list, base_init
*** 711,717 ****
  
        if (init != void_list_node)
  	{
! 	  member = convert_pointer_to_real (base_binfo, current_class_ptr);
  	  expand_aggr_init_1 (base_binfo, NULL_TREE,
  			      build_indirect_ref (member, NULL), init,
  			      LOOKUP_NORMAL);
--- 704,711 ----
  
        if (init != void_list_node)
  	{
! 	  member = build_base_path (PLUS_EXPR, current_class_ptr,
! 				    base_binfo, 1);
  	  expand_aggr_init_1 (base_binfo, NULL_TREE,
  			      build_indirect_ref (member, NULL), init,
  			      LOOKUP_NORMAL);
*************** static void
*** 802,816 ****
  expand_virtual_init (binfo, decl)
       tree binfo, decl;
  {
-   tree type = BINFO_TYPE (binfo);
    tree vtbl, vtbl_ptr;
-   tree vtype, vtype_binfo;
    tree vtt_index;
  
-   /* Compute the location of the vtable.  */
-   vtype = DECL_CONTEXT (TYPE_VFIELD (type));
-   vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
-   
    /* Compute the initializer for vptr.  */
    vtbl = build_vtbl_address (binfo);
  
--- 796,804 ----
*************** expand_virtual_init (binfo, decl)
*** 842,851 ****
      }
  
    /* Compute the location of the vtpr.  */
!   decl = convert_pointer_to_real (vtype_binfo, decl);
!   vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL), vtype);
!   if (vtbl_ptr == error_mark_node)
!     return;
  
    /* Assign the vtable to the vptr.  */
    vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
--- 830,838 ----
      }
  
    /* Compute the location of the vtpr.  */
!   vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL),
! 			       TREE_TYPE (binfo));
!   my_friendly_assert (vtbl_ptr != error_mark_node, 20010730);
  
    /* Assign the vtable to the vptr.  */
    vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
*************** resolve_offset_ref (exp)
*** 1842,1855 ****
        if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
  	base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type));
  
!       addr = build_unary_op (ADDR_EXPR, base, 0);
!       addr = convert_pointer_to (basetype, addr);
! 
!       if (addr == error_mark_node)
  	return error_mark_node;
  
        expr = build (COMPONENT_REF, TREE_TYPE (member),
! 		    build_indirect_ref (addr, NULL), member);
        return convert_from_reference (expr);
      }
  
--- 1829,1842 ----
        if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
  	base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type));
  
!       basetype = lookup_base (TREE_TYPE (base), basetype, ba_check, NULL);
!       expr = build_base_path (PLUS_EXPR, base, basetype, 1);
!       
!       if (expr == error_mark_node)
  	return error_mark_node;
  
        expr = build (COMPONENT_REF, TREE_TYPE (member),
! 		    expr, member);
        return convert_from_reference (expr);
      }
  
*************** resolve_offset_ref (exp)
*** 1872,1878 ****
  	}
  
        basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
!       addr = convert_pointer_to (basetype, addr);
        member = cp_convert (ptrdiff_type_node, member);
  
        return build1 (INDIRECT_REF, type,
--- 1859,1868 ----
  	}
  
        basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
!       basetype = lookup_base (TREE_TYPE (TREE_TYPE (addr)),
! 			      basetype, ba_check, NULL);
!       addr = build_base_path (PLUS_EXPR, addr, basetype, 1);
!       
        member = cp_convert (ptrdiff_type_node, member);
  
        return build1 (INDIRECT_REF, type,
Index: cp/rtti.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/rtti.c,v
retrieving revision 1.124
diff -c -3 -p -r1.124 rtti.c
*** rtti.c	2001/10/03 15:18:25	1.124
--- rtti.c	2001/11/20 15:48:28
*************** build_dynamic_cast_1 (type, expr)
*** 472,499 ****
    /* If *type is an unambiguous accessible base class of *exprtype,
       convert statically.  */
    {
!     int distance;
!     tree path;
  
!     distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,
! 				  &path);
  
!     if (distance == -2)
        {
! 	cp_error ("dynamic_cast from `%T' to ambiguous base class `%T'",
! 		  TREE_TYPE (exprtype), TREE_TYPE (type));
! 	return error_mark_node;
!       }
!     if (distance == -3)
!       {
! 	cp_error ("dynamic_cast from `%T' to private base class `%T'",
! 		  TREE_TYPE (exprtype), TREE_TYPE (type));
! 	return error_mark_node;
!       }
! 
!     if (distance >= 0)
!       {
! 	expr = build_vbase_path (PLUS_EXPR, type, expr, path, 0);
  	if (TREE_CODE (exprtype) == POINTER_TYPE)
  	  expr = non_lvalue (expr);
  	return expr;
--- 472,486 ----
    /* If *type is an unambiguous accessible base class of *exprtype,
       convert statically.  */
    {
!     tree binfo;
  
!     binfo = lookup_base (TREE_TYPE (exprtype), TREE_TYPE (type),
! 			 ba_not_special, NULL);
  
!     if (binfo)
        {
! 	expr = build_base_path (PLUS_EXPR, convert_from_reference (expr),
! 				binfo, 0);
  	if (TREE_CODE (exprtype) == POINTER_TYPE)
  	  expr = non_lvalue (expr);
  	return expr;
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/search.c,v
retrieving revision 1.216
diff -c -3 -p -r1.216 search.c
*** search.c	2001/11/15 15:09:39	1.216
--- search.c	2001/11/20 15:48:29
*************** struct vbase_info 
*** 83,89 ****
    tree inits;
  };
  
- static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *));
  static tree lookup_field_1 PARAMS ((tree, tree));
  static int is_subobject_of_p PARAMS ((tree, tree, tree));
  static tree dfs_check_overlap PARAMS ((tree, void *));
--- 83,88 ----
*************** static tree dfs_no_overlap_yet PARAMS ((
*** 91,96 ****
--- 90,98 ----
  static int get_base_distance_recursive
  	PARAMS ((tree, int, int, int, int *, tree *, tree,
  	       int, int *, int, int));
+ static base_kind lookup_base_recursive
+ 	PARAMS ((tree, tree, base_access,
+ 		 int, int, int, tree *));
  static int dynamic_cast_base_recurse PARAMS ((tree, tree, int, tree *));
  static tree marked_pushdecls_p PARAMS ((tree, void *));
  static tree unmarked_pushdecls_p PARAMS ((tree, void *));
*************** static int n_contexts_saved;
*** 169,244 ****
  #endif /* GATHER_STATISTICS */
  
  
- /* Get a virtual binfo that is found inside BINFO's hierarchy that is
-    the same type as the type given in PARENT.  To be optimal, we want
-    the first one that is found by going through the least number of
-    virtual bases.
- 
-    This uses a clever algorithm that updates *depth when we find the vbase,
-    and cuts off other paths of search when they reach that depth.  */
- 
- static tree
- get_vbase_1 (parent, binfo, depth)
-      tree parent, binfo;
-      unsigned int *depth;
- {
-   tree binfos;
-   int i, n_baselinks;
-   tree rval = NULL_TREE;
-   int virtualp = TREE_VIA_VIRTUAL (binfo) != 0;
- 
-   *depth -= virtualp;
-   if (virtualp && BINFO_TYPE (binfo) == parent)
-     {
-       *depth = 0;
-       return binfo;
-     }
- 
-   binfos = BINFO_BASETYPES (binfo);
-   n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- 
-   /* Process base types.  */
-   for (i = 0; i < n_baselinks; i++)
-     {
-       tree base_binfo = TREE_VEC_ELT (binfos, i);
-       tree nrval;
- 
-       if (*depth == 0)
- 	break;
- 
-       nrval = get_vbase_1 (parent, base_binfo, depth);
-       if (nrval)
- 	rval = nrval;
-     }
-   *depth += virtualp;
-   return rval;
- }
- 
- /* Return the shortest path to vbase PARENT within BINFO, ignoring
-    access and ambiguity.  */
- 
- tree
- get_vbase (parent, binfo)
-      tree parent;
-      tree binfo;
- {
-   unsigned int d = (unsigned int)-1;
-   return get_vbase_1 (parent, binfo, &d);
- }
- 
- /* Convert EXPR to a virtual base class of type TYPE.  We know that
-    EXPR is a non-null POINTER_TYPE to RECORD_TYPE.  We also know that
-    the type of what expr points to has a virtual base of type TYPE.  */
- 
- tree
- convert_pointer_to_vbase (type, expr)
-      tree type;
-      tree expr;
- {
-   tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))));
-   return convert_pointer_to_real (vb, expr);
- }
- 
  /* Check whether the type given in BINFO is derived from PARENT.  If
     it isn't, return 0.  If it is, but the derivation is MI-ambiguous
     AND protect != 0, emit an error message and return error_mark_node.
--- 171,176 ----
*************** get_base_distance_recursive (binfo, dept
*** 406,414 ****
     If PROTECT is greater than 1, ignore any special access the current
     scope might have when determining whether PARENT is inaccessible.
  
-    PARENT can also be a binfo, in which case that exact parent is found
-    and no other.  convert_pointer_to_real uses this functionality.
- 
     If BINFO is a binfo, its BINFO_INHERITANCE_CHAIN will be left alone.  */
  
  int
--- 338,343 ----
*************** get_base_distance (parent, binfo, protec
*** 471,476 ****
--- 400,576 ----
    if (path_ptr)
      *path_ptr = new_binfo;
    return rval;
+ }
+ 
+ static base_kind
+ lookup_base_recursive (binfo, base, access, within_current_scope,
+ 		       is_non_public, is_virtual, binfo_ptr)
+      tree binfo, base;
+      base_access access;
+      int within_current_scope;
+      int is_non_public;		/* inside a non-public part */
+      int is_virtual;		/* inside a virtual part */
+      tree *binfo_ptr;
+ {
+   int i;
+   tree bases;
+   base_kind found = bk_not_base;
+   
+   if (access == ba_check
+       && !within_current_scope
+       && is_friend (BINFO_TYPE (binfo), current_scope ()))
+     {
+       within_current_scope = 1;
+       is_non_public = 0;
+     }
+   
+   if (same_type_p (BINFO_TYPE (binfo), base))
+     {
+       /* We have found a base. Check against what we have found
+          already. */
+       found = bk_same_type;
+       if (is_virtual)
+ 	found = bk_via_virtual;
+       if (is_non_public)
+ 	found = bk_inaccessible;
+       
+       if (!*binfo_ptr)
+ 	*binfo_ptr = binfo;
+       else if (!is_virtual || !tree_int_cst_equal (BINFO_OFFSET (binfo),
+ 						   BINFO_OFFSET (*binfo_ptr)))
+ 	{
+ 	  if (access != ba_any)
+ 	    *binfo_ptr = NULL;
+ 	  else if (found != is_virtual)
+ 	    /* prefer a non-virtual base */
+ 	    *binfo_ptr = binfo;
+ 	  found = bk_ambig;
+ 	}
+       else if (found == bk_via_virtual)
+ 	*binfo_ptr = binfo;
+       
+       return found;
+     }
+   
+   bases = BINFO_BASETYPES (binfo);
+   if (!bases)
+     return bk_not_base;
+   
+   for (i = TREE_VEC_LENGTH (bases); i--;)
+     {
+       tree base_binfo = TREE_VEC_ELT (bases, i);
+       int this_non_public = is_non_public;
+       int this_virtual = is_virtual;
+ 
+       if (access <= ba_ignore)
+ 	; /* no change */
+       else if (TREE_VIA_PUBLIC (base_binfo))
+ 	; /* no change */
+       else if (access == ba_not_special)
+ 	this_non_public = 1;
+       else if (TREE_VIA_PROTECTED (base_binfo) && within_current_scope)
+ 	; /* no change */
+       else if (is_friend (BINFO_TYPE (binfo), current_scope ()))
+ 	; /* no change */
+       else
+ 	this_non_public = 1;
+       
+       if (TREE_VIA_VIRTUAL (base_binfo))
+ 	this_virtual = 1;
+       
+       base_kind bk = lookup_base_recursive (base_binfo, base,
+ 					    access, within_current_scope,
+ 					    this_non_public, this_virtual,
+ 					    binfo_ptr);
+ 
+       switch (bk)
+ 	{
+ 	case bk_ambig:
+ 	  if (access != ba_any)
+ 	    return bk;
+ 	  found = bk;
+ 	  break;
+ 	  
+ 	case bk_inaccessible:
+ 	  if (found == bk_not_base)
+ 	    found = bk;
+ 	  my_friendly_assert (found == bk_via_virtual
+ 			      || found == bk_inaccessible, 20010723);
+ 	  
+ 	  break;
+ 	  
+ 	case bk_same_type:
+ 	  bk = bk_proper_base;
+ 	  /* FALLTHROUGH */
+ 	case bk_proper_base:
+ 	  my_friendly_assert (found == bk_not_base, 20010723);
+ 	  found = bk;
+ 	  break;
+ 	  
+ 	case bk_via_virtual:
+ 	  my_friendly_assert (found == bk_not_base
+ 			      || found == bk_via_virtual
+ 			      || found == bk_inaccessible, 20010723);
+ 	  found = bk;
+ 	  break;
+ 	  
+ 	case bk_not_base:
+ 	  break;
+ 	}
+     }
+   return found;
+ }
+ 
+ /* Lookup BASE in the hierarchy dominated by T. Do access checking as
+    ACCESS specifies. Return the binfo we discover (which might not be
+    canonical). If KIND_PTR is non-NULL, fill with information about
+    what kind of base we discoveded.
+ 
+    Issue an error message if an inaccessible or ambiguous base is
+    discovered, and return error_mark_node. */
+ 
+ tree
+ lookup_base (t, base, access, kind_ptr)
+      tree t, base;
+      base_access access;
+      base_kind *kind_ptr;
+ {
+   tree binfo = NULL;		/* The binfo we've found so far. */
+   base_kind bk;
+ 
+   if (t == error_mark_node || base == error_mark_node)
+     {
+       if (kind_ptr)
+ 	*kind_ptr = bk_not_base;
+       return error_mark_node;
+     }
+   
+   t = TYPE_MAIN_VARIANT (t);
+   base = TYPE_MAIN_VARIANT (base);
+   
+   bk = lookup_base_recursive (TYPE_BINFO (t), base, access, 0, 0, 0, &binfo);
+ 
+   switch (bk)
+     {
+     case bk_inaccessible:
+       cp_error ("`%T' is an inaccessible base of `%T'", base, t);
+       binfo = error_mark_node;
+       break;
+     case bk_ambig:
+       if (access != ba_any)
+ 	{
+ 	  cp_error ("`%T' is an ambiguous base of `%T'", base, t);
+ 	  binfo = error_mark_node;
+ 	}
+       break;
+       
+     default:;
+     }
+   
+   if (kind_ptr)
+     *kind_ptr = bk;
+   
+   return binfo;
  }
  
  /* Worker function for get_dynamic_cast_base_type.  */
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.369
diff -c -3 -p -r1.369 typeck.c
*** typeck.c	2001/11/15 15:09:40	1.369
--- typeck.c	2001/11/20 15:48:30
*************** require_complete_type (value)
*** 116,123 ****
      {
        tree base, member = TREE_OPERAND (value, 1);
        tree basetype = TYPE_OFFSET_BASETYPE (type);
        my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305);
!       base = convert_pointer_to (basetype, current_class_ptr);
        value = build (COMPONENT_REF, TREE_TYPE (member),
  		     build_indirect_ref (base, NULL), member);
        return require_complete_type (value);
--- 116,126 ----
      {
        tree base, member = TREE_OPERAND (value, 1);
        tree basetype = TYPE_OFFSET_BASETYPE (type);
+       
        my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305);
!       basetype = lookup_base (current_class_type, basetype, ba_check, NULL);
!       base = build_base_path (PLUS_EXPR, current_class_ptr, basetype, 1);
!       
        value = build (COMPONENT_REF, TREE_TYPE (member),
  		     build_indirect_ref (base, NULL), member);
        return require_complete_type (value);
*************** build_component_ref (datum, component, b
*** 2208,2221 ****
        /* Handle base classes here...  */
        if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
  	{
! 	  tree addr = build_unary_op (ADDR_EXPR, datum, 0);
! 	  if (integer_zerop (addr))
  	    {
  	      error ("invalid reference to NULL ptr, use ptr-to-member instead");
  	      return error_mark_node;
  	    }
! 	  addr = convert_pointer_to (base, addr);
! 	  datum = build_indirect_ref (addr, NULL);
  	  if (datum == error_mark_node)
  	    return error_mark_node;
  	}
--- 2211,2225 ----
        /* Handle base classes here...  */
        if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
  	{
!  	  tree binfo = lookup_base (TREE_TYPE (datum), base, ba_check, NULL);
!  
! 	  if (TREE_CODE (datum) == INDIRECT_REF
! 	      && integer_zerop (TREE_OPERAND (datum, 0)))
  	    {
  	      error ("invalid reference to NULL ptr, use ptr-to-member instead");
  	      return error_mark_node;
  	    }
!  	  datum = build_base_path (PLUS_EXPR, datum, binfo, 1);
  	  if (datum == error_mark_node)
  	    return error_mark_node;
  	}
*************** build_x_function_call (function, params,
*** 2806,2813 ****
        if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE
  	  && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)))
  	{
  	  decl = build_unary_op (ADDR_EXPR, decl, 0);
! 	  decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
  	}
        else
  	decl = build_c_cast (ctypeptr, decl);
--- 2810,2820 ----
        if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE
  	  && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)))
  	{
+ 	  tree binfo = lookup_base (TREE_TYPE (decl), TREE_TYPE (ctypeptr),
+ 				    ba_check, NULL);
+ 	  
  	  decl = build_unary_op (ADDR_EXPR, decl, 0);
! 	  decl = build_base_path (PLUS_EXPR, decl, binfo, 1);
  	}
        else
  	decl = build_c_cast (ctypeptr, decl);
*************** get_member_function_from_ptrfunc (instan
*** 2826,2834 ****
       tree function;
  {
    if (TREE_CODE (function) == OFFSET_REF)
!     {
!       function = TREE_OPERAND (function, 1);
!     }
  
    if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
      {
--- 2833,2839 ----
       tree function;
  {
    if (TREE_CODE (function) == OFFSET_REF)
!     function = TREE_OPERAND (function, 1);
  
    if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
      {
*************** get_member_function_from_ptrfunc (instan
*** 2857,2870 ****
        fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
        basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
  
!       /* Convert down to the right base, before using the instance.  */
!       instance = convert_pointer_to_real (basetype, instance_ptr);
        if (instance == error_mark_node && instance_ptr != error_mark_node)
  	return instance;
  
        e3 = PFN_FROM_PTRMEMFUNC (function);
! 
!       vtbl = convert_pointer_to (ptr_type_node, instance);
        delta = cp_convert (ptrdiff_type_node,
  			  build_component_ref (function, delta_identifier,
  					       NULL_TREE, 0));
--- 2862,2879 ----
        fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
        basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
  
!       /* Convert down to the right base, before using the instance. */
!       instance = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)), basetype,
! 			      ba_check, NULL);
!       instance = build_base_path (PLUS_EXPR, instance_ptr, instance, 1);
        if (instance == error_mark_node && instance_ptr != error_mark_node)
  	return instance;
  
        e3 = PFN_FROM_PTRMEMFUNC (function);
!       
!       vtbl = build1 (NOP_EXPR, build_pointer_type (ptr_type_node), instance);
!       TREE_CONSTANT (vtbl) = TREE_CONSTANT (instance);
!       
        delta = cp_convert (ptrdiff_type_node,
  			  build_component_ref (function, delta_identifier,
  					       NULL_TREE, 0));
*************** build_component_addr (arg, argtype)
*** 4229,4236 ****
        /* Can't convert directly to ARGTYPE, since that
  	 may have the same pointer type as one of our
  	 baseclasses.  */
!       rval = build1 (NOP_EXPR, argtype,
! 		     convert_pointer_to (basetype, rval));
        TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
      }
    else
--- 4238,4248 ----
        /* Can't convert directly to ARGTYPE, since that
  	 may have the same pointer type as one of our
  	 baseclasses.  */
!       tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)), basetype,
! 				ba_check, NULL);
! 
!       rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
!       rval = build1 (NOP_EXPR, argtype, rval);
        TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
      }
    else
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.105
diff -c -3 -p -r1.105 typeck2.c
*** typeck2.c	2001/10/12 09:06:32	1.105
--- typeck2.c	2001/11/20 15:48:31
*************** build_scoped_ref (datum, basetype)
*** 997,1008 ****
       tree basetype;
  {
    tree ref;
  
    if (datum == error_mark_node)
      return error_mark_node;
  
    ref = build_unary_op (ADDR_EXPR, datum, 0);
!   ref = convert_pointer_to (basetype, ref);
  
    return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
  }
--- 997,1013 ----
       tree basetype;
  {
    tree ref;
+   tree binfo;
  
    if (datum == error_mark_node)
      return error_mark_node;
+   binfo = lookup_base (TREE_TYPE (datum), basetype, ba_check, NULL);
  
+   if (!binfo)
+     return error_not_base_type (TREE_TYPE (datum), basetype);
+   
    ref = build_unary_op (ADDR_EXPR, datum, 0);
!   ref = build_base_path (PLUS_EXPR, ref, binfo, 1);
  
    return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
  }
// { dg-options -w }
// { dg-do run }

// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 20 Nov 2001 <nathan@codesourcery.com>

// Origin stefan@space.twc.de
// Bug 3145 case 4. Horribly complicated class hierarchy

class C0
{};
class C1
 :  virtual public C0
{};
class C2
 :  public C0
 ,  public C1
{};
class C3
 :  virtual public C0
 ,  public C1
 ,  public C2
{};
class C4
 :  public C2
 ,  public C3
 ,  virtual public C1
 ,  virtual public C0
{};
class C5
 :  virtual public C2
 ,  public C1
 ,  public C0
{};
class C6
 :  virtual public C0
 ,  virtual public C5
 ,  public C1
 ,  public C3
 ,  public C4
{};
class C7
 :  public C6
 ,  virtual public C0
 ,  public C1
 ,  public C2
 ,  virtual public C4
{};
class C8
 :  public C2
 ,  virtual public C6
 ,  virtual public C7
 ,  public C5
 ,  public C3
 ,  virtual public C4
{};
class C9
 :  public C5
 ,  virtual public C3
 ,  virtual public C8
 ,  public C0
 ,  public C2
 ,  public C7
 ,  public C6
 ,  public C4
{};
main() {
  C0 c0;
  C1 c1;
  C2 c2;
  C3 c3;
  C4 c4;
  C5 c5;
  C6 c6;
  C7 c7;
  C8 c8;
  C9 c9;
}

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