| ! { dg-do run } |
| ! Test the fix for PR110987 |
| ! Segfaulted in runtime, as shown below. |
| ! Contributed by Kirill Chankin <chilikin.k@gmail.com> |
| ! and John Haiducek <jhaiduce@gmail.com> (comment 5) |
| ! |
| MODULE original_mod |
| IMPLICIT NONE |
| |
| TYPE T1_POINTER |
| CLASS(T1), POINTER :: T1 |
| END TYPE |
| |
| TYPE T1 |
| INTEGER N_NEXT |
| CLASS(T1_POINTER), ALLOCATABLE :: NEXT(:) |
| CONTAINS |
| FINAL :: T1_DESTRUCTOR |
| PROCEDURE :: SET_N_NEXT => T1_SET_N_NEXT |
| PROCEDURE :: GET_NEXT => T1_GET_NEXT |
| END TYPE |
| |
| INTERFACE T1 |
| PROCEDURE T1_CONSTRUCTOR |
| END INTERFACE |
| |
| TYPE, EXTENDS(T1) :: T2 |
| REAL X |
| CONTAINS |
| END TYPE |
| |
| INTERFACE T2 |
| PROCEDURE T2_CONSTRUCTOR |
| END INTERFACE |
| |
| TYPE, EXTENDS(T1) :: T3 |
| CONTAINS |
| FINAL :: T3_DESTRUCTOR |
| END TYPE |
| |
| INTERFACE T3 |
| PROCEDURE T3_CONSTRUCTOR |
| END INTERFACE |
| |
| INTEGER :: COUNTS = 0 |
| |
| CONTAINS |
| |
| TYPE(T1) FUNCTION T1_CONSTRUCTOR() RESULT(L) |
| IMPLICIT NONE |
| L%N_NEXT = 0 |
| END FUNCTION |
| |
| SUBROUTINE T1_DESTRUCTOR(SELF) |
| IMPLICIT NONE |
| TYPE(T1), INTENT(INOUT) :: SELF |
| IF (ALLOCATED(SELF%NEXT)) THEN |
| DEALLOCATE(SELF%NEXT) |
| ENDIF |
| END SUBROUTINE |
| |
| SUBROUTINE T3_DESTRUCTOR(SELF) |
| IMPLICIT NONE |
| TYPE(T3), INTENT(IN) :: SELF |
| if (.NOT.ALLOCATED (SELF%NEXT)) COUNTS = COUNTS + 1 |
| END SUBROUTINE |
| |
| SUBROUTINE T1_SET_N_NEXT(SELF, N_NEXT) |
| IMPLICIT NONE |
| CLASS(T1), INTENT(INOUT) :: SELF |
| INTEGER, INTENT(IN) :: N_NEXT |
| INTEGER I |
| SELF%N_NEXT = N_NEXT |
| ALLOCATE(SELF%NEXT(N_NEXT)) |
| DO I = 1, N_NEXT |
| NULLIFY(SELF%NEXT(I)%T1) |
| ENDDO |
| END SUBROUTINE |
| |
| FUNCTION T1_GET_NEXT(SELF) RESULT(NEXT) |
| IMPLICIT NONE |
| CLASS(T1), TARGET, INTENT(IN) :: SELF |
| CLASS(T1), POINTER :: NEXT |
| CLASS(T1), POINTER :: L |
| INTEGER I |
| IF (SELF%N_NEXT .GE. 1) THEN |
| NEXT => SELF%NEXT(1)%T1 |
| RETURN |
| ENDIF |
| NULLIFY(NEXT) |
| END FUNCTION |
| |
| TYPE(T2) FUNCTION T2_CONSTRUCTOR() RESULT(L) |
| IMPLICIT NONE |
| L%T1 = T1() |
| CALL L%T1%SET_N_NEXT(1) |
| END FUNCTION |
| |
| TYPE(T3) FUNCTION T3_CONSTRUCTOR() RESULT(L) |
| IMPLICIT NONE |
| L%T1 = T1() |
| END FUNCTION |
| |
| END MODULE original_mod |
| |
| module comment5_mod |
| type::parent |
| character(:), allocatable::name |
| end type parent |
| type, extends(parent)::child |
| contains |
| final::child_finalize |
| end type child |
| interface child |
| module procedure new_child |
| end interface child |
| integer :: counts = 0 |
| |
| contains |
| |
| type(child) function new_child(name) |
| character(*)::name |
| new_child%name=name |
| end function new_child |
| |
| subroutine child_finalize(this) |
| type(child), intent(in)::this |
| counts = counts + 1 |
| end subroutine child_finalize |
| end module comment5_mod |
| |
| PROGRAM TEST_PROGRAM |
| call original |
| call comment5 |
| contains |
| subroutine original |
| USE original_mod |
| IMPLICIT NONE |
| TYPE(T1), TARGET :: X1 |
| TYPE(T2), TARGET :: X2 |
| TYPE(T3), TARGET :: X3 |
| CLASS(T1), POINTER :: L |
| X1 = T1() |
| X2 = T2() |
| X2%NEXT(1)%T1 => X1 |
| X3 = T3() |
| CALL X3%SET_N_NEXT(1) |
| X3%NEXT(1)%T1 => X2 |
| L => X3 |
| DO WHILE (.TRUE.) |
| L => L%GET_NEXT() ! Used to segfault here in runtime |
| IF (.NOT. ASSOCIATED(L)) EXIT |
| COUNTS = COUNTS + 1 |
| ENDDO |
| ! Two for T3 finalization and two for associated 'L's |
| IF (COUNTS .NE. 4) STOP 1 |
| end subroutine original |
| |
| subroutine comment5 |
| use comment5_mod, only: child, counts |
| implicit none |
| type(child)::kid |
| kid = child("Name") |
| if (.not.allocated (kid%name)) stop 2 |
| if (kid%name .ne. "Name") stop 3 |
| if (counts .ne. 2) stop 4 |
| end subroutine comment5 |
| END PROGRAM |