]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ada: Implement proper upcasting in more cases
authorEric Botcazou <ebotcazou@adacore.com>
Wed, 24 Sep 2025 17:02:34 +0000 (19:02 +0200)
committerMarc Poulhiès <dkm@gcc.gnu.org>
Mon, 6 Oct 2025 12:27:10 +0000 (14:27 +0200)
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.

gcc/ada/gcc-interface/utils.cc

index eff58b1075195aacd4c4f65b616b25c7d6149dd0..f176ca9eb65f6e18c4ac29356f174d4e36047adc 100644 (file)
@@ -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);
     }