diff --git a/gcc/c-family/c-ada-spec.cc b/gcc/c-family/c-ada-spec.cc index 7a28cb6..923670d 100644 --- a/gcc/c-family/c-ada-spec.cc +++ b/gcc/c-family/c-ada-spec.cc @@ -3189,6 +3189,20 @@ is_abi_ignored_empty_field (tree node, tree field) return false; } +/* Return true if FIELD is represented as a component in the generated Ada + record. Keep this in step with dump_ada_structure. */ + +static bool +is_ada_record_field (tree node, tree field) +{ + if (TREE_CODE (field) != FIELD_DECL + || DECL_VIRTUAL_P (field) + || is_abi_ignored_empty_field (node, field)) + return false; + + return DECL_NAME (field) || !is_tagged_type (TREE_TYPE (field)); +} + /* Dump the value and object sizes of an empty C++ class. Ada's value size is zero so an empty base consumes no storage, while Object_Size preserves the byte occupied by a complete C++ object. */ @@ -2947,9 +2961,7 @@ static bool has_constant_field_layout (tree node) { for (tree field = TYPE_FIELDS (node); field; field = TREE_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && DECL_NAME (field) - && !DECL_VIRTUAL_P (field) + if (is_ada_record_field (node, field) && (!DECL_FIELD_OFFSET (field) || !DECL_FIELD_BIT_OFFSET (field) || !DECL_SIZE (field) @@ -2962,14 +2974,19 @@ has_constant_field_layout (tree node) return true; } -/* Dump the size and component clauses needed to preserve NODE's C++ tail - padding layout. TYPE is the declaration used for Ada name qualification. */ +/* Dump the size and component clauses needed to preserve NODE's C++ layout. + For virtual inheritance the generated record contains the virtual bases and + therefore uses the complete-object size; other calls preserve the as-base + size needed for reusable tail padding. TYPE is the declaration used for + Ada name qualification. */ static void -dump_ada_tail_padding_layout (pretty_printer *pp, tree node, tree type, int spc) +dump_ada_cpp_layout (pretty_printer *pp, tree node, tree type, int spc, + bool has_virtual_base) { const int data_size = cpp_check (node, GET_AS_BASE_SIZE); const HOST_WIDE_INT object_size = int_size_in_bytes (node); + const HOST_WIDE_INT value_size = has_virtual_base ? object_size : data_size; gcc_assert (data_size >= 0 && object_size >= 0); @@ -2977,7 +2994,7 @@ dump_ada_tail_padding_layout (pretty_printer *pp, tree node, tree type, int spc) pp_string (pp, "for "); dump_ada_node (pp, TYPE_NAME (node), type, spc, false, true); pp_string (pp, "'Size use "); - pp_wide_integer (pp, (HOST_WIDE_INT) data_size * BITS_PER_UNIT); + pp_wide_integer (pp, value_size * BITS_PER_UNIT); pp_semicolon (pp); newline_and_indent (pp, spc); @@ -2987,16 +3004,26 @@ dump_ada_tail_padding_layout (pretty_printer *pp, tree node, tree type, int spc) pp_wide_integer (pp, object_size * BITS_PER_UNIT); pp_semicolon (pp); + if (has_virtual_base) + { + newline_and_indent (pp, spc); + pp_string (pp, "for "); + dump_ada_node (pp, TYPE_NAME (node), type, spc, false, true); + pp_string (pp, "'Alignment use "); + pp_decimal_int (pp, TYPE_ALIGN (node) / BITS_PER_UNIT); + pp_semicolon (pp); + } + newline_and_indent (pp, spc); pp_string (pp, "for "); dump_ada_node (pp, TYPE_NAME (node), type, spc, false, true); pp_string (pp, " use record"); + int field_num = 0; for (tree field = TYPE_FIELDS (node); field; field = TREE_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && DECL_NAME (field) - && !DECL_VIRTUAL_P (field)) + if (is_ada_record_field (node, field)) { + field_num++; const unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (DECL_FIELD_OFFSET (field)) * BITS_PER_UNIT + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)); @@ -3006,7 +3033,16 @@ dump_ada_tail_padding_layout (pretty_printer *pp, tree node, tree type, int spc) = first_bit + tree_to_uhwi (DECL_SIZE (field)) - 1; newline_and_indent (pp, spc + INDENT_INCR); - dump_ada_decl_name (pp, field, false); + if (DECL_NAME (field)) + dump_ada_decl_name (pp, field, false); + else if (field_num == 1) + pp_string (pp, "parent"); + else + { + char buf[32]; + sprintf (buf, "field_%d", field_num); + pp_string (pp, buf); + } pp_string (pp, " at "); pp_unsigned_wide_integer (pp, position); pp_string (pp, " range "); @@ -4063,7 +4099,8 @@ dump_ada_structure (pretty_printer *pp, tree node, tree type, bool nested, pp_newline (pp); dump_ada_empty_class_layout (pp, node, type, spc); } - else if (needs_tail_padding_layout (node) + else if ((needs_tail_padding_layout (node) + || (cpp_check && cpp_check (node, HAS_VIRTUAL_BASE))) && has_constant_field_layout (node)) { if (need_semicolon) @@ -4073,7 +4110,8 @@ dump_ada_structure (pretty_printer *pp, tree node, tree type, bool nested, } pp_newline (pp); - dump_ada_tail_padding_layout (pp, node, type, spc); + dump_ada_cpp_layout (pp, node, type, spc, + cpp_check (node, HAS_VIRTUAL_BASE)); } /* Print the static fields of the structure, if any. */ diff --git a/gcc/c-family/c-ada-spec.h b/gcc/c-family/c-ada-spec.h index 1866dfc..fe9ae33 100644 --- a/gcc/c-family/c-ada-spec.h +++ b/gcc/c-family/c-ada-spec.h @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see enum cpp_operation { GET_AS_BASE_SIZE, GET_FUNCTION_QUALIFIERS, + HAS_VIRTUAL_BASE, HAS_DEPENDENT_TEMPLATE_ARGS, IS_ABSTRACT, IS_ASSIGNMENT_OPERATOR, diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 92b556c..8c606bf 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5288,6 +5288,9 @@ cpp_check (tree t, cpp_operation op) return qualifiers; } + case HAS_VIRTUAL_BASE: + return (CLASS_TYPE_P (t) && COMPLETE_TYPE_P (t) + && CLASSTYPE_VBASECLASSES (t)); case HAS_DEPENDENT_TEMPLATE_ARGS: { tree ti = CLASSTYPE_TEMPLATE_INFO (t); diff --git a/gcc/testsuite/g++.dg/ada-spec/virtual-inheritance-layout.C b/gcc/testsuite/g++.dg/ada-spec/virtual-inheritance-layout.C new file mode 100644 index 0000000..514d8e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/ada-spec/virtual-inheritance-layout.C @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-options "-fdump-ada-spec-slim" } */ +/* { dg-final { scan-file virtual_inheritance_layout_c.ads "for Virtual'Size use 128;" } } */ +/* { dg-final { scan-file virtual_inheritance_layout_c.ads "for Virtual'Object_Size use 128;" } } */ +/* { dg-final { scan-file virtual_inheritance_layout_c.ads "for Virtual'Alignment use 8;" } } */ +/* { dg-final { scan-file virtual_inheritance_layout_c.ads "derived_value at 8 range 0 .. 31;" } } */ +/* { dg-final { scan-file virtual_inheritance_layout_c.ads "field_2 at 12 range 0 .. 31;" } } */ + +struct Root +{ + int root_value; +}; + +struct Virtual : virtual Root +{ + int derived_value; + Virtual (int root, int derived); +}; + +Virtual::Virtual (int root, int derived) + : Root {root}, derived_value {derived} +{} + +extern "C" unsigned long cpp_root_size () { return sizeof (Root); } +extern "C" unsigned long cpp_virtual_size () { return sizeof (Virtual); } +extern "C" unsigned long cpp_virtual_alignment () { return alignof (Virtual); } +extern "C" unsigned long cpp_derived_offset () +{ + Virtual object (0, 0); + return reinterpret_cast (&object.derived_value) + - reinterpret_cast (&object); +} +extern "C" unsigned long cpp_root_offset () +{ + Virtual object (0, 0); + return reinterpret_cast (&object.root_value) + - reinterpret_cast (&object); +} +extern "C" Virtual *cpp_create (int root, int derived) +{ + return new Virtual (root, derived); +} +extern "C" void cpp_delete (Virtual *object) { delete object; } +extern "C" int cpp_root_value (const Virtual *object) +{ + return object->root_value; +} +extern "C" int cpp_derived_value (const Virtual *object) +{ + return object->derived_value; +} + +/* { dg-final { cleanup-ada-spec } } */