Take the program code from https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61284#c0 , change derived type name "t3" to "DerivedType" (three places in the code) and compile the result by gfortran 7.3.0. It will compile fine, but result in segmentation fault at runtime, even though the original code (with "t3") now runs all right. When the modified code is compiled with gfortran 7.2.0 or ifort 17.0.0, it also runs well, without crashing. Finally, when "non_overridable" keyword on line 12 is removed (as indicated in the commented line 13), the modified program runs well, too, even when compiled by gfortran 7.3.0. For reference, here is the failing code: 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 ! works 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() write(*,*) v%i end program p
This has to be one of the stranger bugs I have encountered... It appears that the bug depends on the alphabetical ordering of the type names. So, replace DerivedType in your code by anything (such as "t2a") that comes later in the alphabet than t2, the code compiles and runs fine. Now, replacing DerivedType with t0 and t3, respectively, and comparing the assembly dumps, shows some significant difference. The t3 version has, right at the top .file "a.f90" .text .globl __m_MOD___def_init_m_T3 .section .rodata .align 4 .type __m_MOD___def_init_m_T3, @object .size __m_MOD___def_init_m_T3, 4 __m_MOD___def_init_m_T3: .zero 4 .globl __m_MOD___vtab_m_T1 .align 32 .type __m_MOD___vtab_m_T1, @object .size __m_MOD___vtab_m_T1, 64 and the t0 version (which does not work) has .file "a.f90" .text .globl __m_MOD___def_init_m_T0 .section .rodata .align 4 .type __m_MOD___def_init_m_T0, @object .size __m_MOD___def_init_m_T0, 4 __m_MOD___def_init_m_T0: .zero 4 .globl __m_MOD___vtab_m_T0 .align 32 .type __m_MOD___vtab_m_T0, @object .size __m_MOD___vtab_m_T0, 64 so whatever the def_init_m data structures are supposed to point to, they appear to point to something wrong if things are out of alphabetical order. Wow, this has to be among the top 2% in weird gfortran bugs.
Regression! We are looking for a commit between r254227 (2017-10-30, OK) and r254498 (2017-11-07, wrong-code) that has been back-ported to gcc7, may be r254244(?).
Bisection points to revision 254427 from 5 November 2017, which adds this chunk of code to "fortran/resolv.c" (function "resolve_fl_derived", lines 14081-14093): /* Generate module vtables subject to their accessibility and their not being vtables or pdt templates. If this is not done class declarations in external procedures wind up with their own version and so SELECT TYPE fails because the vptrs do not have the same address. */ if (gfc_option.allow_std & GFC_STD_F2003 && sym->ns->proc_name && sym->ns->proc_name->attr.flavor == FL_MODULE && sym->attr.access != ACCESS_PRIVATE && !(sym->attr.use_assoc || sym->attr.vtype || sym->attr.pdt_template)) { gfc_symbol *vtab = gfc_find_derived_vtab (sym); gfc_set_sym_referenced (vtab); } When I comment it out, the compiled program works as expected.
I got a bug, which I think is related to the one described here and wanted to avoid opening another bug report. I tried my best to build a small minimal example (see bottom). It compiles with all compilers I tried. However with gfortran 6.3.1, gfortran 7.3.1 and gfortran 8.1.0 it does not produce the wanted result (see test.f90). With gfortran 4.8.5, nag 6.2 and intel 18.0.3 it runs as expected. I carried out all tests on CentOS 7.4 and Ubuntu 16.04. With a debugger, I could see: in test.f90, F%get() is called (line 8), the program then moves into child_get() in module2.f90 (line 35) as it should. However, stepping into this%calc() (line 39), it moves to child_reset() in module1.f90 (line 31) instead of child2_calc() in module2.f90 (line 15). There are two ways to get this program to work, which are both quite weird: 1. remove "non_overridable" from line 14 in module1.f90 old: procedure, pass, non_overridable :: get => child_get new: procedure, pass :: get => child_get 2. merge module1 and module2 into one module. FILES: ***module1.f90: 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 ***module2.f90: 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 ***test.f90: program test use module2, only: child2 implicit none type(child2) :: F if (F%get() /= 1) stop ': FAILED' end program test
(In reply to Libavius from comment #4) > There are two ways to get this program to work, which are both quite weird: > 1. remove "non_overridable" from line 14 in module1.f90 > old: procedure, pass, non_overridable :: get => child_get > new: procedure, pass :: get => child_get Sorry for this, I meant line 13: old: procedure, pass, non_overridable :: reset => child_reset new: procedure, pass :: reset => child_reset
The GCC 7 branch is being closed, re-targeting to GCC 8.4.
GCC 8.4.0 has been released, adjusting target milestone.
GCC 8 branch is being closed.
GCC 9.4 is being released, retargeting bugs to GCC 9.5.
GCC 9 branch is being closed
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
GCC 10 branch is being closed.