From: Eric Botcazou Date: Mon, 15 Dec 2025 08:09:13 +0000 (+0100) Subject: Ada: Fix ICE in fld_incomplete_type_of when building GtkAda with LTO X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=897cba5b334294bc5c9f184764f9395f0c628fcf;p=thirdparty%2Fgcc.git Ada: Fix ICE in fld_incomplete_type_of when building GtkAda with LTO This is a regression from GCC 9 present on mainline and all active branches: the compilation of GtkAda in LTO mode trips on the assertion present in the fld_incomplete_type_of function about the TYPE_CANONICAL of types pointed to by pointer (or reference) types. The problem comes from an oversight in the update_pointer_to function on gcc-interface, which correctly propagates the TYPE_CANONICAL of the new pointer type to the old one when there is a new pointer type, but fails to synthesize it when there is no new pointer type. gcc/ada/ PR ada/123060 * gcc-interface/utils.cc (update_pointer_to): Synthesize a new TYPE_CANONICAL for the old pointer type in the case where there is no new pointer type. Likewise for references. gcc/testsuite/ * gnat.dg/lto30.ads, gnat.dg/lto30.adb: New test. --- diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc index db736a8d26d..62587cdb91d 100644 --- a/gcc/ada/gcc-interface/utils.cc +++ b/gcc/ada/gcc-interface/utils.cc @@ -4673,8 +4673,23 @@ update_pointer_to (tree old_type, tree new_type) new_ptr = TYPE_NEXT_PTR_TO (new_ptr); TYPE_NEXT_PTR_TO (new_ptr) = old_ptr; } - else - TYPE_POINTER_TO (new_type) = old_ptr; + else if (old_ptr) + { + TYPE_POINTER_TO (new_type) = old_ptr; + + /* If there is no pointer pointing to NEW_TYPE yet, re-compute the + TYPE_CANONICAL of the old pointer but pointing to NEW_TYPE, like + build_pointer_type would have done for such a pointer, because we + will propagate it in the adjustment loop below. */ + if (TYPE_STRUCTURAL_EQUALITY_P (new_type)) + SET_TYPE_STRUCTURAL_EQUALITY (old_ptr); + else if (TYPE_CANONICAL (new_type) != new_type + || (TYPE_REF_CAN_ALIAS_ALL (old_ptr) + && !lookup_attribute ("may_alias", + TYPE_ATTRIBUTES (new_type)))) + TYPE_CANONICAL (old_ptr) + = build_pointer_type (TYPE_CANONICAL (new_type)); + } /* Now adjust them. */ for (ptr = old_ptr; ptr; ptr = TYPE_NEXT_PTR_TO (ptr)) @@ -4694,8 +4709,23 @@ update_pointer_to (tree old_type, tree new_type) new_ref = TYPE_NEXT_REF_TO (new_ref); TYPE_NEXT_REF_TO (new_ref) = old_ref; } - else - TYPE_REFERENCE_TO (new_type) = old_ref; + else if (old_ref) + { + TYPE_REFERENCE_TO (new_type) = old_ref; + + /* If there is no reference pointing to NEW_TYPE yet, re-compute the + TYPE_CANONICAL of the old reference but pointing to NEW_TYPE, like + build_reference_type would have done for such a reference, because + we will propagate it in the adjustment loop below. */ + if (TYPE_STRUCTURAL_EQUALITY_P (new_type)) + SET_TYPE_STRUCTURAL_EQUALITY (old_ref); + else if (TYPE_CANONICAL (new_type) != new_type + || (TYPE_REF_CAN_ALIAS_ALL (old_ref) + && !lookup_attribute ("may_alias", + TYPE_ATTRIBUTES (new_type)))) + TYPE_CANONICAL (old_ref) + = build_reference_type (TYPE_CANONICAL (new_type)); + } /* Now adjust them. */ for (ref = old_ref; ref; ref = TYPE_NEXT_REF_TO (ref)) diff --git a/gcc/testsuite/gnat.dg/lto30.adb b/gcc/testsuite/gnat.dg/lto30.adb new file mode 100644 index 00000000000..863ca61a574 --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto30.adb @@ -0,0 +1,31 @@ +-- { dg-do compile } +-- { dg-options "-flto" { target lto } } + +with Ada.Unchecked_Conversion; +with System; + +package body Lto30 is + + generic + type T is private; + package Unbounded_Arrays is + type Unbounded_Array is array (Natural range 1 .. Natural'Last) of T; + type Unbounded_Array_Access is access Unbounded_Array; + function Convert is new + Ada.Unchecked_Conversion (System.Address, Unbounded_Array_Access); + end Unbounded_Arrays; + + package Atom_Arrays is new Unbounded_Arrays (Ptr); + use Atom_Arrays; + + procedure Proc is + procedure Foo (Targets : access Unbounded_Array_Access); + pragma Import (Ada, Foo, "Foo"); + + Output : aliased Unbounded_Array_Access; + + begin + Foo (Output'Unchecked_Access); + end; + +end Lto30; diff --git a/gcc/testsuite/gnat.dg/lto30.ads b/gcc/testsuite/gnat.dg/lto30.ads new file mode 100644 index 00000000000..3dec139246b --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto30.ads @@ -0,0 +1,13 @@ +package Lto30 is + + type Rec is private; + + type Ptr is access all Rec; + + procedure Proc; + +private + + type Rec is null record; + +end Lto30;