Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong source type originating from parse_f_source #1073

Open
ivan-pi opened this issue Sep 22, 2024 · 3 comments · May be fixed by #1074
Open

Wrong source type originating from parse_f_source #1073

ivan-pi opened this issue Sep 22, 2024 · 3 comments · May be fixed by #1074
Labels
bug Something isn't working

Comments

@ivan-pi
Copy link
Member

ivan-pi commented Sep 22, 2024

Description

The function parse_f_source returns the wrong source type for the following module:

module foo
public :: bar
abstract interface
    subroutine bar() bind(c)
    end subroutine
end interface
end module foo

Expected Behaviour

Instead of FPM_UNIT_MODULE (=2) it returns FPM_UNIT_SUBPROGRAM (=4). Removing the bind(c) makes the source parser work correctly.

Version of fpm

Version: 0.8.1, alpha

Platform and Architecture

MacOS

Additional Information

No response

@ivan-pi ivan-pi added the bug Something isn't working label Sep 22, 2024
@ivan-pi
Copy link
Member Author

ivan-pi commented Sep 22, 2024

Here is a possible test for the issue:

!> Check parsing of module containing abstract interface with bind(c) attribute
!>   See also https://github.com/fortran-lang/fpm/issues/1073
subroutine test_module_with_abstract_interface_c_binding(error)

    type(error_t), allocatable, intent(out) :: error

    integer :: unit
    character(:), allocatable :: temp_file
    type(srcfile_t), allocatable :: f_source

    allocate(temp_file,source=get_temp_filename())
    open(file=tempfile,newunit=unit)
    write(unit, '(A)') &
    & 'module foo', &
    & 'abstract interface', &
    & '   subroutine bar1()', &
    & '   end subroutine', &
    & '   subroutine bar2() bind(c)', &
    & '   end subroutine', &
    & 'end interface', &
    & 'end module foo'

    close(unit)
    f_source = parse_f_source(temp_file,error)

    if (allocated(error)) return

    if (f_source%unit_type /= FPM_UNIT_MODULE) then
        call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_MODULE')
        return
    end if
    if (size(f_source%modules_provided) /= 1) then
        call test_failed(error,'Wrong number of modules provided - expecting one')
        return
    end if
    if (size(f_source%modules_used) /= 0) then
        call test_failed(error,'Incorrect number of modules_used - expecting zero')
        return
    end if

    call f_source%test_serialization('srcfile_t: serialization', error)
end subroutine test_module_with_abstract_interface

@ivan-pi
Copy link
Member Author

ivan-pi commented Sep 22, 2024

I think the cause is a clash between how the parser handles C bindings and how it determines if it is in an interface:

! Detect exported C-API via bind(C)
if (.not.inside_interface .and. &
parse_subsequence(file_lines_lower(i)%s,'bind','(','c')) then

! Detect beginning of interface block
if (index(file_lines_lower(i)%s,'interface') == 1) then
inside_interface = .true.
cycle
end if
! Detect end of interface block
if (parse_sequence(file_lines_lower(i)%s,'end','interface')) then
inside_interface = .false.
cycle
end if

Maybe changing the predicate at L156 to

if (index(file_lines_lower(i)%s,'interface') == 1) &
    .or. parse_sequence(file_lines_lower(i)%s,'abstract','interface')) then
   ! ...
end if

would fix the issue.

ivan-pi pushed a commit to ivan-pi/fpm that referenced this issue Sep 22, 2024
@ivan-pi ivan-pi linked a pull request Sep 22, 2024 that will close this issue
@ivan-pi
Copy link
Member Author

ivan-pi commented Sep 22, 2024

The problem also occurs when an abstract interface containing a bind(c) procedure is in a program unit. For instance, the following get misclassified as FPM_UNIT_SUBPROGRAM (=4):

program my_program
implicit none
abstract interface
   function cmpfunc(a,b) bind(c)
     use, intrinsic :: iso_c_binding
     type(c_ptr), intent(in), value :: a, b
     integer(c_int) :: cmpfunc
   end function
end interface
interface
   subroutine qsort(ptr,count,size,comp) bind(c,name="qsort")
     use, intrinsic :: iso_c_binding
     type(c_ptr), value :: ptr
     integer(c_size_t), value :: count, size
     type(c_funptr), value :: comp
  end subroutine
end interface
end program my_program

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant