| Issue |
203889
|
| Summary |
[flang] Crash (Aborted, core dumped) when compiling derived type with recursive allocatable component and final procedure
|
| Labels |
flang
|
| Assignees |
|
| Reporter |
RinswindtheMage
|
## Description
flang 22.1.1 crashes with "Aborted (core dumped)" during compilation
of a Fortran module containing a recursive derived type with an
allocatable component of the same type, a `final` procedure, and
`move_alloc` operations on that component.
## Environment
- flang version: 22.1.1
- Target: x86_64-linux-gnu
## Steps to reproduce
1. Save the attached `IO.f90` and `environment.f90`
2. Run: flang -ffree-line-length-none -c IO.f90
## Expected behavior
Compiler should either compile successfully or report a normal
diagnostic error.
## Actual behavior
Compiler crashes with:
## Attached files
- main-183aa5 (preprocessed source, as requested by flang)
- main-183aa5.sh (repro script)
- IO.f90
<img width="794" height="535" alt="Image" src="" />
module Environment
use ISO_Fortran_Env
implicit none
integer, parameter :: I_ = INT32
integer, parameter :: R_ = REAL32
integer, parameter :: C_ = R_
integer, parameter :: CH_= Selected_Char_Kind("ISO_10646")
character(*), parameter :: E_ = "UTF-8"
integer(I_), parameter :: SURNAME_LEN = 15 ! не используется, оставлено для совместимости
integer(I_), parameter :: POS_LEN = 20
interface operator (//)
module procedure Int_plus_string
module procedure String_plus_int
end interface
contains
pure function Int_plus_string(n, str) result(res)
integer, intent(in) :: n
character(*), intent(in) :: str
character(len(str) + max(floor(log10(real(n, kind=I_*2))) + 1, 1)) :: res
write (res, '(i0, a)') n, str
end function Int_plus_string
pure function String_plus_int(str, n) result(res)
character(*), intent(in) :: str
integer, intent(in) :: n
character(len(str) + max(floor(log10(real(n, kind=I_*2))) + 1, 1)) :: res
write (res, '(a, i0)') str, n
end function String_plus_int
subroutine Handle_IO_status(IO, where)
integer, intent(in) :: IO
character(*), intent(in) :: where
open (ERROR_UNIT, encoding=E_)
select case(IO)
case(0, IOSTAT_END, IOSTAT_EOR)
case(1:)
write (ERROR_UNIT, '(a, i0)') "Error " // where // ": ", IO
case default
write (ERROR_UNIT, '(a, i0)') "Undetermined behaviour while " // where // ": ", IO
end select
end subroutine Handle_IO_status
end module Environment
module IO
use Environment
implicit none
private
public :: List
type :: ListNode
character(len=:, kind=CH_), allocatable :: line
type(ListNode), allocatable :: next
end type ListNode
type :: List
type(ListNode), allocatable :: head
integer(I_) :: length = 0
contains
procedure :: ReadFromFile
procedure :: WriteToFile
procedure :: Exclude
procedure :: Destroy
final :: Finalize_list
end type List
contains
! ------------------------------------------------------------
! Чтение из файла (каждая строка – элемент списка)
subroutine ReadFromFile(this, filename)
class(List), intent(inout) :: this
character(*), intent(in) :: filename
integer(I_) :: In
character(len=1024, kind=CH_) :: buffer
open(file=filename, encoding=E_, newunit=In)
if (allocated(this%head)) call this%Destroy()
call Read_line(In, this%head, this%length, buffer)
close(In)
contains
! Хвостовая рекурсия: вызов Read_line – последнее действие
recursive subroutine Read_line(In_unit, node, length, buffer)
integer(I_), intent(in) :: In_unit
type(ListNode), allocatable, intent(out) :: node
integer(I_), intent(inout) :: length
character(len=1024, kind=CH_), intent(inout) :: buffer
integer(I_) :: IO_stat
read(In_unit, '(A)', iostat=IO_stat) buffer
if (IO_stat == 0) then
allocate(node)
node%line = trim(buffer)
length = length + 1
call Read_line(In_unit, node%next, length, buffer) ! хвостовой вызов
else
call Handle_IO_status(IO_stat, "reading line")
end if
end subroutine Read_line
end subroutine ReadFromFile
! ------------------------------------------------------------
! Запись списка в файл
subroutine WriteToFile(this, filename, position, title)
class(List), intent(in) :: this
character(*), intent(in) :: filename, position
character(*, kind=CH_), intent(in) :: title
integer(I_) :: Out
open(file=filename, encoding=E_, position=position, newunit=Out)
write(Out, '(/A)') title
call Write_line(Out, this%head)
close(Out)
contains
! Хвостовая рекурсия, целостность списка гарантируется (intent in)
recursive subroutine Write_line(Out_unit, node)
integer, intent(in) :: Out_unit
type(ListNode), allocatable, intent(in) :: node
if (allocated(node)) then
write(Out_unit, '(A)') node%line
call Write_line(Out_unit, node%next) ! хвостовой вызов
end if
end subroutine Write_line
end subroutine WriteToFile
! ------------------------------------------------------------
! Чистая хвостовая рекурсивная функция: присутствует ли строка `line`
! в списке, начинающемся с узла `node`
pure recursive function Is_present(line, node) result(found)
character(*, kind=CH_), intent(in) :: line
type(ListNode), allocatable, intent(in) :: node
logical :: found
if (.not. allocated(node)) then
found = .false.
else if (node%line == line) then
found = .true.
else
found = Is_present(line, node%next) ! хвостовой вызов
end if
end function Is_present
! ------------------------------------------------------------
! Удаление из текущего списка всех строк, которые есть в списке `other`
subroutine Exclude(this, other)
class(List), intent(inout) :: this
class(List), intent(in) :: other
if (.not. allocated(this%head)) return
if (other%length == 0) return
call Delete_matching(this%head, other%head, this%length)
contains
! Хвостовая рекурсия по списку this; other передаётся как intent(in)
! и не изменяется (гарантия целостности фильтрующего списка).
recursive subroutine Delete_matching(node, other_head, length)
type(ListNode), allocatable, intent(inout) :: node
type(ListNode), allocatable, intent(in) :: other_head
integer(I_), intent(inout) :: length
type(ListNode), allocatable :: tail
if (.not. allocated(node)) return
if (Is_present(node%line, other_head)) then
! Забираем хвост узла, удаляем сам узел, ставим хвост на его место
call move_alloc(node%next, tail)
deallocate(node)
call move_alloc(tail, node)
length = length - 1
call Delete_matching(node, other_head, length) ! хвостовой вызов
else
call Delete_matching(node%next, other_head, length) ! хвостовой вызов
end if
end subroutine Delete_matching
end subroutine Exclude
! ------------------------------------------------------------
! Уничтожение списка (хвостовая рекурсия через вложенную процедуру)
subroutine Destroy(this)
class(List), intent(inout) :: this
call Destroy_node(this%head)
this%length = 0
end subroutine Destroy
! Хвостовая рекурсия: освобождает узлы один за другим
recursive subroutine Destroy_node(node)
type(ListNode), allocatable, intent(inout) :: node
type(ListNode), allocatable :: tail
if (.not. allocated(node)) return
call move_alloc(node%next, tail)
deallocate(node)
call Destroy_node(tail) ! хвостовой вызов
end subroutine Destroy_node
! ------------------------------------------------------------
! Завершаемая процедура (final): гарантирует освобождение списка
! при выходе из области видимости объекта типа List
recursive subroutine Finalize_list(this)
type(List), intent(inout) :: this
call Destroy_node(this%head)
this%length = 0
end subroutine Finalize_list
end module IO
program lab3_variant13
use Environment
use IO
implicit none
character(*), parameter :: input_file = "../data/input.txt" ! исходные строки
character(*), parameter :: delete_file = "../data/delete.txt" ! строки для удаления
character(*), parameter :: output_file = "output.txt"
type(List) :: S, D
! 1. Формирование односвязного списка S из файла In
call S%ReadFromFile(input_file)
! 2. Формирование списка D из файла Delete
call D%ReadFromFile(delete_file)
! 3. Исключение из списка S элементов, присутствующих в D
call S%Exclude(D)
! 4. Вывод результата в выходной файл
call S%WriteToFile(output_file, "rewind", CH_"Результат после удаления:")
! 5. Уничтожение списков
call S%Destroy()
call D%Destroy()
end program lab3_variant13
ERROR
# Crash reproducer for clang version 22.1.1 (https://github.com/llvm/llvm-project.git fef02d48c08db859ef83f84232ed78bd9d1c323a)
# Driver args: "-std=f2018" "-fimplicit-none" "-Jobj/" "-module-dir" "obj/" "-O0" "-c" "src/main.f90" "-o" "obj/main.o"
# Original command: "/usr/local/bin/flang" "-fc1" "-triple" "x86_64-unknown-linux-gnu" "-emit-obj" "-fimplicit-none" "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie" "-target-cpu" "x86-64" "-std=f2018" "-module-dir" "obj/" "-module-dir" "obj/" "-resource-dir" "/usr/local/lib/clang/22" "-mframe-pointer=all" "-O0" "-o" "obj/main.o" "-x" "f95" "src/main.f90"
"/usr/local/bin/flang" "-fc1" "-triple" "x86_64-unknown-linux-gnu" "-emit-obj" "-fimplicit-none" "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie" "-target-cpu" "x86-64" "-std=f2018" "-module-dir" "obj/" "-module-dir" "obj/" "-mframe-pointer=all" "-O0" "-x" "f95" "main-183aa5"
----------------------------------------
#line "./src/main.f90" 1
program lab3_variant13
use Environment
use IO
implicit none
character(*), parameter :: input_file = "../data/input.txt"
character(*), parameter :: delete_file = "../data/delete.txt"
character(*), parameter :: output_file = "output.txt"
type(List) :: S, D
call S%ReadFromFile(input_file)
call D%ReadFromFile(delete_file)
call S%Exclude(D)
call S%WriteToFile(output_file, "rewind", CH_"Результат �&
&�осле удаления:")
call S%Destroy()
call D%Destroy()
end program lab3_variant13
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs