static void check_field_decl PARAMS ((tree, tree, int *, int *, int *, int *));
static void check_field_decls PARAMS ((tree, tree *, int *, int *, int *,
int *));
-static void build_base_field PARAMS ((record_layout_info, tree, int *,
+static bool build_base_field PARAMS ((record_layout_info, tree, int *,
+ splay_tree));
+static bool build_base_fields PARAMS ((record_layout_info, int *,
splay_tree));
-static void build_base_fields PARAMS ((record_layout_info, int *,
- splay_tree));
static tree build_vbase_pointer_fields PARAMS ((record_layout_info, int *));
static tree build_vtbl_or_vbase_field PARAMS ((tree, tree, tree, tree, tree,
int *));
tree, tree,
splay_tree));
static unsigned HOST_WIDE_INT end_of_class PARAMS ((tree, int));
-static void layout_empty_base PARAMS ((tree, tree, splay_tree));
+static bool layout_empty_base PARAMS ((tree, tree, splay_tree));
static void accumulate_vtbl_inits PARAMS ((tree, tree, tree, tree, tree));
static tree dfs_accumulate_vtbl_inits PARAMS ((tree, tree, tree, tree,
tree));
static tree dfs_unshared_virtual_bases (binfo, data)
tree binfo;
- void *data;
+ void *data ATTRIBUTE_UNUSED;
{
if (TREE_VIA_VIRTUAL (binfo) && !BINFO_MARKED (binfo)
&& CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
/* Layout the empty base BINFO. EOC indicates the byte currently just
past the end of the class, and should be correctly aligned for a
class of the type indicated by BINFO; OFFSETS gives the offsets of
- the empty bases allocated so far. */
+ the empty bases allocated so far. Return non-zero iff we added it
+ at the end. */
-static void
+static bool
layout_empty_base (binfo, eoc, offsets)
tree binfo;
tree eoc;
{
tree alignment;
tree basetype = BINFO_TYPE (binfo);
+ bool atend = false;
/* This routine should only be used for empty classes. */
my_friendly_assert (is_empty_class (basetype), 20000321);
{
/* That didn't work. Now, we move forward from the next
available spot in the class. */
+ atend = true;
propagate_binfo_offsets (binfo, convert (ssizetype, eoc));
while (1)
{
propagate_binfo_offsets (binfo, alignment);
}
}
+ return atend;
}
/* Build a FIELD_DECL for the base given by BINFO in the class
indicated by RLI. If the new object is non-empty, clear *EMPTY_P.
*BASE_ALIGN is a running maximum of the alignments of any base
- class. OFFSETS gives the location of empty base subobjects. */
+ class. OFFSETS gives the location of empty base subobjects. Return
+ non-zero if the new object cannot be nearly-empty. */
-static void
+static bool
build_base_field (rli, binfo, empty_p, offsets)
record_layout_info rli;
tree binfo;
{
tree basetype = BINFO_TYPE (binfo);
tree decl;
+ bool atend = false;
if (!COMPLETE_TYPE_P (basetype))
/* This error is now reported in xref_tag, thus giving better
location information. */
- return;
+ return atend;
decl = build_decl (FIELD_DECL, NULL_TREE, basetype);
DECL_ARTIFICIAL (decl) = 1;
byte-aligned. */
eoc = tree_low_cst (rli_size_unit_so_far (rli), 0);
eoc = CEIL (eoc, DECL_ALIGN_UNIT (decl)) * DECL_ALIGN_UNIT (decl);
- layout_empty_base (binfo, size_int (eoc), offsets);
+ atend |= layout_empty_base (binfo, size_int (eoc), offsets);
}
/* Record the offsets of BINFO and its base subobjects. */
BINFO_OFFSET (binfo),
offsets,
/*vbases_p=*/0);
+ return atend;
}
/* Layout all of the non-virtual base classes. Record empty
- subobjects in OFFSETS. */
+ subobjects in OFFSETS. Return non-zero if the type cannot be nearly
+ empty. */
-static void
+static bool
build_base_fields (rli, empty_p, offsets)
record_layout_info rli;
int *empty_p;
tree rec = rli->t;
int n_baseclasses = CLASSTYPE_N_BASECLASSES (rec);
int i;
+ bool atend = 0;
/* Under the new ABI, the primary base class is always allocated
first. */
&& !BINFO_PRIMARY_P (base_binfo))
continue;
- build_base_field (rli, base_binfo, empty_p, offsets);
+ atend |= build_base_field (rli, base_binfo, empty_p, offsets);
}
+ return atend;
}
/* Go through the TYPE_METHODS of T issuing any appropriate
multiple such bases at the same location. */
eoc = end_of_class (t, /*include_virtuals_p=*/1);
if (eoc * BITS_PER_UNIT > dsize)
- dsize = (eoc + 1) * BITS_PER_UNIT;
+ dsize = eoc * BITS_PER_UNIT;
/* Now, make sure that the total size of the type is a multiple of
its alignment. */
{
tree base_binfo;
tree offset;
+ tree size;
unsigned HOST_WIDE_INT end_of_base;
base_binfo = BINFO_BASETYPE (TYPE_BINFO (t), i);
&& !BINFO_PRIMARY_P (base_binfo))
continue;
+ if (is_empty_class (BINFO_TYPE (base_binfo)))
+ /* An empty class has zero CLASSTYPE_SIZE_UNIT, but we need to
+ allocate some space for it. It cannot have virtual bases,
+ so TYPE_SIZE_UNIT is fine. */
+ size = TYPE_SIZE_UNIT (BINFO_TYPE (base_binfo));
+ else
+ size = CLASSTYPE_SIZE_UNIT (BINFO_TYPE (base_binfo));
offset = size_binop (PLUS_EXPR,
BINFO_OFFSET (base_binfo),
- CLASSTYPE_SIZE_UNIT (BINFO_TYPE (base_binfo)));
+ size);
end_of_base = tree_low_cst (offset, /*pos=*/1);
if (end_of_base > result)
result = end_of_base;
/* Build FIELD_DECLs for all of the non-virtual base-types. */
empty_base_offsets = splay_tree_new (splay_tree_compare_integer_csts,
NULL, NULL);
- build_base_fields (rli, empty_p, empty_base_offsets);
+ if (build_base_fields (rli, empty_p, empty_base_offsets))
+ CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
+
/* Add pointers to all of our virtual base-classes. */
TYPE_FIELDS (t) = chainon (build_vbase_pointer_fields (rli, empty_p),
TYPE_FIELDS (t));
if (TREE_CODE (rli_size_unit_so_far (rli)) == INTEGER_CST
&& compare_tree_int (rli_size_unit_so_far (rli), eoc) < 0)
{
- rli->offset = size_binop (MAX_EXPR, rli->offset, size_int (eoc + 1));
+ rli->offset = size_binop (MAX_EXPR, rli->offset, size_int (eoc));
rli->bitpos = bitsize_zero_node;
}
if it has basetypes. Therefore, we add the fake field after all
the other fields; if there are already FIELD_DECLs on the list,
their offsets will not be disturbed. */
- if (*empty_p)
+ if (!eoc && *empty_p)
{
tree padding;
error ("could not open dump file `%s'", name);
return;
}
- fprintf (stream, "%s\n",
- type_as_string (t, TFF_PLAIN_IDENTIFIER));
+ fprintf (stream, "%s size=", type_as_string (t, TFF_PLAIN_IDENTIFIER));
+ fprintf (stream, HOST_WIDE_INT_PRINT_DEC,
+ tree_low_cst (TYPE_SIZE (t), 0) / BITS_PER_UNIT);
+ fprintf (stream, " align=%lu\n",
+ (unsigned long)(TYPE_ALIGN (t) / BITS_PER_UNIT));
dump_class_hierarchy_r (stream, t, TYPE_BINFO (t), 0);
fprintf (stream, "\n");
if (name)
--- /dev/null
+// Build don't link:
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 12 Apr 2001 <nathan@codesourcery.com>
+
+// Check we deal with trailing empty base classes properly
+
+struct A {};
+struct B1 : A {};
+struct B2 : A {};
+struct B3 : A {};
+struct B4 : A {};
+struct B5 : A {};
+struct B6 : A {};
+struct B7 : A {};
+struct B8 : A {};
+
+struct C1 : B1
+{
+ virtual void Foo () {};
+};
+struct C2 : B1, B2
+{
+ virtual void Foo () {};
+};
+struct C3 : B1, B2, B3
+{
+ virtual void Foo () {};
+};
+struct C4 : B1, B2, B3, B4
+{
+ virtual void Foo () {};
+};
+struct C5 : B1, B2, B3, B4, B5
+{
+ virtual void Foo () {};
+};
+struct C6 : B1, B2, B3, B4, B5, B6
+{
+ virtual void Foo () {};
+};
+struct C7 : B1, B2, B3, B4, B5, B6, B7
+{
+ virtual void Foo () {};
+};
+struct C8 : B1, B2, B3, B4, B5, B6, B7, B8
+{
+ virtual void Foo () {};
+};
+
+struct D1 : virtual C1 {};
+struct D2 : virtual C2 {};
+struct D3 : virtual C3 {};
+struct D4 : virtual C4 {};
+struct D5 : virtual C5 {};
+struct D6 : virtual C6 {};
+struct D7 : virtual C7 {};
+struct D8 : virtual C8 {};
+
+unsigned const nearly_empty_size = sizeof (D1);
+
+template <typename Cn, typename Dn> int Check (Dn const &ref)
+{
+ if ((sizeof (Cn) <= nearly_empty_size)
+ != (static_cast <void const *> (&ref)
+ == static_cast <Cn const *> (&ref)))
+ return 1;
+ return 0;
+}
+
+template <typename Bn, typename Cn> int Check ()
+{
+ Cn c[2];
+
+ if (static_cast <A *> (static_cast <B1 *> (&c[1]))
+ == static_cast <A *> (static_cast <Bn *> (&c[0])))
+ return 1;
+ return 0;
+}
+
+
+int main ()
+{
+#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
+ if (Check<B1, C1> ())
+ return 1;
+ if (Check<B2, C2> ())
+ return 2;
+ if (Check<B3, C3> ())
+ return 3;
+ if (Check<B4, C4> ())
+ return 4;
+ if (Check<B5, C5> ())
+ return 5;
+ if (Check<B6, C6> ())
+ return 6;
+ if (Check<B7, C7> ())
+ return 7;
+ if (Check<B8, C8> ())
+ return 8;
+
+ if (Check<C1> (D1 ()))
+ return 11;
+ if (Check<C2> (D2 ()))
+ return 12;
+ if (Check<C3> (D3 ()))
+ return 13;
+ if (Check<C4> (D4 ()))
+ return 14;
+ if (Check<C5> (D5 ()))
+ return 15;
+ if (Check<C6> (D6 ()))
+ return 16;
+ if (Check<C7> (D7 ()))
+ return 17;
+ if (Check<C8> (D8 ()))
+ return 18;
+
+ if (sizeof (C2) == nearly_empty_size)
+ return 22;
+ if (sizeof (C3) == nearly_empty_size)
+ return 23;
+ if (sizeof (C4) == nearly_empty_size)
+ return 24;
+ if (sizeof (C5) == nearly_empty_size)
+ return 25;
+ if (sizeof (C6) == nearly_empty_size)
+ return 26;
+ if (sizeof (C7) == nearly_empty_size)
+ return 27;
+ if (sizeof (C8) == nearly_empty_size)
+ return 28;
+#endif
+ return 0;
+
+}