[flang-commits] [flang] [flang][OpenACC] Accept ROUTINE directive within an interface block (PR #206863)

Eugene Epshteyn via flang-commits flang-commits at lists.llvm.org
Tue Jun 30 17:01:50 PDT 2026


https://github.com/eugeneepshteyn created https://github.com/llvm/llvm-project/pull/206863

An `!$acc routine` directive placed directly within an interface block (as an
interface-specification, e.g. preceding the interface body it names) failed to
parse and produced a misleading cascade of errors.

Accept the OpenACC ROUTINE directive as an additional interface-specification
alternative, mirroring the existing extension that allows a ROUTINE directive in
a module subprogram part / at the top level. The grammar is widened narrowly to
the ROUTINE construct only (not the whole OpenACC declarative construct). A named
directive applies to the interface body it names; name resolution already runs in
a separate pass after the interface-body symbols are created, so the
directive-before-body ordering resolves correctly and the ROUTINE information is
attached to the named procedure's symbol.

This is documented as a Flang extension in OpenACC-extensions.md.

>From 1278e93c95c897c1708819519b275d5ea49f2fc4 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Tue, 30 Jun 2026 19:47:41 -0400
Subject: [PATCH 1/2] [flang][OpenACC] Accept ROUTINE directive within an
 interface block

An `!$acc routine` directive placed directly within an interface block (as an
interface-specification, e.g. preceding the interface body it names) failed to
parse and produced a misleading cascade of errors.

Accept the OpenACC ROUTINE directive as an additional interface-specification
alternative, mirroring the existing extension that allows a ROUTINE directive in
a module subprogram part / at the top level. The grammar is widened narrowly to
the ROUTINE construct only (not the whole OpenACC declarative construct). A named
directive applies to the interface body it names; name resolution already runs in
a separate pass after the interface-body symbols are created, so the
directive-before-body ordering resolves correctly and the ROUTINE information is
attached to the named procedure's symbol.

This is documented as a Flang extension in OpenACC-extensions.md.
---
 flang/docs/OpenACC-extensions.md              |  7 +++++
 flang/include/flang/Parser/parse-tree.h       |  6 ++++-
 flang/lib/Parser/program-parsers.cpp          |  4 +++
 .../test/Parser/acc-routine-in-interface.f90  | 26 +++++++++++++++++++
 .../OpenACC/acc-routine-in-interface.f90      | 17 ++++++++++++
 5 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Parser/acc-routine-in-interface.f90
 create mode 100644 flang/test/Semantics/OpenACC/acc-routine-in-interface.f90

diff --git a/flang/docs/OpenACC-extensions.md b/flang/docs/OpenACC-extensions.md
index d2076122f9ece..c22f00efec758 100644
--- a/flang/docs/OpenACC-extensions.md
+++ b/flang/docs/OpenACC-extensions.md
@@ -34,6 +34,13 @@ These extensions require no flag.
 * The `if` clause accepts scalar integer expressions in addition to scalar
   logical expressions.
 * `!$acc routine` directives can be placed at the top level.
+* `!$acc routine` directives can be placed directly within an interface block
+  (i.e. as an interface-specification, such as preceding the interface body they
+  name). The OpenACC specification only permits the named `routine` directive in
+  the specification part of a subroutine, function, or module, and the unnamed
+  form within an interface body; Flang additionally accepts a `routine`
+  directive between the `INTERFACE` statement and the interface bodies, applying
+  a named directive to the interface body it names.
 * `!$acc cache` directives accept scalar variables.
 * `!$acc cache` directives are accepted outside of a loop construct.
 * The `!$acc declare` directive accepts assumed-size array arguments for
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 4b574ba352c89..84c22c21cf30b 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3237,10 +3237,14 @@ struct ProcedureStmt {
 
 // R1502 interface-specification ->
 //         interface-body | procedure-stmt | compiler-directive
+// Flang extension: an OpenACC ROUTINE directive is also accepted directly
+// within an interface block, e.g. a named directive preceding the interface
+// body it applies to.
 struct InterfaceSpecification {
   UNION_CLASS_BOILERPLATE(InterfaceSpecification);
   std::variant<InterfaceBody, Statement<ProcedureStmt>,
-      common::Indirection<CompilerDirective>>
+      common::Indirection<CompilerDirective>,
+      common::Indirection<OpenACCRoutineConstruct>>
       u;
 };
 
diff --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index 530179bd478eb..193f9af0d0f48 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -377,8 +377,12 @@ TYPE_PARSER(construct<InterfaceBlock>(statement(Parser<InterfaceStmt>{}),
 
 // R1502 interface-specification ->
 //         interface-body | procedure-stmt | compiler-directive
+// Flang extension: an OpenACC ROUTINE directive is also accepted directly
+// within an interface block (e.g. preceding the interface body it names).
 TYPE_PARSER(construct<InterfaceSpecification>(Parser<InterfaceBody>{}) ||
     construct<InterfaceSpecification>(statement(Parser<ProcedureStmt>{})) ||
+    construct<InterfaceSpecification>(indirect(skipStuffBeforeStatement >>
+        "!$ACC "_sptok >> Parser<OpenACCRoutineConstruct>{} / endOfLine)) ||
     construct<InterfaceSpecification>(indirect(compilerDirective)))
 
 // R1503 interface-stmt -> INTERFACE [generic-spec] | ABSTRACT INTERFACE
diff --git a/flang/test/Parser/acc-routine-in-interface.f90 b/flang/test/Parser/acc-routine-in-interface.f90
new file mode 100644
index 0000000000000..428268f985165
--- /dev/null
+++ b/flang/test/Parser/acc-routine-in-interface.f90
@@ -0,0 +1,26 @@
+! RUN: %flang_fc1 -fopenacc -fdebug-unparse %s | FileCheck %s
+! RUN: %flang_fc1 -fopenacc -fdebug-dump-parse-tree %s | FileCheck %s --check-prefix=TREE
+
+! Flang extension: an !$acc routine directive is accepted directly within an
+! interface block (as an interface-specification), e.g. preceding the named
+! interface body it applies to.  The OpenACC specification only permits the
+! named routine directive in the specification part of a subroutine, function,
+! or module.
+
+program p
+  implicit none
+  interface
+  !$acc routine (foo) seq
+  subroutine foo() bind(c, name="foo")
+  end subroutine foo
+  end interface
+end program p
+
+! CHECK: INTERFACE
+! CHECK: !$ACC ROUTINE(foo) SEQ
+! CHECK: SUBROUTINE foo () BIND(C, NAME="foo")
+! CHECK: END SUBROUTINE foo
+! CHECK: END INTERFACE
+
+! TREE: InterfaceSpecification -> OpenACCRoutineConstruct
+! TREE: InterfaceSpecification -> InterfaceBody -> Subroutine
diff --git a/flang/test/Semantics/OpenACC/acc-routine-in-interface.f90 b/flang/test/Semantics/OpenACC/acc-routine-in-interface.f90
new file mode 100644
index 0000000000000..d2a6fd0c083d1
--- /dev/null
+++ b/flang/test/Semantics/OpenACC/acc-routine-in-interface.f90
@@ -0,0 +1,17 @@
+! RUN: %flang_fc1 -fopenacc -fdebug-dump-symbols %s 2>&1 | FileCheck %s
+
+! Flang extension: a named !$acc routine directive placed directly within an
+! interface block applies to the interface body it names.  Verify that the
+! ROUTINE information is attached to the named procedure's symbol and that no
+! diagnostic is produced.
+
+program p
+  implicit none
+  interface
+  !$acc routine (foo) seq
+  subroutine foo() bind(c, name="foo")
+  end subroutine foo
+  end interface
+end program p
+
+! CHECK: foo, BIND(C), EXTERNAL (Subroutine){{.*}}openACCRoutineInfos: seq

>From ef6bc315127b896b1dae1ca503fe5e99f9d307fe Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Tue, 30 Jun 2026 20:00:04 -0400
Subject: [PATCH 2/2] Additional test for interface mismatch

---
 ...acc-routine-in-interface-name-mismatch.f90 | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 flang/test/Semantics/OpenACC/acc-routine-in-interface-name-mismatch.f90

diff --git a/flang/test/Semantics/OpenACC/acc-routine-in-interface-name-mismatch.f90 b/flang/test/Semantics/OpenACC/acc-routine-in-interface-name-mismatch.f90
new file mode 100644
index 0000000000000..6cba5878baf9d
--- /dev/null
+++ b/flang/test/Semantics/OpenACC/acc-routine-in-interface-name-mismatch.f90
@@ -0,0 +1,35 @@
+! RUN: %flang_fc1 -fopenacc -fdebug-dump-symbols %s 2>&1 | FileCheck %s --implicit-check-not=openACCRoutineInfos
+
+! When the name on an !$acc routine directive in an interface block matches no
+! interface body, flang resolves it the same lenient way it does in every other
+! position: the name is bound to an (implicit) external procedure rather than
+! diagnosed, the directive is accepted without a crash, and the interface body
+! receives no ROUTINE information.  Both placements of the directive are covered:
+!   - 'm_in_block': the directive sits directly in the interface block.
+!   - 'm_in_body': the directive sits inside the subroutine interface body.
+
+module m_in_block
+  implicit none
+  interface
+  !$acc routine (no_block) seq
+  subroutine sub_block() bind(c, name="sub_block")
+  end subroutine sub_block
+  end interface
+end module m_in_block
+
+module m_in_body
+  implicit none
+  interface
+  subroutine sub_body() bind(c, name="sub_body")
+  !$acc routine (no_body) seq
+  end subroutine sub_body
+  end interface
+end module m_in_body
+
+! Each mismatched name resolves to an implicit external procedure ...
+! CHECK-DAG: no_block: ProcEntity
+! CHECK-DAG: no_body: ProcEntity
+! ... and neither interface body receives the ROUTINE information (asserted by
+! --implicit-check-not=openACCRoutineInfos on the RUN line).
+! CHECK-DAG: sub_block, BIND(C), EXTERNAL, PUBLIC (Subroutine): Subprogram isInterface
+! CHECK-DAG: sub_body, BIND(C), EXTERNAL, PUBLIC (Subroutine): Subprogram isInterface



More information about the flang-commits mailing list