I all, the attached patch regression tested on x86_64
I have not used the gfortran.dg/lto/ testsuite things so it took me a while to
come up with the test cases. Both are based on Andrew's original examples
provided in the PR.
OK for mainline?
I don't think we need to backport this. Let me know otherwise.
Regards,
Jerry
---
fortran: [PR126170] Fix LTO ICE in copy_function_or_variable
A redundant USE of a module already visible via host association,
written inside a contained procedure, caused gfortran's module
reader to create a second copy of that module's derived
type.
PR fortran/126170
gcc/fortran/ChangeLog:
PR fortran/126170
* class.cc (gfc_find_derived_vtab): Fix up a stale
non-use-associated duplicate vtab symbol.
(gfc_is_finalizable): Same fix-up, for the finalizer wrapper
symbol.
* module.cc (read_module): Skip re-importing a symbol already
visible via host association from the same module.
gcc/testsuite/ChangeLog:
PR fortran/126170
* gfortran.dg/lto/pr126170_0.f90: New test.
* gfortran.dg/lto/pr126170_1.f90: New test.
---commit 97fc4e5d8482a24b8fc5319b60c6e0ecb13fc7eb
Author: Jerry DeLisle <[email protected]>
Date: Thu Jul 9 19:24:49 2026 -0700
fortran: [PR126170] Fix LTO ICE in copy_function_or_variable
A redundant USE of a module already visible via host association,
written inside a contained procedure, caused gfortran's module
reader to create a second copy of that module's derived
type.
PR fortran/126170
gcc/fortran/ChangeLog:
PR fortran/126170
* class.cc (gfc_find_derived_vtab): Fix up a stale
non-use-associated duplicate vtab symbol.
(gfc_is_finalizable): Same fix-up, for the finalizer wrapper
symbol.
* module.cc (read_module): Skip re-importing a symbol already
visible via host association from the same module.
gcc/testsuite/ChangeLog:
PR fortran/126170
* gfortran.dg/lto/pr126170_0.f90: New test.
* gfortran.dg/lto/pr126170_1.f90: New test.
diff --git a/gcc/fortran/class.cc b/gcc/fortran/class.cc
index aa9bdb8f279..c6a1de630fe 100644
--- a/gcc/fortran/class.cc
+++ b/gcc/fortran/class.cc
@@ -2523,6 +2523,15 @@ gfc_find_derived_vtab (gfc_symbol *derived)
if (vtab == NULL && module_ns != ns)
gfc_find_symbol (name, module_ns, 0, &vtab);
+ /* Fix up a stale non-use-associated duplicate vtab. */
+ if (vtab
+ && (derived->attr.use_assoc || derived->attr.used_in_submodule)
+ && !vtab->attr.use_assoc && !vtab->module)
+ {
+ vtab->attr.use_assoc = 1;
+ vtab->module = derived->module;
+ }
+
if (vtab == NULL)
{
gfc_get_symbol (name, ns, &vtab);
@@ -2860,6 +2869,19 @@ yes:
gcc_assert (final->initializer
&& final->initializer->expr_type != EXPR_NULL);
*final_expr = final->initializer;
+
+ /* Same fix-up, for the finalizer wrapper symbol. */
+ if ((derived->attr.use_assoc || derived->attr.used_in_submodule)
+ && (*final_expr)->expr_type == EXPR_VARIABLE
+ && (*final_expr)->symtree)
+ {
+ gfc_symbol *final_sym = (*final_expr)->symtree->n.sym;
+ if (final_sym && !final_sym->attr.use_assoc && !final_sym->module)
+ {
+ final_sym->attr.use_assoc = 1;
+ final_sym->module = derived->module;
+ }
+ }
}
return true;
}
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index 3bb81bab68a..f7bf5854d74 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -6053,6 +6053,19 @@ read_module (void)
module_name, 0))
continue;
+ /* Skip re-importing a symbol already visible via host association
+ from the same module. */
+ if (!only_flag && !info->u.rsym.renamed
+ && strcmp (name, module_name) != 0
+ && gfc_current_ns->parent)
+ {
+ gfc_symbol *host_sym;
+ gfc_find_symbol (name, gfc_current_ns, 1, &host_sym);
+ if (host_sym && host_sym->module
+ && strcmp (host_sym->module, module_name) == 0)
+ continue;
+ }
+
st = gfc_find_symtree (gfc_current_ns->sym_root, p);
if (st != NULL
diff --git a/gcc/testsuite/gfortran.dg/lto/pr126170_0.f90 b/gcc/testsuite/gfortran.dg/lto/pr126170_0.f90
new file mode 100644
index 00000000000..d4d2e6907e1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/lto/pr126170_0.f90
@@ -0,0 +1,37 @@
+! { dg-lto-do link }
+!
+! PR fortran/126170
+! A redundant, already host-associated USE inside a CONTAINS'ed function
+! caused gfortran to serialize a spurious duplicate of a derived type with
+! a FINAL binding. The compiler-generated vtable and finalizer-wrapper
+! symbols for that duplicate ended up without the module/use association
+! attributes needed to mark them as externally defined elsewhere. Under
+! -flto this led to an ICE in get_partitioning_class (vtable) and, once
+! that was fixed, an undefined reference to the finalizer wrapper at link
+! time, both triggered when another translation unit referenced the same
+! type.
+
+module vsm
+ type :: vs
+ integer :: c
+ contains
+ final :: vdst
+ end type vs
+contains
+ subroutine vdst(v)
+ type(vs), intent(inout) :: v
+ end subroutine vdst
+end module vsm
+
+module m_ds
+ use vsm
+ type :: mdcc
+ end type mdcc
+contains
+ function mdot(self)
+ use vsm
+ class(mdcc), intent(inout) :: self
+ type(vs) :: mdot
+ mdot%c = 1
+ end function mdot
+end module m_ds
diff --git a/gcc/testsuite/gfortran.dg/lto/pr126170_1.f90 b/gcc/testsuite/gfortran.dg/lto/pr126170_1.f90
new file mode 100644
index 00000000000..b13fd6c8edd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/lto/pr126170_1.f90
@@ -0,0 +1,14 @@
+module caller
+ use m_ds
+contains
+ subroutine s()
+ type(mdcc) :: self
+ type(vs) :: vs_
+ vs_ = mdot(self)
+ end subroutine s
+end module caller
+
+program main
+ use caller
+ call s()
+end program main