| ! RUN: %python %S/test_errors.py %s %flang_fc1 |
| ! Tests for I/O of derived types without defined I/O procedures |
| ! but with exposed allocatable/pointer components that would fail |
| ! at run time. |
| |
| module m1 |
| type :: poison |
| real, allocatable :: allocatableComponent(:) |
| end type |
| type :: ok |
| integer :: x |
| type(poison) :: pill |
| contains |
| procedure :: wuf1 |
| generic :: write(unformatted) => wuf1 |
| end type |
| type :: maybeBad |
| integer :: x |
| type(poison) :: pill |
| end type |
| contains |
| subroutine wuf1(dtv, unit, iostat, iomsg) |
| class(ok), intent(in) :: dtv |
| integer, intent(in) :: unit |
| integer, intent(out) :: iostat |
| character(*), intent(in out) :: iomsg |
| write(unit) dtv%x |
| end subroutine |
| end module |
| |
| module m2 |
| use m1 |
| interface write(unformatted) |
| module procedure wuf2 |
| end interface |
| contains |
| subroutine wuf2(dtv, unit, iostat, iomsg) |
| class(maybeBad), intent(in) :: dtv |
| integer, intent(in) :: unit |
| integer, intent(out) :: iostat |
| character(*), intent(in out) :: iomsg |
| write(unit) dtv%x |
| end subroutine |
| end module |
| |
| module m3 |
| use m1 |
| contains |
| subroutine test3(u) |
| integer, intent(in) :: u |
| type(ok) :: x |
| type(maybeBad) :: y |
| type(poison) :: z |
| write(u) x ! always ok |
| !ERROR: Derived type 'maybebad' in I/O cannot have an allocatable or pointer direct component 'allocatablecomponent' unless using defined I/O |
| write(u) y ! bad here |
| !ERROR: Derived type 'poison' in I/O cannot have an allocatable or pointer direct component 'allocatablecomponent' unless using defined I/O |
| write(u) z ! bad |
| end subroutine |
| end module |
| |
| module m4 |
| use m2 |
| contains |
| subroutine test4(u) |
| integer, intent(in) :: u |
| type(ok) :: x |
| type(maybeBad) :: y |
| type(poison) :: z |
| write(u) x ! always ok |
| write(u) y ! ok here |
| !ERROR: Derived type 'poison' in I/O cannot have an allocatable or pointer direct component 'allocatablecomponent' unless using defined I/O |
| write(u) z ! bad |
| end subroutine |
| end module |
| |
| ! Regression test: an illegal recursive derived-type component used to cause |
| ! infinite recursion in FindUnsafeIoDirectComponent when the object appeared |
| ! in an I/O list (issue #192387). |
| subroutine test_recursive_io |
| type t1 |
| !ERROR: Recursive use of the derived type requires POINTER or ALLOCATABLE |
| type(t1) :: b |
| end type t1 |
| type(t1) :: obj |
| print *, obj |
| end subroutine |
| |
| ! Same regression covering the FindInaccessibleComponent walk: the type |
| ! must be defined in a module and used in I/O outside that module so the |
| ! recursive component traversal in FindInaccessibleComponent is reached. |
| module m_recursive |
| type t2 |
| !ERROR: Recursive use of the derived type requires POINTER or ALLOCATABLE |
| type(t2) :: b |
| end type t2 |
| end module |
| subroutine test_recursive_io_module |
| use m_recursive |
| type(t2) :: obj |
| print *, obj |
| end subroutine |
| |
| ! Positive cases: a recursive type is legal when the recursive component |
| ! is POINTER or ALLOCATABLE. With defined I/O, an I/O list item of such |
| ! a type is accepted without diagnostics. |
| module m_recursive_pointer |
| type :: rp |
| integer :: x |
| type(rp), pointer :: next => null() |
| contains |
| procedure :: wuf_rp |
| generic :: write(unformatted) => wuf_rp |
| end type |
| contains |
| subroutine wuf_rp(dtv, unit, iostat, iomsg) |
| class(rp), intent(in) :: dtv |
| integer, intent(in) :: unit |
| integer, intent(out) :: iostat |
| character(*), intent(in out) :: iomsg |
| write(unit) dtv%x |
| end subroutine |
| end module |
| subroutine test_recursive_pointer_io(u) |
| use m_recursive_pointer |
| integer, intent(in) :: u |
| type(rp) :: obj |
| write(u) obj ! ok: defined I/O |
| end subroutine |
| |
| module m_recursive_allocatable |
| type :: ra |
| integer :: x |
| type(ra), allocatable :: next |
| contains |
| procedure :: wuf_ra |
| generic :: write(unformatted) => wuf_ra |
| end type |
| contains |
| subroutine wuf_ra(dtv, unit, iostat, iomsg) |
| class(ra), intent(in) :: dtv |
| integer, intent(in) :: unit |
| integer, intent(out) :: iostat |
| character(*), intent(in out) :: iomsg |
| write(unit) dtv%x |
| end subroutine |
| end module |
| subroutine test_recursive_allocatable_io(u) |
| use m_recursive_allocatable |
| integer, intent(in) :: u |
| type(ra) :: obj |
| write(u) obj ! ok: defined I/O |
| end subroutine |
| |