Errror in pointer list abstract writer

I have the following simple example program:

module abstract_writer
  implicit none
  private
  public :: writer_type
  
  type, abstract :: writer_type
  contains
    procedure(write_integer_interface), deferred :: write_integer
    generic :: write =>  write_integer

  end type

  abstract interface
    subroutine write_integer_interface(writer, v)
      import writer_type
      class(writer_type),intent(inout) :: writer
      integer, intent(in) :: v(:) 
    end subroutine

  end interface

end module abstract_writer

And some concrete writers:

module screen_writer_mod
    use abstract_writer, only: writer_type
    implicit none

    type, extends(writer_type) :: screen_writer_type
    contains
        procedure ::  write_integer => write_integer_to_screen
    end type

contains

subroutine write_integer_to_screen(writer, v)
    class(screen_writer_type), intent(inout) :: writer
    integer, intent(in)  :: v(:)
    print *, 'integer', v
end subroutine

end module
    

and a pointer list one

module writer_pointer_mod
    use abstract_writer, only: writer_type
    implicit none
    private
    public :: pointer_writer_type, append_writer
    type writer_ptr
        class(writer_type), pointer :: ptr => null()
    end type

    type, extends(writer_type) :: pointer_writer_type
        type(writer_ptr), allocatable :: writer_list(:)
    contains
        procedure :: write_integer => write_integer_from_list
    end type

contains

subroutine append_writer(writer_cont, writer)
    type(pointer_writer_type), intent(inout) :: writer_cont
    class(writer_type), pointer, intent(in) :: writer
    
    if (.not. allocated(writer_cont%writer_list)) allocate(writer_cont%writer_list(0))
     
    writer_cont%writer_list = [writer_cont%writer_list, writer_ptr(writer)]
end subroutine

subroutine write_integer_from_list(writer, v)
    class(pointer_writer_type), intent(inout) :: writer
    integer, intent(in)  :: v(:)
    integer:: n, i

    if (.not. allocated(writer%writer_list)) return
    n = size(writer%writer_list)
    do i=1,n
        if (.not.associated(writer%writer_list(i)%ptr)) cycle
        call writer%writer_list(i)%ptr%write(v)
    end do    

end subroutine

end module

Where I’m storing pointer to the writers in an array.

And of course the main

module writer_user
    use abstract_writer, only: writer_type
    implicit none

contains
    subroutine use_writer(writer)
        class(writer_type) :: writer

        integer,allocatable :: x(:)
        
        x = [1,2,3,4,5,6,7,8,9,10]
        
        call writer%write(x)
        

    end subroutine
end module

program main
  use screen_writer_mod, only: screen_writer_type
  use writer_pointer_mod, only: pointer_writer_type, append_writer
  use writer_user, only: use_writer
  implicit none

  type(screen_writer_type), target :: swriter

  type(pointer_writer_type) :: pwriter

  print *,'Appending new writers'
  call append_writer(pwriter, swriter)
  
  call use_writer(pwriter)

end program main

Now.
gfortran 13.2 accept and runs it:

[g2egiova@viz06 abstract_write_lf_bug]$ fpm run --compiler gfortran
abstract_writer.f90                    done.
writer_pointer_mod.f90                 done.
writer_user.f90                        done.
screen_writer.f90                      done.
libabstract_writer.a                   done.
main.f90                               done.
abstract_writer                        done.
[100%] Project compiled successfully.
 Appending new writers
 integer           1           2           3           4           5           6           7           8           9          10

ifx (IFX) 2023.2.0 20230721 rejects it

[g2egiova@viz06 abstract_write_lf_bug]$ fpm run --compiler ifx
abstract_writer.f90                    done.
writer_pointer_mod.f90                 done.
writer_user.f90                        done.
screen_writer.f90                      done.
libabstract_writer.a                   done.
main.f90                               failed.
[ 85%] Compiling...
app/main.f90(12): error #6633: The type of the actual argument differs from the type of the dummy argument.   [SWRITER]
  call append_writer(pwriter, swriter)
------------------------------^
compilation aborted for app/main.f90 (code 1)
<ERROR> Compilation failed for object " app_main.f90.o "
<ERROR> stopping due to failed compilation
STOP 1

lfortran (LFortran version: 0.67.0-35-g44a399676) compiles it but fail to execute

[g2egiova@viz06 abstract_write_lf_bug]$ fpm run --compiler lfortran --flag --realloc-lhs-arrays
abstract_writer.f90                    done.
writer_pointer_mod.f90                 done.
writer_user.f90                        done.
screen_writer.f90                      done.
libabstract_writer.a                   done.
main.f90                               done.
abstract_writer                        done.
[100%] Project compiled successfully.
Appending new writers
free(): double free detected in tcache 2
<ERROR> Execution for object " abstract_writer " returned exit code  134
<ERROR> *cmd_run*:stopping due to failed executions
STOP 134

Is the program correct, is it a bug in that, not very new, version of ifx, there could be a way to make it work with lfortran?

I’ve tried your code with LLMs, and I got this page (which says that the compiler bug was fixed in ifx 2025.1):
https://community.intel.com/t5/Intel-Fortran-Compiler/Problem-with-pointer-to-extended-type/m-p/1582183

Here is an excerpt from the output:

The suspicious line: call append_writer(pwriter, swriter)

Here a nonpointer variable with the TARGET attribute is passed to a pointer dummy argument:

type(screen_writer_type), target :: swriter          ! actual: nonpointer, non-polymorphic, extended type
...
class(writer_type), pointer, intent(in) :: writer   ! dummy: polymorphic pointer, base type
  1. The original rule: a pointer dummy argument required a pointer actual argument.
  2. Added in Fortran 2008: if the dummy has INTENT(IN) and the pointer assignment writer => swriter would be valid, a TARGET variable can be passed directly. The dummy then becomes pointer-associated with swriter. This is sometimes called “auto-targeting.”
  3. The problem was the wording: the original F2008 text (12.5.2.5) required that the actual argument corresponding to a pointer or allocatable dummy be polymorphic if and only if the dummy is polymorphic, and have the same declared type. Read literally, passing type(screen_writer_type) (non-polymorphic, different declared type) to class(writer_type), pointer violates this.
  4. The fix: this was recognized as an oversight and corrected by interpretation F08/0059. In F2018, the requirement applies only when the actual argument itself has the POINTER or ALLOCATABLE attribute.

So a compiler that implements the original F2008 wording literally will reject this call. In fact, the same pattern (a TARGET actual passed to a CLASS(...), POINTER, INTENT(IN) dummy) was reported on the Intel forum in March 2024. Intel rejected it with “The type of the actual argument differs from the type of the dummy argument”; it was filed as a bug, and Intel stated that the issue was fixed in ifx 2025.1.

and the suggested fixes:

Option 1 (recommended): on the caller side, go through a polymorphic pointer whose declared type is writer_type. Then the actual and dummy are both polymorphic with the same declared type, which is valid under both the old and new readings, so any compiler should accept it. The change is only three lines in the main program:

use abstract_writer, only: writer_type
...
class(writer_type), pointer :: wp
...
wp => swriter
call append_writer(pwriter, wp)

Option 2: make the dummy argument of append_writer a nonpointer with the TARGET attribute:

class(writer_type), target :: writer

This also works with gfortran and flang, but there are two caveats:

  • If the caller’s actual argument lacks the TARGET attribute, the stored pointer becomes undefined (dangling) after the procedure returns, and the compiler will not warn you. Option 1 keeps a pointer dummy argument, so this kind of mistake is caught at compile time.
  • If you also add intent(in), flang warns that you are creating a pointer to an INTENT(IN) object (which would allow modifying it through the pointer).

I’ve also tried the code with Flang, and it worked just fine.