diff --git a/gcc/c-family/c-ada-spec.cc b/gcc/c-family/c-ada-spec.cc index e127eedfe4d81b8ead5dad993eb591974f098d01..aa7ab535134b4223b969a11ed8a2dc94a2667478 100644 --- a/gcc/c-family/c-ada-spec.cc +++ b/gcc/c-family/c-ada-spec.cc @@ -40,6 +40,7 @@ static void dump_ada_structure (pretty_printer *, tree, tree, bool, int); static void dump_nested_types (pretty_printer *, tree, int); static char *to_ada_name (const char *, bool *); static bool needs_empty_class_layout (tree); +static bool maps_to_ada_tagged_type (tree); #define INDENT(SPACE) \ do { int i; for (i = 0; i 0 + && bitpos < ((unsigned HOST_WIDE_INT) object_size + * BITS_PER_UNIT)) + return true; + } + + return false; +} + +/* Return true if FIELD is a concrete C++ base that NODE must represent as a + component. Ada inheritance can represent the primary base only when NODE + maps to a tagged type without overlapping the primary base's tail. */ static bool -is_ada_record_field (tree node, tree field) +is_concrete_nested_base_field (tree node, tree field) +{ + return (cpp_check && TREE_CODE (field) == FIELD_DECL + && cpp_check (field, IS_BASE_FIELD) + && (!is_tagged_type (node) + || !cpp_check (field, IS_PRIMARY_BASE_FIELD) + || primary_base_tail_reused (node, field)) + && !is_ada_interface_type (TREE_TYPE (field)) + && is_tagged_type (TREE_TYPE (field))); +} + +/* Return true if NODE can use Ada tagged inheritance without losing a C++ + primary base's reused tail padding. */ + +static bool +maps_to_ada_tagged_type (tree node) +{ + if (!is_tagged_type (node)) + return false; + + for (tree field = TYPE_FIELDS (node); field; field = TREE_CHAIN (field)) + if (cpp_check && cpp_check (field, IS_PRIMARY_BASE_FIELD) + && is_concrete_nested_base_field (node, field)) + return false; + return true; +} + +/* Return true if NODE has a tagged C++ primary base represented by Ada + inheritance rather than an explicit record component. */ + +static bool +has_tagged_primary_base (tree node) +{ + if (!maps_to_ada_tagged_type (node)) + return false; + + for (tree field = TYPE_FIELDS (node); field; field = TREE_CHAIN (field)) + if (cpp_check && cpp_check (field, IS_PRIMARY_BASE_FIELD) + && is_tagged_type (TREE_TYPE (field))) + return true; + return false; +} + +/* Return true if NODE has a concrete C++ base that needs a component. */ + +static bool +has_concrete_nested_base (tree node) +{ + for (tree field = TYPE_FIELDS (node); field; field = TREE_CHAIN (field)) + if (is_concrete_nested_base_field (node, field)) + return true; + return false; +} + +/* Return true if FIELD is represented as a component in NODE's 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)); + return (DECL_NAME (field) || !is_tagged_type (TREE_TYPE (field)) + || is_concrete_nested_base_field (node, field)); } /* Return true if NODE needs a distinct storage type when used as a base - subobject. A non-polymorphic class with virtual bases contains those bases - as a complete object, but excludes them from its as-base size. */ + subobject. A class can exclude virtual bases or complete-object tail + padding from its as-base size. */ static bool -needs_virtual_as_base_type (tree node) +needs_as_base_storage_type (tree node) { - if (!cpp_check || !RECORD_OR_UNION_TYPE_P (node) || is_tagged_type (node) - || !cpp_check (node, HAS_VIRTUAL_BASE)) + if (!cpp_check || !RECORD_OR_UNION_TYPE_P (node)) return false; const int data_size = cpp_check (node, GET_AS_BASE_SIZE); @@ -3174,10 +3300,10 @@ needs_virtual_as_base_type (tree node) for this component. */ static bool -is_shortened_virtual_base_field (tree field) +is_shortened_base_field (tree field) { if (TREE_CODE (field) != FIELD_DECL || DECL_NAME (field) - || !needs_virtual_as_base_type (TREE_TYPE (field)) + || !needs_as_base_storage_type (TREE_TYPE (field)) || !DECL_SIZE (field) || !tree_fits_uhwi_p (DECL_SIZE (field))) return false; @@ -3194,7 +3320,7 @@ static void dump_ada_record_field_type (pretty_printer *buffer, tree field) { dump_ada_decl_name (buffer, TYPE_NAME (TREE_TYPE (field)), false); - if (is_shortened_virtual_base_field (field)) + if (is_shortened_base_field (field)) pp_string (buffer, "_As_Base"); } @@ -3204,7 +3330,7 @@ static bool field_fits_as_base (tree node, tree field) { const int data_size = cpp_check (node, GET_AS_BASE_SIZE); - if (data_size < 0 || !is_ada_record_field (node, field) + if (data_size < 0 || !is_ada_record_field (node, field) || !DECL_FIELD_OFFSET (field) || !DECL_FIELD_BIT_OFFSET (field) || !DECL_SIZE (field) || !tree_fits_uhwi_p (DECL_FIELD_OFFSET (field)) @@ -3225,7 +3351,7 @@ field_fits_as_base (tree node, tree field) padding is not part of a base subobject. */ static unsigned int -virtual_as_base_alignment (tree node, unsigned int data_size) +as_base_alignment (tree node, unsigned int data_size) { unsigned int alignment = TYPE_ALIGN (node) / BITS_PER_UNIT; while (alignment > 1 && data_size % alignment != 0) @@ -3237,11 +3363,11 @@ virtual_as_base_alignment (tree node, unsigned int data_size) keeps each direct field addressable while excluding shared virtual bases. */ static void -dump_ada_virtual_as_base_type (pretty_printer *buffer, tree node, tree type, - int spc) +dump_ada_as_base_storage_type (pretty_printer *buffer, tree node, tree type, + int spc) { const unsigned int data_size = cpp_check (node, GET_AS_BASE_SIZE); - int field_num = 0; + int field_num = has_tagged_primary_base (node) ? 1 : 0; pp_newline (buffer); newline_and_indent (buffer, spc); @@ -3297,6 +3423,15 @@ dump_ada_virtual_as_base_type (pretty_printer *buffer, tree node, tree type, newline_and_indent (buffer, spc); pp_string (buffer, "with Convention => C_Pass_By_Copy;"); + if (as_base_alignment (node, data_size) + < TYPE_ALIGN (node) / BITS_PER_UNIT) + { + newline_and_indent (buffer, spc); + pp_string (buffer, "pragma Component_Alignment (Storage_Unit, "); + dump_ada_node (buffer, TYPE_NAME (node), type, spc, false, true); + pp_string (buffer, "_As_Base);"); + } + newline_and_indent (buffer, spc); pp_string (buffer, "for "); dump_ada_node (buffer, TYPE_NAME (node), type, spc, false, true); @@ -3315,7 +3450,7 @@ dump_ada_virtual_as_base_type (pretty_printer *buffer, tree node, tree type, pp_string (buffer, "for "); dump_ada_node (buffer, TYPE_NAME (node), type, spc, false, true); pp_string (buffer, "_As_Base'Alignment use "); - pp_decimal_int (buffer, virtual_as_base_alignment (node, data_size)); + pp_decimal_int (buffer, as_base_alignment (node, data_size)); pp_semicolon (buffer); newline_and_indent (buffer, spc); @@ -3395,7 +3530,7 @@ static bool has_constant_field_layout (tree node) { for (tree field = TYPE_FIELDS (node); field; field = TREE_CHAIN (field)) - if (is_ada_record_field (node, field) + if (is_ada_record_field (node, field) && (!DECL_FIELD_OFFSET (field) || !DECL_FIELD_BIT_OFFSET (field) || !DECL_SIZE (field) @@ -3453,9 +3588,9 @@ dump_ada_cpp_layout (pretty_printer *buffer, tree node, tree type, int spc, dump_ada_node (buffer, TYPE_NAME (node), type, spc, false, true); pp_string (buffer, " use record"); - int field_num = 0; + int field_num = has_tagged_primary_base (node) ? 1 : 0; for (tree field = TYPE_FIELDS (node); field; field = TREE_CHAIN (field)) - if (is_ada_record_field (node, field)) + if (is_ada_record_field (node, field)) { field_num++; const unsigned HOST_WIDE_INT bitpos @@ -4389,6 +4524,7 @@ dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested, const bool is_union = (TREE_CODE (node) == UNION_TYPE); char buf[32]; int field_num = 0; + int fields_emitted = 0; int field_spc = spc + INDENT_INCR; int need_semicolon; @@ -4415,7 +4551,12 @@ dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested, /* Add parent field if needed. */ if (!DECL_NAME (tmp)) { - if (!is_tagged_type (TREE_TYPE (tmp))) + if (maps_to_ada_tagged_type (node) && cpp_check + && cpp_check (tmp, IS_PRIMARY_BASE_FIELD) + && is_tagged_type (TREE_TYPE (tmp))) + field_num++; + else if (!is_tagged_type (TREE_TYPE (tmp)) + || is_concrete_nested_base_field (node, tmp)) { if (!TYPE_NAME (TREE_TYPE (tmp))) dump_ada_declaration (buffer, tmp, type, field_spc); @@ -4436,6 +4577,7 @@ dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested, pp_newline (buffer); field_num++; + fields_emitted++; } } else if (TREE_CODE (tmp) == FIELD_DECL) @@ -4461,6 +4603,7 @@ dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested, { pp_newline (buffer); field_num++; + fields_emitted++; } } } @@ -4473,7 +4616,7 @@ dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested, pp_newline (buffer); } - if (field_num == 0) + if (fields_emitted == 0) { INDENT (spc + INDENT_INCR); pp_string (buffer, "null;"); @@ -4543,7 +4686,8 @@ dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested, dump_ada_empty_class_layout (buffer, node, type, spc); } else if ((needs_tail_padding_layout (node) - || (cpp_check && cpp_check (node, HAS_VIRTUAL_BASE))) + || (cpp_check && cpp_check (node, HAS_VIRTUAL_BASE)) + || has_concrete_nested_base (node)) && has_constant_field_layout (node)) { if (need_semicolon) @@ -4556,8 +4700,8 @@ dump_ada_structure (pretty_printer *buffer, tree node, tree type, bool nested, dump_ada_cpp_layout (buffer, node, type, spc, cpp_check (node, HAS_VIRTUAL_BASE)); - if (needs_virtual_as_base_type (node)) - dump_ada_virtual_as_base_type (buffer, node, type, spc); + if (needs_as_base_storage_type (node)) + dump_ada_as_base_storage_type (buffer, node, type, spc); } /* 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 a621f583363b4add7a94d4b37832ea8e6b63cdd6..ba22c55bd8c83eaea8513babab6d184ef57e2610 100644 --- a/gcc/c-family/c-ada-spec.h +++ b/gcc/c-family/c-ada-spec.h @@ -31,10 +31,12 @@ enum cpp_operation { HAS_DEPENDENT_TEMPLATE_ARGS, IS_ABSTRACT, IS_ASSIGNMENT_OPERATOR, + IS_BASE_FIELD, IS_CONSTRUCTOR, IS_DESTRUCTOR, IS_COPY_CONSTRUCTOR, IS_MOVE_CONSTRUCTOR, + IS_PRIMARY_BASE_FIELD, IS_TEMPLATE, IS_TRIVIAL, REUSES_BASE_TAIL_PADDING diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 70e10b4179d851438cb052d8fbac498c09a4f8bb..dd1a400275c1e7a522e9589b0664b1fdebcdc6e6 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -4593,6 +4593,8 @@ cpp_check (tree t, cpp_operation op) return DECL_PURE_VIRTUAL_P (t); case IS_ASSIGNMENT_OPERATOR: return DECL_ASSIGNMENT_OPERATOR_P (t); + case IS_BASE_FIELD: + return (TREE_CODE (t) == FIELD_DECL && DECL_FIELD_IS_BASE (t)); case IS_CONSTRUCTOR: return DECL_CONSTRUCTOR_P (t); case IS_DESTRUCTOR: @@ -4601,6 +4603,22 @@ cpp_check (tree t, cpp_operation op) return DECL_COPY_CONSTRUCTOR_P (t); case IS_MOVE_CONSTRUCTOR: return DECL_MOVE_CONSTRUCTOR_P (t); + case IS_PRIMARY_BASE_FIELD: + { + if (TREE_CODE (t) != FIELD_DECL || !DECL_FIELD_IS_BASE (t) + || !CLASS_TYPE_P (DECL_CONTEXT (t))) + return 0; + + tree binfo; + unsigned int i = 0; + vec *vbases = + CLASSTYPE_VBASECLASSES (DECL_CONTEXT (t)); + for (; vec_safe_iterate (vbases, i, &binfo); i++) + if (TREE_TYPE (t) == CLASSTYPE_AS_BASE (BINFO_TYPE (binfo))) + return 0; + + return tree_int_cst_equal (bit_position (t), bitsize_zero_node); + } case IS_TEMPLATE: return TREE_CODE (t) == TEMPLATE_DECL; case IS_TRIVIAL: diff --git a/gcc/testsuite/g++.dg/ada-spec/concrete-multiple-inheritance.C b/gcc/testsuite/g++.dg/ada-spec/concrete-multiple-inheritance.C new file mode 100644 index 0000000000000000000000000000000000000000..b7febaecd3858500d0fbbc935eb1f30a1ccf7766 --- /dev/null +++ b/gcc/testsuite/g++.dg/ada-spec/concrete-multiple-inheritance.C @@ -0,0 +1,64 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-options "-fdump-ada-spec-slim" } */ +/* { dg-final { scan-file concrete_multiple_inheritance_c.ads "type Both is limited new Left with record" } } */ +/* { dg-final { scan-file concrete_multiple_inheritance_c.ads "field_2 : aliased Right_As_Base;" } } */ +/* { dg-final { scan-file concrete_multiple_inheritance_c.ads "for Right_As_Base'Object_Size use 96;" } } */ +/* { dg-final { scan-file concrete_multiple_inheritance_c.ads "field_2 at 16 range 0 .. 95;" } } */ + +class Left +{ +public: + virtual ~Left () = default; + virtual int left_value () { return l; } + int l; +}; + +class Right +{ +public: + virtual ~Right () = default; + virtual int right_value () { return r; } + int r; +}; + +class Both : public Left, public Right +{ +public: + Both (int l_value, int r_value, int both_value); + ~Both () override = default; + int left_value () override { return l + both; } + int right_value () override { return r + both; } + int both; +}; + +Both::Both (int l_value, int r_value, int both_value) +{ + l = l_value; + r = r_value; + both = both_value; +} + +extern "C" Both *cpp_create_both (int l, int r, int both_value) +{ + return new Both (l, r, both_value); +} + +extern "C" void cpp_delete_both (Both *object) { delete object; } +extern "C" unsigned long cpp_both_size () { return sizeof (Both); } +extern "C" unsigned long cpp_right_offset (Both *object) +{ + return reinterpret_cast (static_cast (object)) + - reinterpret_cast (object); +} +extern "C" int cpp_call_left (Both *object) { return object->left_value (); } +extern "C" int cpp_call_right (Right *object) { return object->right_value (); } +extern "C" int cpp_call_right_from_both (Both *object) +{ + return static_cast (object)->right_value (); +} +extern "C" int cpp_read_left (Both *object) { return object->l; } +extern "C" int cpp_read_right (Both *object) { return object->r; } +extern "C" int cpp_read_both (Both *object) { return object->both; } + +/* { dg-final { cleanup-ada-spec } } */