https://gcc.gnu.org/g:022f2ed33cc4ec1353dd5b60a961d7529521bc31
commit r16-4246-g022f2ed33cc4ec1353dd5b60a961d7529521bc31 Author: Eric Botcazou <[email protected]> Date: Wed Sep 24 19:02:34 2025 +0200 ada: Implement proper upcasting in more cases 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. Diff: --- 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 eff58b107519..f176ca9eb65f 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); }
