Skip to content

Commit c020044

Browse files
authored
Parse intrinsic and non_intrinsic used modules (#920)
2 parents 6d33e74 + 6e3ca2b commit c020044

File tree

7 files changed

+276
-58
lines changed

7 files changed

+276
-58
lines changed

ci/run_tests.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ pushd circular_example
3131
"$fpm" build
3232
popd
3333

34+
pushd nonintrinsic
35+
"$fpm" build
36+
popd
37+
3438
pushd hello_complex
3539
"$fpm" build
3640
"$fpm" test
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/*
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
program test_nonintr
2+
use, non_intrinsic :: iso_fortran_env
3+
4+
! ijk=0 can be read
5+
stop ijk
6+
end program test_nonintr
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
name = "non-intrinsic"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module iso_fortran_env
2+
implicit none
3+
integer, parameter :: ijk = 0
4+
end module iso_fortran_env

src/fpm_source_parsing.f90

Lines changed: 123 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,7 @@ module fpm_source_parsing
2727
implicit none
2828

2929
private
30-
public :: parse_f_source, parse_c_source
31-
32-
character(15), parameter :: INTRINSIC_MODULE_NAMES(*) = &
33-
['iso_c_binding ', &
34-
'iso_fortran_env', &
35-
'ieee_arithmetic', &
36-
'ieee_exceptions', &
37-
'ieee_features ', &
38-
'omp_lib ']
30+
public :: parse_f_source, parse_c_source, parse_use_statement
3931

4032
contains
4133

@@ -77,7 +69,7 @@ function parse_f_source(f_filename,error) result(f_source)
7769
type(srcfile_t) :: f_source
7870
type(error_t), allocatable, intent(out) :: error
7971

80-
logical :: inside_module, inside_interface
72+
logical :: inside_module, inside_interface, using, intrinsic_module
8173
integer :: stat
8274
integer :: fh, n_use, n_include, n_mod, n_parent, i, j, ic, pass
8375
type(string_t), allocatable :: file_lines(:), file_lines_lower(:)
@@ -179,59 +171,24 @@ function parse_f_source(f_filename,error) result(f_source)
179171
end if
180172

181173
! Process 'USE' statements
182-
if (index(file_lines_lower(i)%s,'use ') == 1 .or. &
183-
index(file_lines_lower(i)%s,'use::') == 1) then
174+
call parse_use_statement(f_filename,i,file_lines_lower(i)%s,using,intrinsic_module,mod_name,error)
175+
if (allocated(error)) return
184176

185-
if (index(file_lines_lower(i)%s,'::') > 0) then
177+
if (using) then
186178

187-
temp_string = split_n(file_lines_lower(i)%s,delims=':',n=2,stat=stat)
188-
if (stat /= 0) then
189-
call file_parse_error(error,f_filename, &
190-
'unable to find used module name',i, &
191-
file_lines_lower(i)%s,index(file_lines_lower(i)%s,'::'))
192-
return
193-
end if
179+
! Not a valid module name?
180+
if (.not.is_fortran_name(mod_name)) cycle
194181

195-
mod_name = split_n(temp_string,delims=' ,',n=1,stat=stat)
196-
if (stat /= 0) then
197-
call file_parse_error(error,f_filename, &
198-
'unable to find used module name',i, &
199-
file_lines_lower(i)%s)
200-
return
201-
end if
202-
203-
else
204-
205-
mod_name = split_n(file_lines_lower(i)%s,n=2,delims=' ,',stat=stat)
206-
if (stat /= 0) then
207-
call file_parse_error(error,f_filename, &
208-
'unable to find used module name',i, &
209-
file_lines_lower(i)%s)
210-
return
211-
end if
212-
213-
end if
214-
215-
if (.not.is_fortran_name(mod_name)) then
216-
cycle
217-
end if
218-
219-
if (any([(index(mod_name,trim(INTRINSIC_MODULE_NAMES(j)))>0, &
220-
j=1,size(INTRINSIC_MODULE_NAMES))])) then
221-
cycle
222-
end if
182+
! Valid intrinsic module: not a dependency
183+
if (intrinsic_module) cycle
223184

224185
n_use = n_use + 1
225186

226-
if (pass == 2) then
227-
228-
f_source%modules_used(n_use)%s = mod_name
229-
230-
end if
187+
if (pass == 2) f_source%modules_used(n_use)%s = mod_name
231188

232189
cycle
233190

234-
end if
191+
endif
235192

236193
! Process 'INCLUDE' statements
237194
ic = index(file_lines_lower(i)%s,'include')
@@ -655,5 +612,117 @@ function parse_sequence(string,t1,t2,t3,t4) result(found)
655612

656613
end function parse_sequence
657614

615+
! USE [, intrinsic] :: module_name [, only: only_list]
616+
! USE [, non_intrinsic] :: module_name [, only: only_list]
617+
subroutine parse_use_statement(f_filename,i,line,use_stmt,is_intrinsic,module_name,error)
618+
619+
!> Current file name and line number (for error messaging)
620+
character(*), intent(in) :: f_filename
621+
integer, intent(in) :: i
622+
623+
!> The line being parsed. MUST BE preprocessed with trim(adjustl()
624+
character(*), intent(in) :: line
625+
626+
!> Does this line contain a `use` statement?
627+
logical, intent(out) :: use_stmt
628+
629+
!> Is the module in this statement intrinsic?
630+
logical, intent(out) :: is_intrinsic
631+
632+
!> used module name
633+
character(:), allocatable, intent(out) :: module_name
634+
635+
!> Error handling
636+
type(error_t), allocatable, intent(out) :: error
637+
638+
character(15), parameter :: INTRINSIC_NAMES(*) = &
639+
['iso_c_binding ', &
640+
'iso_fortran_env', &
641+
'ieee_arithmetic', &
642+
'ieee_exceptions', &
643+
'ieee_features ', &
644+
'omp_lib ']
645+
646+
character(len=:), allocatable :: temp_string
647+
integer :: colons,intr,nonintr,j,stat
648+
logical :: has_intrinsic_name
649+
650+
use_stmt = .false.
651+
is_intrinsic = .false.
652+
if (len_trim(line)<=0) return
653+
654+
! Quick check that the line is preprocessed
655+
if (line(1:1)==' ') then
656+
call fatal_error(error,'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement')
657+
return
658+
end if
659+
660+
! 'use' should be the first string in the adjustl line
661+
use_stmt = index(line,'use ')==1 .or. index(line,'use::')==1 .or. index(line,'use,')==1
662+
if (.not.use_stmt) return
663+
colons = index(line,'::')
664+
nonintr = 0
665+
intr = 0
666+
667+
have_colons: if (colons>3) then
668+
669+
! there may be an intrinsic/non-intrinsic spec
670+
nonintr = index(line(1:colons-1),'non_intrinsic')
671+
if (nonintr==0) intr = index(line(1:colons-1),'intrinsic')
672+
673+
674+
temp_string = split_n(line,delims=':',n=2,stat=stat)
675+
if (stat /= 0) then
676+
call file_parse_error(error,f_filename, &
677+
'unable to find used module name',i, &
678+
line,colons)
679+
return
680+
end if
681+
682+
module_name = split_n(temp_string,delims=' ,',n=1,stat=stat)
683+
if (stat /= 0) then
684+
call file_parse_error(error,f_filename, &
685+
'unable to find used module name',i, &
686+
line)
687+
return
688+
end if
689+
690+
else
691+
692+
module_name = split_n(line,n=2,delims=' ,',stat=stat)
693+
if (stat /= 0) then
694+
call file_parse_error(error,f_filename, &
695+
'unable to find used module name',i, &
696+
line)
697+
return
698+
end if
699+
700+
end if have_colons
701+
702+
! If declared intrinsic, check that it is true
703+
has_intrinsic_name = any([(index(module_name,trim(INTRINSIC_NAMES(j)))>0, &
704+
j=1,size(INTRINSIC_NAMES))])
705+
if (intr>0 .and. .not.has_intrinsic_name) then
706+
707+
! An intrinsic module was not found. Its name could be in the next line,
708+
! in which case, we just skip this check. The compiler will do the job if the name is invalid.
709+
710+
! Module name was not read: it's in the next line
711+
if (index(module_name,'&')<=0) then
712+
call file_parse_error(error,f_filename, &
713+
'module '//module_name//' is declared intrinsic but it is not ',i, &
714+
line)
715+
return
716+
endif
717+
endif
718+
719+
! Should we treat this as an intrinsic module
720+
is_intrinsic = nonintr==0 .and. & ! not declared non-intrinsic
721+
(intr>0 .or. has_intrinsic_name)
722+
723+
end subroutine parse_use_statement
724+
725+
726+
658727
end module fpm_source_parsing
659728

0 commit comments

Comments
 (0)