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

commit r15-5628-gdd6dbbb5111fba960ad0ee7999a225783e0ae80e
Author: Paul Thomas <pa...@gcc.gnu.org>
Date:   Sun Nov 24 08:50:58 2024 +0000

    Fortran: Fix non_overridable typebound proc problems [PR84674/117730].
    
    2024-11-24  Paul Thomas  <pa...@gcc.gnu.org>
    
    gcc/fortran/ChangeLog
    
            PR fortran/117730
            * class.cc (add_proc_comp): Only reject a non_overridable if it
            has no overridden procedure and the component is already
            present in the vtype.
            PR fortran/84674
            * resolve.cc (resolve_fl_derived): Do not build a vtable for a
            derived type extension that is completely empty.
    
    gcc/testsuite/ChangeLog
    
            PR fortran/117730
            * gfortran.dg/pr117730_a.f90: New test.
            * gfortran.dg/pr117730_b.f90: New test.
    
            PR fortran/84674
            * gfortran.dg/pr84674.f90: New test.

Diff:
---
 gcc/fortran/class.cc                     |  5 +--
 gcc/fortran/resolve.cc                   |  4 +++
 gcc/testsuite/gfortran.dg/pr117730_a.f90 | 50 +++++++++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/pr117730_b.f90 | 47 +++++++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/pr84674.f90    | 55 ++++++++++++++++++++++++++++++++
 5 files changed, 159 insertions(+), 2 deletions(-)

diff --git a/gcc/fortran/class.cc b/gcc/fortran/class.cc
index da09d210b4b5..59ac0d97e080 100644
--- a/gcc/fortran/class.cc
+++ b/gcc/fortran/class.cc
@@ -885,11 +885,12 @@ add_proc_comp (gfc_symbol *vtype, const char *name, 
gfc_typebound_proc *tb)
 {
   gfc_component *c;
 
-  if (tb->non_overridable && !tb->overridden)
-    return;
 
   c = gfc_find_component (vtype, name, true, true, NULL);
 
+  if (tb->non_overridable && !tb->overridden && c)
+    return;
+
   if (c == NULL)
     {
       /* Add procedure component.  */
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index b817192cd930..b1740cec3881 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -16287,6 +16287,10 @@ resolve_fl_derived (gfc_symbol *sym)
       && sym->ns->proc_name
       && sym->ns->proc_name->attr.flavor == FL_MODULE
       && sym->attr.access != ACCESS_PRIVATE
+      && !(sym->attr.extension
+          && sym->attr.zero_comp
+          && !sym->f2k_derived->tb_sym_root
+          && !sym->f2k_derived->tb_uop_root)
       && !(sym->attr.vtype || sym->attr.pdt_template))
     {
       gfc_symbol *vtab = gfc_find_derived_vtab (sym);
diff --git a/gcc/testsuite/gfortran.dg/pr117730_a.f90 
b/gcc/testsuite/gfortran.dg/pr117730_a.f90
new file mode 100644
index 000000000000..12e28214b02b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr117730_a.f90
@@ -0,0 +1,50 @@
+! { dg-do compile }
+!
+! Test the fix for PR117730 in which the non_overrridable procedures in 'child'
+! were mixied up in the vtable for the extension 'child2' in pr117730_b.f90.
+! This resulted in 'this%calc()' in 'function child_get(this)' returning 
garbage
+! when 'this' was of dynamic type 'child2'.
+!
+! Contributed by  <dar...@web.de> in comment 4 of PR84674.
+!
+module module1
+    implicit none
+    private
+    public :: child
+
+    type, abstract :: parent
+    contains
+        procedure, pass :: reset => parent_reset
+    end type parent
+
+    type, extends(parent), abstract :: child
+    contains
+        procedure, pass, non_overridable :: reset => child_reset
+        procedure, pass, non_overridable :: get => child_get
+        procedure(calc_i), pass, deferred :: calc
+    end type child
+
+    abstract interface
+        pure function calc_i(this) result(value)
+            import :: child
+            class(child), intent(in) :: this
+            integer                 :: value
+        end function calc_i
+    end interface
+
+contains
+    pure subroutine parent_reset(this)
+        class(parent), intent(inout) :: this
+    end subroutine parent_reset
+
+    pure subroutine child_reset(this)
+        class(child), intent(inout) :: this
+    end subroutine child_reset
+
+    function child_get(this) result(value)
+        class(child), intent(inout) :: this
+        integer                   :: value
+
+        value = this%calc()
+    end function child_get
+end module module1
diff --git a/gcc/testsuite/gfortran.dg/pr117730_b.f90 
b/gcc/testsuite/gfortran.dg/pr117730_b.f90
new file mode 100644
index 000000000000..09707882989e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr117730_b.f90
@@ -0,0 +1,47 @@
+! { dg-do run }
+! { dg-compile-aux-modules "pr117730_a.f90" }
+! { dg-additional-sources pr117730_a.f90 }
+!
+! Test the fix for PR117730 in which the non_overrridable procedures in
+! pr117730_a.f90 were mixied up in the vtable for 'child2' below. This resulted
+! in 'this%calc()' in 'function child_get(this)' returning garbage.
+!
+! Contributed by  <dar...@web.de> in comment 4 of PR84674.
+!
+module module2
+    use module1, only: child
+
+    implicit none
+    private
+    public :: child2
+
+    type, extends(child) :: child2
+    contains
+        procedure, pass :: calc => child2_calc
+    end type child2
+
+contains
+
+    pure function child2_calc(this) result(value)
+        class(child2), intent(in) :: this
+        integer :: value
+
+        value = 1
+    end function child2_calc
+
+end module module2
+
+program test
+    use module2, only: child2
+
+    implicit none
+
+    type(child2) :: F
+
+    if (F%calc() /= 1) stop 1
+
+    print *, "---------------"
+    if (F%get() /= 1) stop 2
+
+end program test
+! { dg-final { cleanup-modules "module1" } }
diff --git a/gcc/testsuite/gfortran.dg/pr84674.f90 
b/gcc/testsuite/gfortran.dg/pr84674.f90
new file mode 100644
index 000000000000..c58ae9efff69
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr84674.f90
@@ -0,0 +1,55 @@
+! { dg-do run }
+!
+! Test the fix for PR84674, in which the non-overridable variant of the
+! procedure ff below caused a runtime segfault.
+!
+! Contributed by Jakub Benda  <alban...@atlas.cz>
+!
+ module m
+  implicit none
+
+  type, abstract :: t1
+   integer :: i
+  contains
+   procedure(i_f), pass(u), deferred :: ff
+  end type t1
+
+  type, abstract, extends(t1) :: t2
+  contains
+   procedure, non_overridable, pass(u) :: ff => f ! Segmentation fault
+   !procedure, pass(u) :: ff => f ! worked
+  end type t2
+
+  type, extends(t2) :: DerivedType
+  end type DerivedType
+
+  abstract interface
+   subroutine i_f(u)
+    import :: t1
+    class(t1), intent(inout) :: u
+   end subroutine i_f
+  end interface
+
+ contains
+
+  subroutine f(u)
+   class(t2), intent(inout) :: u
+    u%i = 3*u%i
+  end subroutine f
+
+ end module m
+
+
+ program p
+
+  use m
+
+  implicit none
+
+  class(t1), allocatable :: v
+
+  allocate(DerivedType::v)
+  v%i = 2
+  call v%ff()
+  if (v%i /= 6) stop
+ end program p

Reply via email to