Refer to base members using COMPONENT_REFs where possible.
authorJason Merrill <jason@redhat.com>
Fri, 30 Apr 2004 17:25:42 +0000 (13:25 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 30 Apr 2004 17:25:42 +0000 (13:25 -0400)
        * class.c (build_simple_base_path): New fn.
        (build_base_path): Use it for non-virtual base references.
        (layout_class_type): Change base fields to their real type
        after layout is done.
        * cp-tree.h (IS_FAKE_BASE_TYPE): New macro.
        * cp-lang.c (cxx_get_alias_set): Use it.

From-SVN: r81349

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-lang.c
gcc/cp/cp-tree.h

index 2eaab1c67ae7616ac044745c00ae774a76574e84..0f0a5e2cf7fb55383a93cc9a4d07ba6f300aee33 100644 (file)
@@ -1,3 +1,13 @@
+2004-04-30  Jason Merrill  <jason@redhat.com>
+
+       Refer to base members using COMPONENT_REFs where possible.
+       * class.c (build_simple_base_path): New fn.
+       (build_base_path): Use it for non-virtual base references.
+       (layout_class_type): Change base fields to their real type
+       after layout is done.
+       * cp-tree.h (IS_FAKE_BASE_TYPE): New macro.
+       * cp-lang.c (cxx_get_alias_set): Use it.
+
 2004-04-30  Kazu Hirata  <kazu@cs.umass.edu>
 
        * class.c, cp-tree.h, decl.c, decl2.c, pt.c, rtti.c: Fix
index 42310338abe21d821f35e187215ddc1e4d0a0eaa..13d6d03c9a595d6a9c32bbcd1e3d2c2f91bed087 100644 (file)
@@ -129,6 +129,7 @@ static void add_implicitly_declared_members (tree, int, int, int);
 static tree fixed_type_or_null (tree, int *, int *);
 static tree resolve_address_of_overloaded_function (tree, tree, tsubst_flags_t,
                                                    bool, tree);
+static tree build_simple_base_path (tree expr, tree binfo);
 static tree build_vtbl_ref_1 (tree, tree);
 static tree build_vtbl_initializer (tree, tree, tree, tree, int *);
 static int count_fields (tree);
@@ -253,6 +254,7 @@ build_base_path (enum tree_code code,
   tree ptr_target_type;
   int fixed_type_p;
   int want_pointer = TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE;
+  bool has_empty = false;
 
   if (expr == error_mark_node || binfo == error_mark_node || !binfo)
     return error_mark_node;
@@ -260,6 +262,8 @@ build_base_path (enum tree_code code,
   for (probe = binfo; probe; probe = BINFO_INHERITANCE_CHAIN (probe))
     {
       d_binfo = probe;
+      if (is_empty_class (BINFO_TYPE (probe)))
+       has_empty = true;
       if (!v_binfo && TREE_VIA_VIRTUAL (probe))
        v_binfo = probe;
     }
@@ -267,13 +271,17 @@ build_base_path (enum tree_code code,
   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 (d_binfo), probe)
                      : false, 20010723);
   
+  if (binfo == d_binfo)
+    /* Nothing to do.  */
+    return expr;
+
   if (code == MINUS_EXPR && v_binfo)
     {
       error ("cannot convert from base `%T' to derived type `%T' via virtual base `%T'",
@@ -285,16 +293,36 @@ build_base_path (enum tree_code code,
     /* This must happen before the call to save_expr.  */
     expr = build_unary_op (ADDR_EXPR, expr, 0);
 
+  offset = BINFO_OFFSET (binfo);
   fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
-  if (fixed_type_p <= 0 && TREE_SIDE_EFFECTS (expr))
+
+  if (want_pointer && !nonnull
+      && (!integer_zerop (offset) || (v_binfo && fixed_type_p <= 0)))
+    null_test = error_mark_node;
+
+  if (TREE_SIDE_EFFECTS (expr)
+      && (null_test || (v_binfo && fixed_type_p <= 0)))
     expr = save_expr (expr);
 
-  if (want_pointer && !nonnull)
+  if (null_test)
     null_test = fold (build2 (NE_EXPR, boolean_type_node,
                              expr, integer_zero_node));
-  
-  offset = BINFO_OFFSET (binfo);
-  
+
+  /* If this is a simple base reference, express it as a COMPONENT_REF.  */
+  if (code == PLUS_EXPR
+      && (v_binfo == NULL_TREE || fixed_type_p > 0)
+      /* We don't build base fields for empty bases, and they aren't very
+        interesting to the optimizers anyway.  */
+      && !has_empty)
+    {
+      expr = build_indirect_ref (expr, NULL);
+      expr = build_simple_base_path (expr, binfo);
+      if (want_pointer)
+       expr = build_unary_op (ADDR_EXPR, expr, 0);
+      target_type = TREE_TYPE (expr);
+      goto out;
+    }
+
   if (v_binfo && fixed_type_p <= 0)
     {
       /* Going via virtual base V_BINFO.  We need the static offset
@@ -365,6 +393,7 @@ build_base_path (enum tree_code code,
   if (!want_pointer)
     expr = build_indirect_ref (expr, NULL);
 
+ out:
   if (null_test)
     expr = fold (build3 (COND_EXPR, target_type, null_test, expr,
                         fold (build1 (NOP_EXPR, target_type,
@@ -373,6 +402,47 @@ build_base_path (enum tree_code code,
   return expr;
 }
 
+/* Subroutine of build_base_path; EXPR and BINFO are as in that function.
+   Perform a derived-to-base conversion by recursively building up a
+   sequence of COMPONENT_REFs to the appropriate base fields.  */
+
+static tree
+build_simple_base_path (tree expr, tree binfo)
+{
+  tree type = BINFO_TYPE (binfo);
+  tree d_binfo;
+  tree field;
+
+  /* For primary virtual bases, we can't just follow
+     BINFO_INHERITANCE_CHAIN.  */
+  d_binfo = BINFO_PRIMARY_BASE_OF (binfo);
+  if (d_binfo == NULL_TREE)
+    d_binfo = BINFO_INHERITANCE_CHAIN (binfo);
+
+  if (d_binfo == NULL_TREE)
+    {
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (expr)) != type)
+       abort ();
+      return expr;
+    }
+
+  /* Recurse.  */
+  expr = build_simple_base_path (expr, d_binfo);
+
+  for (field = TYPE_FIELDS (BINFO_TYPE (d_binfo));
+       field; field = TREE_CHAIN (field))
+    /* Is this the base field created by build_base_field?  */
+    if (TREE_CODE (field) == FIELD_DECL
+       && TREE_TYPE (field) == type
+       && DECL_ARTIFICIAL (field)
+       && DECL_IGNORED_P (field))
+      return build_class_member_access_expr (expr, field,
+                                            NULL_TREE, false);
+
+  /* Didn't find the base field?!?  */
+  abort ();
+}
+
 /* Convert OBJECT to the base TYPE.  If CHECK_ACCESS is true, an error
    message is emitted if TYPE is inaccessible.  OBJECT is assumed to
    be non-NULL.  */
@@ -4885,6 +4955,11 @@ layout_class_type (tree t, tree *virtuals_p)
   /* Warn about bases that can't be talked about due to ambiguity.  */
   warn_about_ambiguous_bases (t);
 
+  /* Now that we're done with layout, give the base fields the real types.  */
+  for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+    if (DECL_ARTIFICIAL (field) && IS_FAKE_BASE_TYPE (TREE_TYPE (field)))
+      TREE_TYPE (field) = TYPE_CONTEXT (TREE_TYPE (field));
+
   /* Clean up.  */
   splay_tree_delete (empty_base_offsets);
 }
index bbe91707dd7575debbc569b36249d752c518bf98..3c2a311e9ca109a52f47d8c6e37ac8714b324579 100644 (file)
@@ -292,9 +292,7 @@ ok_to_generate_alias_set_for_type (tree t)
 static HOST_WIDE_INT
 cxx_get_alias_set (tree t)
 {
-  if (TREE_CODE (t) == RECORD_TYPE
-      && TYPE_CONTEXT (t) && CLASS_TYPE_P (TYPE_CONTEXT (t))
-      && CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t)
+  if (IS_FAKE_BASE_TYPE (t))
     /* The base variant of a type must be in the same alias set as the
        complete type.  */
     return get_alias_set (TYPE_CONTEXT (t));
index fb02e41ec56e95ea7e3b7fc3fb9d8265e3a96b2f..c3c7c868e25f229ccb865e6bf938b93020c70456 100644 (file)
@@ -1302,6 +1302,13 @@ struct lang_type GTY(())
 
 #define CLASSTYPE_AS_BASE(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->as_base)
 
+/* True iff NODE is the CLASSTYPE_AS_BASE version of some type.  */
+
+#define IS_FAKE_BASE_TYPE(NODE)                                        \
+  (TREE_CODE (NODE) == RECORD_TYPE                             \
+   && TYPE_CONTEXT (NODE) && CLASS_TYPE_P (TYPE_CONTEXT (NODE))        \
+   && CLASSTYPE_AS_BASE (TYPE_CONTEXT (NODE)) == (NODE))
+
 /* These are the size and alignment of the type without its virtual
    base classes, for when we use this type as a base itself.  */
 #define CLASSTYPE_SIZE(NODE) TYPE_SIZE (CLASSTYPE_AS_BASE (NODE))