From: Eric Botcazou <[email protected]>
Upcasting (conversion from a tagged type extension to one of its parents)
is represented as a simple N_Type_Conversion node in the expanded code,
but translating it into a VIEW_CONVERT_EXPR is a bit problematic because
source and target types of the GCC node are supposed to have the same size
(at least in "non-pathological" cases).
That's why Gigi attempts to build an explicit chain of references to the
appropriate _Parent (sub)component instead, but it currently does that
only for simple (i.e. non-discriminated) tagged types. This can be easily
extended to discriminated tagged types in not-too-dynamic cases (an example
is the ACATS c391002 test).
gcc/ada/ChangeLog:
* gcc-interface/utils.cc (convert): Also extract the _Parent field
to implement upcasting in the case where only the sizes match.
Tested on x86_64-pc-linux-gnu, committed on master.
---
gcc/ada/gcc-interface/utils.cc | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index eff58b10751..f176ca9eb65 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -5343,10 +5343,20 @@ convert (tree type, tree expr)
&& !type_annotate_only)
{
tree child_etype = etype;
+ /* Loop through the nested _Parent fields until we find one with either
+ directly the right type (simple record case), or only the right size
+ (discriminated record case), and extract it to be the new expression.
+ Note that build_component_ref will automatically build the chain of
+ COMPONENT_REFs in the case where it is not the immediate parent. */
do {
tree field = TYPE_FIELDS (child_etype);
- if (DECL_NAME (field) == parent_name_id && TREE_TYPE (field) == type)
- return build_component_ref (expr, field, false);
+ if (DECL_NAME (field) == parent_name_id)
+ {
+ if (TREE_TYPE (field) == type)
+ return build_component_ref (expr, field, false);
+ if (operand_equal_p (DECL_SIZE (field), TYPE_SIZE (type), 0))
+ return convert (type, build_component_ref (expr, field, false));
+ }
child_etype = TREE_TYPE (field);
} while (TREE_CODE (child_etype) == RECORD_TYPE);
}
--
2.43.0