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

Reply via email to