OpenACC (as OpenMP) permits some directives in the 'specification part'
In Fortran (here: Fortran 2018), the latter is: R504 specification-part is [use-stmt]... [import-stmt]... [implicit-part] [declaration-construct]... which is an ordered list (first use, then import etc.). Hence, gfortran's state_order lists the latter separately: enum state_order {ORDER_START, ORDER_USE, ORDER_IMPORT, ORDER_IMPLICIT_NONE, ORDER_IMPLICIT, ORDER_SPEC, ORDER_EXEC}; Currently, 'acc declare' and 'acc routine' are placed into '#define case_decl' which implies ORDER_SPEC. This patch adds them to the related OpenMP constructs ('case_omp_decl'), which does not touch the current state and just checks that the ST_... appear before ORDER_EXEC. If there are no comments, I intent to commit it later today. Tobias PS: Thanks to Thomas for pointing me to the PR. ----------------- Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Fortran: Fix OpenACC in specification-part checks [PR90111] OpenACC's routine and declare directives can appear anywhere in the specification part, i.e. before/after use-stmts, import-stmt, implicit-part, or declaration-constructs. gcc/fortran/ChangeLog: PR fortran/90111 * parse.c (case_decl): Move ST_OACC_ROUTINE and ST_OACC_DECLARE to ... (case_omp_decl): ... here: (verify_st_order): Update comment. gcc/testsuite/ChangeLog: PR fortran/90111 * gfortran.dg/goacc/specification-part.f90: New test. gcc/fortran/parse.c | 11 +-- .../gfortran.dg/goacc/specification-part.f90 | 100 +++++++++++++++++++++ 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index e57669c51e5..ec7abc240d6 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -1628,24 +1628,25 @@ next_statement (void) case ST_OACC_DATA: case ST_OACC_HOST_DATA: case ST_OACC_LOOP: \ case ST_OACC_KERNELS_LOOP: case ST_OACC_SERIAL_LOOP: case ST_OACC_SERIAL: \ case ST_OACC_ATOMIC /* Declaration statements */ #define case_decl case ST_ATTR_DECL: case ST_COMMON: case ST_DATA_DECL: \ case ST_EQUIVALENCE: case ST_NAMELIST: case ST_STATEMENT_FUNCTION: \ - case ST_TYPE: case ST_INTERFACE: case ST_PROCEDURE: case ST_OACC_ROUTINE: \ - case ST_OACC_DECLARE + case ST_TYPE: case ST_INTERFACE: case ST_PROCEDURE -/* OpenMP declaration statements. */ +/* OpenMP and OpenACC declaration statements, which may appear anywhere in + the specification part. */ #define case_omp_decl case ST_OMP_THREADPRIVATE: case ST_OMP_DECLARE_SIMD: \ case ST_OMP_DECLARE_TARGET: case ST_OMP_DECLARE_REDUCTION: \ - case ST_OMP_REQUIRES + case ST_OMP_REQUIRES: case ST_OACC_ROUTINE: case ST_OACC_DECLARE + /* Block end statements. Errors associated with interchanging these are detected in gfc_match_end(). */ #define case_end case ST_END_BLOCK_DATA: case ST_END_FUNCTION: \ case ST_END_PROGRAM: case ST_END_SUBROUTINE: \ case ST_END_BLOCK: case ST_END_ASSOCIATE @@ -2808,17 +2809,17 @@ verify_st_order (st_state *p, gfc_statement st, bool silent) case_decl: if (p->state >= ORDER_EXEC) goto order; if (p->state < ORDER_SPEC) p->state = ORDER_SPEC; break; case_omp_decl: - /* The OpenMP directives have to be somewhere in the specification + /* The OpenMP/OpenACC directives have to be somewhere in the specification part, but there are no further requirements on their ordering. Thus don't adjust p->state, just ignore them. */ if (p->state >= ORDER_EXEC) goto order; break; case_executable: case_exec_markers: diff --git a/gcc/testsuite/gfortran.dg/goacc/specification-part.f90 b/gcc/testsuite/gfortran.dg/goacc/specification-part.f90 new file mode 100644 index 00000000000..14af6aecc7d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/specification-part.f90 @@ -0,0 +1,100 @@ +! { dg-do compile } +! +! PR fortran/90111 +! +! Check that OpenACC directives in everywhere in specification part, +! i.e. it may appear before/after the use, import, implicit, and declaration +! + +module m +end module m + +subroutine foo0(kk) + use m + implicit none + integer :: jj, kk + !$acc routine +end + +subroutine foo1() + use m + implicit none + !$acc routine + integer :: jj +end + +subroutine foo2() + use m + !$acc routine + implicit none +end + +subroutine foo3() + !$acc routine + use m + implicit none +end + +module m2 + interface + subroutine foo0(kk) + use m + import + implicit none + integer :: kk + !$acc routine + end + subroutine foo1() + use m + import + implicit none + !$acc routine + end + subroutine foo2() + use m + import + !$acc routine + implicit none + end + subroutine foo3() + use m + !$acc routine + import + implicit none + end + subroutine foo4() + use m + !$acc routine + import + implicit none + end + end interface +end module m2 + +subroutine bar0() + use m + implicit none + integer :: ii + !$acc declare copyin(ii) +end + +subroutine bar1() + use m + implicit none + !$acc declare copyin(ii) + integer :: ii +end + +subroutine bar2() + use m + !$acc declare copyin(ii) + implicit none + integer :: ii +end + +subroutine bar3() + !$acc declare copyin(ii) + use m + implicit none + integer :: ii +end