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]

Re: [C++ PATCH] fix 3145


Mark Mitchell wrote:

> 
> I'm not sure I quite understand the interface.  Maybe this is the
> right comment, or at least something close:
> 
>   /* Convert EXPR (an expression whose type is `A' or `A*'
>      for some class type `A') to the base subobject `B' given by
>      BINFO.  The expression returned will be of type `B' or `B*', matching
>      the form provided in EXPR.  If CODE is PLUS_EXPR, `A' is derived
>      from `B'; if it is MINUS_EXPR `B' is derived from `A'.  (In the latter
>      case, there must be no virtual bases along the path from `A' to
>      `B'.)  NONNULL is true if EXPR is known to be non-NULL.  */
How's this?
! /* Convert to or from a base subobject.  EXPR is an expression of type
!    `A' or `A*', an expression of type `B' or `B*' is returned.  To
!    convert A to a base B, CODE is PLUS_EXPR and BINFO is the binfo for
!    the B base instance within A.  To convert base A to derived B, CODE
!    is MINUS_EXPR and BINFO is the binfo for the A instance within B.
!    In this latter case, A must not be a morally virtual base of B.
!    NONNULL is true if EXPR is known to be non-NULL (this is only
!    needed when EXPR is of pointer type).  CV qualifiers are preserved
!    from EXPR.  */
BTW, the CODE parameter could be inferred from BINFO, I just kept a
similar interface to that which build_vbase_path had. For derived->base
(PLUS_EXPR), TYPE_BINFO (BINFO) will not be the type of EXPR, for
base->derived (MINUS_EXPR) it will be. The nop case where we're
converting from A to A results in no code, so it doesn't matter what CODE
we pick.)  I could make that change, but the more verbose way adds that
extra consistency check.

> !         /* 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))
> 
> Where did this check go in the new code?  Or is it no longer necessary?
It is no longer necessary, (A*)(B*)0 does indeed result in no code.

+ /* Worker for lookup_base.  BINFO is the binfo we are searching at,
+    BASE is the RECORD_TYPE we are searching for.  ACCESS is the
+    required access checks.  WITHIN_CURRENT_SCOPE, IS_NON_PUBLIC and
+    IS_VIRTUAL indicate how BINFO was reached from the start of the
+    search.  WITHIN_CURRENT_SCOPE is true if we met the current scope,
+    or friend thereof (this allows us to determine whether a protected
+    base is accessible or not).  IS_NON_PUBLIC indicates whether BINFO
+    is accessible and IS_VIRTUAL indicates if it is morally virtual.
+ 
+    If BINFO is of the required type, then *BINFO_PTR is examined to
+    compare with any other instance of BASE we might have already
+    discovered. *BINFO_PTR is initialized and a base_kind return value
+    indicates what kind of base was located.
+ 
+    Otherwise BINFO's bases are searched.  */
+ 
+ static base_kind
+ lookup_base_r (binfo, base, access, within_current_scope,
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-22  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.287
diff -c -3 -p -r1.287 call.c
*** call.c	2001/11/20 09:00:31	1.287
--- call.c	2001/11/22 12:02:47
*************** 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)
*** 4157,4163 ****
           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);
--- 4160,4168 ----
           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)
*** 4307,4315 ****
    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));
--- 4312,4323 ----
    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/22 12:02:50
*************** 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,356 ----
  int n_inner_fields_searched = 0;
  #endif
  
! /* Convert to or from a base subobject.  EXPR is an expression of type
!    `A' or `A*', an expression of type `B' or `B*' is returned.  To
!    convert A to a base B, CODE is PLUS_EXPR and BINFO is the binfo for
!    the B base instance within A.  To convert base A to derived B, CODE
!    is MINUS_EXPR and BINFO is the binfo for the A instance within B.
!    In this latter case, A must not be a morally virtual base of B.
!    NONNULL is true if EXPR is known to be non-NULL (this is only
!    needed when EXPR is of pointer type).  CV qualifiers are preserved
!    from EXPR.  */
  
  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.  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.
--- 5399,5410 ----
      }
  }
  
! /* 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.655
diff -c -3 -p -r1.655 cp-tree.h
*** cp-tree.h	2001/11/16 19:17:32	1.655
--- cp-tree.h	2001/11/22 12:02:51
*************** typedef enum instantiate_type_flags {
*** 3022,3027 ****
--- 3022,3050 ----
    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,
+ 		      prefer a non-virtual 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 ****
--- 3535,3541 ----
  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           
*** 3558,3565 ****
  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*/));
--- 3582,3587 ----
*************** extern int tinfo_decl_p                 
*** 3984,3989 ****
--- 4006,4012 ----
  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_
*** 4034,4040 ****
  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));
--- 4057,4062 ----
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/22 12:02:51
*************** 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/22 12:02:53
*************** 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/22 12:02:53
*************** 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/22 12:02:54
*************** 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_r
+ 	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,592 ----
    if (path_ptr)
      *path_ptr = new_binfo;
    return rval;
+ }
+ 
+ /* Worker for lookup_base.  BINFO is the binfo we are searching at,
+    BASE is the RECORD_TYPE we are searching for.  ACCESS is the
+    required access checks.  WITHIN_CURRENT_SCOPE, IS_NON_PUBLIC and
+    IS_VIRTUAL indicate how BINFO was reached from the start of the
+    search.  WITHIN_CURRENT_SCOPE is true if we met the current scope,
+    or friend thereof (this allows us to determine whether a protected
+    base is accessible or not).  IS_NON_PUBLIC indicates whether BINFO
+    is accessible and IS_VIRTUAL indicates if it is morally virtual.
+ 
+    If BINFO is of the required type, then *BINFO_PTR is examined to
+    compare with any other instance of BASE we might have already
+    discovered. *BINFO_PTR is initialized and a base_kind return value
+    indicates what kind of base was located.
+ 
+    Otherwise BINFO's bases are searched.  */
+ 
+ static base_kind
+ lookup_base_r (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_r (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_r (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.370
diff -c -3 -p -r1.370 typeck.c
*** typeck.c	2001/11/20 05:09:33	1.370
--- typeck.c	2001/11/22 12:02:56
*************** 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/22 12:02:56
*************** 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)");
  }

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