re PR c++/3145 (virtual inheritance still creates wrong code)
authorNathan Sidwell <nathan@codesourcery.com>
Sun, 25 Nov 2001 13:21:45 +0000 (13:21 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Sun, 25 Nov 2001 13:21:45 +0000 (13:21 +0000)
cp:
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.
testsuite:
* g++.dg/abi/vbase8-4.C: New test.

From-SVN: r47316

12 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/init.c
gcc/cp/rtti.c
gcc/cp/search.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/vbase8-4.C [new file with mode: 0644]

index a3856da7f4ab8417d69b7c59e584fc9cc58c3889..3512f20ae8c6da61da0dc39d0387a566f27c9cc7 100644 (file)
@@ -1,3 +1,46 @@
+2001-11-25  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.
+
 2001-11-22  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>
 
        * cp-tree.h (CP_TYPE_QUALS): Removed.
index 46aacca2f0498ad8029fbc98f04df4180d24a98a..c0ab2c2191d1d19e981111c16f64e736f425f616 100644 (file)
@@ -298,7 +298,7 @@ build_scoped_method_call (exp, basetype, name, parms)
 
   if (! binfo)
     {
-      binfo = get_binfo (basetype, type, 1);
+      binfo = lookup_base (type, basetype, ba_check, NULL);
       if (binfo == error_mark_node)
        return error_mark_node;
       if (! binfo)
@@ -308,9 +308,12 @@ build_scoped_method_call (exp, basetype, name, parms)
   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);
+       {
+         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);
 
@@ -4157,7 +4160,9 @@ build_over_call (cand, args, flags)
          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));
+      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);
@@ -4307,9 +4312,12 @@ build_over_call (cand, args, flags)
   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);
+      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 68ab3a3c9348d2d536d9a2132ec50ed74c737b66..3afaf5d75da8597c546661405b3bc8f6e47945dc 100644 (file)
@@ -106,7 +106,6 @@ varray_type local_classes;
 
 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));
@@ -236,190 +235,122 @@ int n_build_method_call = 0;
 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.  */
+/* 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_vbase_path (code, type, expr, path, nonnull)
+build_base_path (code, expr, binfo, nonnull)
      enum tree_code code;
-     tree type, expr, path;
+     tree expr;
+     tree binfo;
      int nonnull;
 {
-  register int changed = 0;
-  tree last = NULL_TREE, last_virtual = NULL_TREE;
+  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;
-  tree null_expr = 0, nonnull_expr;
-  tree basetype;
-  tree offset = integer_zero_node;
+  int want_pointer = TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE;
 
-  if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
-    return build1 (NOP_EXPR, type, expr);
+  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;
+    }
 
-  /* 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 (!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)
     {
-      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.  */
+      /* 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)));
 
-  /* 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);
+      if (!integer_zerop (offset))
+       offset = build (code, ptrdiff_type_node, v_offset, offset);
+      else
+       offset = v_offset;
     }
-  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));
+  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 (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last))
-       offset
-         = BINFO_OFFSET (get_binfo (last, TYPE_MAIN_VARIANT (intype), 0));
-    }
+  if (!integer_zerop (offset))
+    expr = build (code, ptr_target_type, expr, offset);
   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);
-    }
+    null_test = NULL;
+  
+  if (!want_pointer)
+    expr = build_indirect_ref (expr, NULL);
 
-  /* 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);
+  if (null_test)
+    expr = build (COND_EXPR, target_type, null_test,
+                 build1 (NOP_EXPR, target_type, integer_zero_node),
+                 expr);
+  
+  return expr;
 }
 
 \f
@@ -5468,11 +5399,12 @@ fixed_type_or_null (instance, nonnull, cdtorp)
     }
 }
 
-/* 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.
+/* 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 4b39e804172b0b0f45c764c4008cfdcda74062cf..f82e4fe901b7e2e559f7ac3b531bc5d365ca3535 100644 (file)
@@ -3018,6 +3018,29 @@ typedef enum instantiate_type_flags {
   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;
 
@@ -3508,6 +3531,7 @@ extern tree strip_top_quals                     PARAMS ((tree));
 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));
@@ -3554,8 +3578,6 @@ extern tree get_primary_binfo                   PARAMS ((tree));
 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*/));
@@ -3980,6 +4002,7 @@ extern int tinfo_decl_p                         PARAMS((tree, void *));
 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));
@@ -4030,7 +4053,6 @@ extern tree dfs_marked_real_bases_queue_p       PARAMS ((tree, void *));
 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));
index 3ab60b63f8f8acd0fc0b5185ec5e31c4a57d1562..e2b9f3932534ebbd3026f741f8e4ea459ea01380 100644 (file)
@@ -141,44 +141,35 @@ cp_convert_to_pointer (type, expr, force)
          && 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))
+         && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
        {
          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)
+         tree binfo;
+
+         /* Try derived to base conversion. */
+         binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type),
+                              ba_check, NULL);
+         if (!binfo)
            {
-             binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 1);
-             if (binfo == error_mark_node)
-               return error_mark_node;
+             /* 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)
            {
-             if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (type))
-                 || TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (intype))
-                 || ! BINFO_OFFSET_ZEROP (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)))
                {
-                 /* 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);
+                 expr = build1 (NOP_EXPR, type, expr);
+                 TREE_CONSTANT (expr) =
+                   TREE_CONSTANT (TREE_OPERAND (expr, 0));
                }
+             return expr;
            }
        }
 
@@ -187,36 +178,29 @@ cp_convert_to_pointer (type, expr, force)
          tree b1; 
          tree b2;
          tree binfo;
-         tree virt_binfo;
-         enum tree_code code;
+         enum tree_code code = PLUS_EXPR;
+         base_kind bk;
 
          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 = lookup_base (b1, b2, ba_check, &bk);
+         if (!binfo)
            {
-             binfo = get_binfo (b1, b2, 1);
+             binfo = lookup_base (b2, b1, ba_check, &bk);
              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 (bk == bk_via_virtual)
            {
              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)));
+               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 via virtual base `%T' of `%T'",
-                           BINFO_TYPE (virt_binfo),
-                            BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+                 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.
@@ -319,34 +303,32 @@ convert_to_pointer_force (type, expr)
          && 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)
+         tree binfo;
+
+         binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type),
+                              ba_ignore, NULL);
+         if (!binfo)
            {
-             cp_error ("type `%T' is ambiguous base of `%T'",
-                       TREE_TYPE (type),
-                       TREE_TYPE (intype));
-             return error_mark_node;
+             binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
+                                  ba_ignore, NULL);
+             code = MINUS_EXPR;
            }
-         if (distance == -1)
+         if (binfo == error_mark_node)
+           return error_mark_node;
+         if (binfo)
            {
-             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;
+             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;
            }
-         return build_vbase_path (code, type, expr, path, 0);
+         
        }
     }
 
@@ -420,12 +402,12 @@ build_up_reference (type, arg, flags, decl)
       && IS_AGGR_TYPE (target_type))
     {
       /* We go through get_binfo for the access control.  */
-      tree binfo = get_binfo (target_type, argtype, 1);
+      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 = convert_pointer_to_real (binfo, rval);
+      rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
     }
   else
     rval
@@ -626,87 +608,6 @@ convert_lvalue (totype, expr)
   return convert_from_reference (expr);
 }
 \f
-/* 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);
-}
-\f
 /* C++ conversions, preference to static cast conversions.  */
 
 tree
index ffbe8221309aa448a2ac28b7ede03fab0a2d4c51..75ba05a3bd6c70416101cfc50475dfa7b9383ca7 100644 (file)
@@ -130,7 +130,9 @@ finish_init_stmts (stmt_expr, compound_stmt)
 
 /* Constructors */
 
-/* Called from initialize_vtbl_ptrs via dfs_walk.  */
+/* 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)
@@ -142,16 +144,7 @@ dfs_initialize_vtbl_ptrs (binfo, data)
     {
       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);
+      base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1);
 
       expand_virtual_init (binfo, base_ptr);
     }
@@ -711,7 +704,8 @@ emit_base_init (mem_init_list, base_init_list)
 
       if (init != void_list_node)
        {
-         member = convert_pointer_to_real (base_binfo, current_class_ptr);
+         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);
@@ -802,15 +796,9 @@ static void
 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);
 
@@ -842,10 +830,9 @@ expand_virtual_init (binfo, decl)
     }
 
   /* 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;
+  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);
@@ -1842,14 +1829,14 @@ resolve_offset_ref (exp)
       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)
+      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),
-                   build_indirect_ref (addr, NULL), member);
+                   expr, member);
       return convert_from_reference (expr);
     }
 
@@ -1872,7 +1859,10 @@ resolve_offset_ref (exp)
        }
 
       basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
-      addr = convert_pointer_to (basetype, addr);
+      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 ae9600c648d4031d1f54a04cf726bd866c24b4da..3510cc10b380f3eeebb7574c6cd079aaa9af91da 100644 (file)
@@ -472,28 +472,15 @@ build_dynamic_cast_1 (type, expr)
   /* If *type is an unambiguous accessible base class of *exprtype,
      convert statically.  */
   {
-    int distance;
-    tree path;
+    tree binfo;
 
-    distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,
-                                 &path);
+    binfo = lookup_base (TREE_TYPE (exprtype), TREE_TYPE (type),
+                        ba_not_special, NULL);
 
-    if (distance == -2)
+    if (binfo)
       {
-       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);
+       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 e09aa23ff3ba54138e3dbd8a7913dfd14831f8dd..3bc6d9dbfbcf938b6252e11d1b28b6e5c9618d7b 100644 (file)
@@ -83,7 +83,6 @@ struct vbase_info
   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 *));
@@ -91,6 +90,9 @@ static tree dfs_no_overlap_yet PARAMS ((tree, void *));
 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 *));
@@ -169,76 +171,6 @@ static int n_contexts_saved;
 #endif /* GATHER_STATISTICS */
 
 \f
-/* 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.
@@ -406,9 +338,6 @@ get_base_distance_recursive (binfo, depth, is_private, rval,
    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
@@ -473,6 +402,193 @@ get_base_distance (parent, binfo, protect, path_ptr)
   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.  */
 
 static int
index c4c0e10d0785f98b8a9ccbc106ee0dccb1a9e28b..ddd4fc75508ee5e99032c869a4e98495552ccd94 100644 (file)
@@ -116,8 +116,11 @@ require_complete_type (value)
     {
       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);
+      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);
@@ -2208,14 +2211,15 @@ build_component_ref (datum, component, basetype_path, protect)
       /* 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))
+         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;
            }
-         addr = convert_pointer_to (base, addr);
-         datum = build_indirect_ref (addr, NULL);
+         datum = build_base_path (PLUS_EXPR, datum, binfo, 1);
          if (datum == error_mark_node)
            return error_mark_node;
        }
@@ -2806,8 +2810,11 @@ build_x_function_call (function, params, decl)
       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 = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
+         decl = build_base_path (PLUS_EXPR, decl, binfo, 1);
        }
       else
        decl = build_c_cast (ctypeptr, decl);
@@ -2826,9 +2833,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
      tree function;
 {
   if (TREE_CODE (function) == OFFSET_REF)
-    {
-      function = TREE_OPERAND (function, 1);
-    }
+    function = TREE_OPERAND (function, 1);
 
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
     {
@@ -2857,14 +2862,18 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       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);
+      /* 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 = convert_pointer_to (ptr_type_node, instance);
+      
+      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));
@@ -4229,8 +4238,11 @@ build_component_addr (arg, argtype)
       /* 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 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 8281b34de4991a35abffda8aba728fbacc7f364e..39e047927c08137d61646567db5e10acf7b50aee 100644 (file)
@@ -997,12 +997,17 @@ build_scoped_ref (datum, basetype)
      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 = convert_pointer_to (basetype, ref);
+  ref = build_base_path (PLUS_EXPR, ref, binfo, 1);
 
   return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
 }
index 885d0918641bf5d0be2eb8521550239825c1633f..c1a7fdeb1db36b9da51a60a0143f1e25b4e77600 100644 (file)
@@ -1,3 +1,7 @@
+2001-11-25  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.dg/abi/vbase8-4.C: New test.
+
 2001-11-24  Ian Lance Taylor  <ian@airs.com>
 
        * gcc.c-torture/execute/20011121-1.c: New test.
diff --git a/gcc/testsuite/g++.dg/abi/vbase8-4.C b/gcc/testsuite/g++.dg/abi/vbase8-4.C
new file mode 100644 (file)
index 0000000..2e816f6
--- /dev/null
@@ -0,0 +1,78 @@
+// { 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;
+}