https://gcc.gnu.org/g:f935a7a9013d0748ba1f42dc532df3d278707bf6

commit r17-2320-gf935a7a9013d0748ba1f42dc532df3d278707bf6
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:
---
 gcc/fortran/class.cc                         | 22 ++++++++++++++++++++
 gcc/fortran/module.cc                        | 13 ++++++++++++
 gcc/testsuite/gfortran.dg/lto/pr126170_0.f90 | 31 ++++++++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/lto/pr126170_1.f90 | 14 +++++++++++++
 4 files changed, 80 insertions(+)

diff --git a/gcc/fortran/class.cc b/gcc/fortran/class.cc
index aa9bdb8f2795..18cff8f47a18 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;
+
+      /* Fix up a stale non-use-associated duplicate vtab.  */
+      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 3bb81bab68a5..f7bf5854d745 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 000000000000..c862da5d5442
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/lto/pr126170_0.f90
@@ -0,0 +1,31 @@
+! { dg-lto-do link }
+!
+! PR fortran/126170
+! A redundant, already host-associated USE inside a contained function
+! caused gfortran to create duplicate of a derived type with
+! a FINAL binding.
+
+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 000000000000..b13fd6c8edd9
--- /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

Reply via email to