[flang-commits] [flang] [Flang][OpenMP] Fix interop-var handling and diagnostics (#203959) (PR #211693)

Sunil Shrestha via flang-commits flang-commits at lists.llvm.org
Fri Jul 24 15:48:27 PDT 2026


https://github.com/sshrestha-aa updated https://github.com/llvm/llvm-project/pull/211693

>From f818eac2a16bdf3725f2f17b07755948a955fcee Mon Sep 17 00:00:00 2001
From: Sunil Shrestha <sunil.shrestha at hpe.com>
Date: Thu, 23 Jul 2026 12:23:24 -0500
Subject: [PATCH 1/2] [Flang][OpenMP] Fix interop-var handling and diagnostics
 (#203959)

This change builds on top of the work done in PR #203959
- Diagnose interop destroy without an interop variable
- Lower array-element / derived-component interop-vars via their designator
- Require interop-var to be a scalar integer of omp_interop_kind
- Remove "hsa" prefer_type (no omp_ifr_hsa in the runtime)
- Fix a latent bug in Parser/OpenMP/interop-construct.f90
---
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 12 +++-
 flang/lib/Semantics/check-omp-structure.cpp   | 56 ++++++++++++++++
 flang/test/Lower/OpenMP/interop.f90           | 27 ++++++++
 .../test/Parser/OpenMP/interop-construct.f90  |  6 +-
 flang/test/Semantics/OpenMP/init-clause.f90   |  1 +
 .../Semantics/OpenMP/interop-construct.f90    | 65 +++++++++++++++++++
 6 files changed, 162 insertions(+), 5 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 387b83793dd1b..ae6039c253732 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -6316,8 +6316,17 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
     }
   }
 
-  // Helper to get the address of an interop variable from an Object.
+  // Helper to get the address of an interop variable from an Object. A
+  // designator such as arr(1) or rec%obj must lower through genExprAddr so we
+  // obtain the address of the actual scalar element/component with the correct
+  // type, rather than the base symbol address (which would be the whole array,
+  // or null for a component defined inside a derived type).
   auto getInteropVarAddr = [&](const Object &object) -> mlir::Value {
+    if (const auto &designator = object.ref()) {
+      fir::ExtendedValue exv =
+          converter.genExprAddr(*designator, stmtCtx, &loc);
+      return fir::getBase(exv);
+    }
     const semantics::Symbol *sym = object.sym();
     assert(sym && "interop variable must have a symbol");
     mlir::Value addr = converter.getSymbolAddress(*sym);
@@ -6376,7 +6385,6 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
                             .Case("sycl", 4)
                             .Case("hip", 5)
                             .Case("level_zero", 6)
-                            .Case("hsa", 7)
                             .Default(std::nullopt);
             if (frId)
               prefValues.push_back(*frId);
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 4e29a1c387ec2..b40909fab76aa 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -5978,6 +5978,48 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
   bool hasInitClause{false};
   int targetCount{0}, targetSyncCount{0};
   std::set<const Symbol *> objectSymbolList;
+  // An interop-var must be a scalar variable of integer type. Reject
+  // non-scalar designators (whole arrays, array sections) and non-integer
+  // designators; array elements and scalar derived-type components are valid.
+  auto checkInteropVar = [&](const parser::OmpObject &object,
+                             parser::CharBlock source) {
+    // Type-parameter inquiries (e.g. x%kind) are diagnosed separately by
+    // CheckTypeParamInquiry, so don't also flag them here.
+    if (const Symbol *sym{GetObjectSymbol(object)};
+        sym && IsTypeParamInquiry(*sym)) {
+      return;
+    }
+    const parser::Designator *designator{GetDesignatorFromObj(object)};
+    if (!designator) {
+      return;
+    }
+    // Analyze the designator only to inspect its rank and type. Permit a
+    // whole assumed-size array so the analyzer does not add its own "may not
+    // appear here" error on top of the interop-specific diagnostic below,
+    // keeping a single clean message for any non-scalar interop-var. This
+    // mirrors other OMP-object checks here.
+    evaluate::ExpressionAnalyzer ea{context_};
+    auto restore{ea.AllowWholeAssumedSizeArray(true)};
+    MaybeExpr expr{ea.Analyze(*designator)};
+    if (!expr) {
+      return;
+    }
+    if (expr->Rank() != 0) {
+      context_.Say(source,
+          "The interop variable in an INTEROP construct must be a scalar variable"_err_en_US);
+      return;
+    }
+    // The interop-var must be a scalar integer of omp_interop_kind
+    // (c_intptr_t): the runtime uses its storage as a pointer-sized handle.
+    std::optional<evaluate::DynamicType> type{expr->GetType()};
+    int interopKind{static_cast<int>(
+        context_.targetCharacteristics().integerKindForPointer())};
+    if (!type || type->category() != evaluate::TypeCategory::Integer ||
+        type->kind() != interopKind) {
+      context_.Say(source,
+          "The interop variable in an INTEROP construct must be a scalar integer variable of kind omp_interop_kind"_err_en_US);
+    }
+  };
   const auto &clauseList{std::get<std::optional<parser::OmpClauseList>>(x.v.t)};
   for (const auto &clause : clauseList->v) {
     common::visit(
@@ -6043,6 +6085,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
                   std::get<parser::OmpObject>(initClause.v.t))};
               CheckTypeParamInquiry(
                   clause.source, *interopVar, llvm::omp::Clause::OMPC_init);
+              if (interopVar) {
+                checkInteropVar(*interopVar, clause.source);
+              }
               if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
                 const auto *objectSymbol{name->symbol};
                 if (llvm::is_contained(objectSymbolList, objectSymbol)) {
@@ -6057,8 +6102,16 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
               isDependClauseOccurred = true;
             },
             [&](const parser::OmpClause::Destroy &destroyClause) {
+              if (!destroyClause.v) {
+                context_.Say(GetContext().directiveSource,
+                    "The DESTROY clause on an INTEROP construct must specify an interop variable"_err_en_US);
+                return;
+              }
               const auto *interopVar{
                   parser::Unwrap<parser::OmpObject>(destroyClause.v)};
+              if (interopVar) {
+                checkInteropVar(*interopVar, clause.source);
+              }
               if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
                 const auto *objectSymbol{name->symbol};
                 if (llvm::is_contained(objectSymbolList, objectSymbol)) {
@@ -6074,6 +6127,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
                   parser::Unwrap<parser::OmpObject>(useClause.v)};
               CheckTypeParamInquiry(
                   clause.source, *interopVar, llvm::omp::Clause::OMPC_use);
+              if (interopVar) {
+                checkInteropVar(*interopVar, clause.source);
+              }
               if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
                 const auto *objectSymbol{name->symbol};
                 if (llvm::is_contained(objectSymbolList, objectSymbol)) {
diff --git a/flang/test/Lower/OpenMP/interop.f90 b/flang/test/Lower/OpenMP/interop.f90
index b20332bef6893..1fd9b353b535f 100644
--- a/flang/test/Lower/OpenMP/interop.f90
+++ b/flang/test/Lower/OpenMP/interop.f90
@@ -173,3 +173,30 @@ subroutine test_interop_destroy_device(obj, dev)
   integer :: dev
   !$omp interop destroy(obj) device(dev)
 end subroutine
+
+!===============================================================================
+! Interop Init — array element interop-var
+!===============================================================================
+
+!CHECK-LABEL: func.func @_QPtest_interop_init_array_element(
+!CHECK:         %[[EL:.*]] = hlfir.designate %{{.*}} (%{{.*}}) : (!fir.ref<!fir.array<10xi64>>, index) -> !fir.ref<i64>
+!CHECK:         omp.interop.init %[[EL]] : !fir.ref<i64> interop_types([#omp<interop_type(target)>])
+subroutine test_interop_init_array_element(arr)
+  integer(8) :: arr(10)
+  !$omp interop init(target: arr(1))
+end subroutine
+
+!===============================================================================
+! Interop Use — derived-type component interop-var
+!===============================================================================
+
+!CHECK-LABEL: func.func @_QPtest_interop_use_component(
+!CHECK:         %[[COMP:.*]] = hlfir.designate %{{.*}}{"obj"} : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<i64>
+!CHECK:         omp.interop.use %[[COMP]] : !fir.ref<i64>
+subroutine test_interop_use_component(rec)
+  type t
+    integer(8) :: obj
+  end type
+  type(t) :: rec
+  !$omp interop use(rec%obj)
+end subroutine
diff --git a/flang/test/Parser/OpenMP/interop-construct.f90 b/flang/test/Parser/OpenMP/interop-construct.f90
index c46d15cff8082..a5ae197f3c534 100644
--- a/flang/test/Parser/OpenMP/interop-construct.f90
+++ b/flang/test/Parser/OpenMP/interop-construct.f90
@@ -22,14 +22,14 @@ END SUBROUTINE test_interop_01
 SUBROUTINE test_interop_02()
   USE omp_lib
   INTEGER(OMP_INTEROP_KIND) :: obj1, obj2, obj3
-  !$OMP INTEROP INIT(TARGETSYNC: obj) USE(obj1) DESTROY(obj3)
+  !$OMP INTEROP INIT(TARGETSYNC: obj2) USE(obj1) DESTROY(obj3)
   PRINT *,'pass'
 END SUBROUTINE test_interop_02
 
 !UNPARSE: SUBROUTINE test_interop_02
 !UNPARSE:  USE :: omp_lib
 !UNPARSE:  INTEGER(KIND=8_4) obj1, obj2, obj3
-!UNPARSE: !$OMP INTEROP  INIT(TARGETSYNC: obj) USE(obj1) DESTROY(obj3)
+!UNPARSE: !$OMP INTEROP  INIT(TARGETSYNC: obj2) USE(obj1) DESTROY(obj3)
 !UNPARSE:  PRINT *, "pass"
 !UNPARSE: END SUBROUTINE test_interop_02
 
@@ -37,7 +37,7 @@ END SUBROUTINE test_interop_02
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interop
 !PARSE-TREE: | OmpClauseList -> OmpClause -> Init -> OmpInitClause
 !PARSE-TREE: | | Modifier -> OmpInteropType -> Value = Targetsync
-!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'obj2'
 !PARSE-TREE: | OmpClause -> Use -> OmpUseClause -> OmpObject -> Designator -> DataRef -> Name = 'obj1'
 !PARSE-TREE: | OmpClause -> Destroy -> OmpDestroyClause -> OmpObject -> Designator -> DataRef -> Name = 'obj3'
 !PARSE-TREE: | Flags = {}
diff --git a/flang/test/Semantics/OpenMP/init-clause.f90 b/flang/test/Semantics/OpenMP/init-clause.f90
index e47b0af7d0aa6..714cd9faed880 100644
--- a/flang/test/Semantics/OpenMP/init-clause.f90
+++ b/flang/test/Semantics/OpenMP/init-clause.f90
@@ -24,6 +24,7 @@ subroutine f02
 
 subroutine f03
   integer :: x, y
+  !ERROR: The interop variable in an INTEROP construct must be a scalar integer variable of kind omp_interop_kind
   !ERROR: The 'depinfo-modifier' is not allowed on INTEROP construct
   !$omp interop init(mutexinoutset(x): y)
 end
diff --git a/flang/test/Semantics/OpenMP/interop-construct.f90 b/flang/test/Semantics/OpenMP/interop-construct.f90
index bc32bd80c22a6..987f59536c9fe 100644
--- a/flang/test/Semantics/OpenMP/interop-construct.f90
+++ b/flang/test/Semantics/OpenMP/interop-construct.f90
@@ -28,3 +28,68 @@ SUBROUTINE test_interop_03()
   !$OMP INTEROP INIT(TARGET: obj) DEPEND(INOUT: obj)
   PRINT *, 'pass'
 END SUBROUTINE test_interop_03
+
+SUBROUTINE test_interop_04()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND) :: obj
+  !$OMP INTEROP INIT(TARGETSYNC: obj)
+  !ERROR: The DESTROY clause on an INTEROP construct must specify an interop variable
+  !$OMP INTEROP DESTROY
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_04
+
+SUBROUTINE test_interop_05()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND) :: arr(10)
+  !ERROR: The interop variable in an INTEROP construct must be a scalar variable
+  !$OMP INTEROP INIT(TARGET: arr)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_05
+
+SUBROUTINE test_interop_06()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND) :: arr(10)
+  !ERROR: The interop variable in an INTEROP construct must be a scalar variable
+  !$OMP INTEROP USE(arr(1:5))
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_06
+
+SUBROUTINE test_interop_07()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND) :: arr(10)
+  !ERROR: The interop variable in an INTEROP construct must be a scalar variable
+  !$OMP INTEROP DESTROY(arr)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_07
+
+SUBROUTINE test_interop_08()
+  REAL(8) :: x
+  !ERROR: The interop variable in an INTEROP construct must be a scalar integer variable of kind omp_interop_kind
+  !$OMP INTEROP INIT(TARGET: x)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_08
+
+SUBROUTINE test_interop_09()
+  INTEGER(4) :: obj
+  !ERROR: The interop variable in an INTEROP construct must be a scalar integer variable of kind omp_interop_kind
+  !$OMP INTEROP USE(obj)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_09
+
+SUBROUTINE test_interop_10()
+  INTEGER(4) :: obj
+  !ERROR: The interop variable in an INTEROP construct must be a scalar integer variable of kind omp_interop_kind
+  !$OMP INTEROP DESTROY(obj)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_10
+
+! An array element is a valid interop-var (scalar, of omp_interop_kind) and
+! must be accepted on all action clauses.
+SUBROUTINE test_interop_11()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND) :: arr(10)
+  !$OMP INTEROP INIT(TARGET: arr(1))
+  !$OMP INTEROP USE(arr(1))
+  !$OMP INTEROP DESTROY(arr(1))
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_11

>From 51728e6482aa8ff18ec4f6305c011bbe2aa5c402 Mon Sep 17 00:00:00 2001
From: Sunil Shrestha <sunil.shrestha at hpe.com>
Date: Fri, 24 Jul 2026 15:15:50 -0500
Subject: [PATCH 2/2] Address reviewers feedback

---
 flang/lib/Semantics/check-omp-structure.cpp   | 66 ++++++++++---------
 .../Semantics/OpenMP/interop-construct.f90    | 56 ++++++++++++++++
 2 files changed, 90 insertions(+), 32 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index b40909fab76aa..17375d4fdd99e 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -5977,12 +5977,12 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
   bool isDependClauseOccurred{false};
   bool hasInitClause{false};
   int targetCount{0}, targetSyncCount{0};
-  std::set<const Symbol *> objectSymbolList;
+  std::set<std::string> interopVarNames;
   // An interop-var must be a scalar variable of integer type. Reject
   // non-scalar designators (whole arrays, array sections) and non-integer
   // designators; array elements and scalar derived-type components are valid.
   auto checkInteropVar = [&](const parser::OmpObject &object,
-                             parser::CharBlock source) {
+                             parser::CharBlock source, bool requireDefinable) {
     // Type-parameter inquiries (e.g. x%kind) are diagnosed separately by
     // CheckTypeParamInquiry, so don't also flag them here.
     if (const Symbol *sym{GetObjectSymbol(object)};
@@ -6018,6 +6018,32 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
         type->kind() != interopKind) {
       context_.Say(source,
           "The interop variable in an INTEROP construct must be a scalar integer variable of kind omp_interop_kind"_err_en_US);
+      return;
+    }
+    // An interop-var must be a variable (never a constant). For init and
+    // destroy the runtime stores the handle through the interop-var, so it
+    // must additionally be definable (not an INTENT(IN) dummy, PROTECTED,
+    // etc.). A use clause only reads the handle, so a non-definable variable
+    // (e.g. an INTENT(IN) dummy holding an initialized handle) is acceptable.
+    if (requireDefinable) {
+      if (auto msg{WhyNotDefinable(source, context_.FindScope(source),
+              DefinabilityFlags{}, *expr)}) {
+        context_
+            .Say(source,
+                "The interop variable in an INTEROP construct must be a definable variable"_err_en_US)
+            .Attach(std::move(msg->set_severity(parser::Severity::Because)));
+      }
+    } else if (!evaluate::IsVariable(*expr)) {
+      context_.Say(source,
+          "The interop variable in an INTEROP construct must be a variable"_err_en_US);
+    }
+    // Each interop-var may appear in at most one action-clause. Compare the
+    // full designator in canonical form so distinct array elements or
+    // structure components (e.g. arr(1) vs arr(2)) are allowed, while a
+    // repeated designator is flagged as a duplicate.
+    if (!interopVarNames.insert(expr->AsFortran()).second) {
+      context_.Say(source,
+          "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
     }
   };
   const auto &clauseList{std::get<std::optional<parser::OmpClauseList>>(x.v.t)};
@@ -6086,16 +6112,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
               CheckTypeParamInquiry(
                   clause.source, *interopVar, llvm::omp::Clause::OMPC_init);
               if (interopVar) {
-                checkInteropVar(*interopVar, clause.source);
-              }
-              if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
-                const auto *objectSymbol{name->symbol};
-                if (llvm::is_contained(objectSymbolList, objectSymbol)) {
-                  context_.Say(GetContext().directiveSource,
-                      "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
-                } else {
-                  objectSymbolList.insert(objectSymbol);
-                }
+                checkInteropVar(*interopVar, clause.source,
+                    /*requireDefinable=*/true);
               }
             },
             [&](const parser::OmpClause::Depend &dependClause) {
@@ -6110,16 +6128,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
               const auto *interopVar{
                   parser::Unwrap<parser::OmpObject>(destroyClause.v)};
               if (interopVar) {
-                checkInteropVar(*interopVar, clause.source);
-              }
-              if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
-                const auto *objectSymbol{name->symbol};
-                if (llvm::is_contained(objectSymbolList, objectSymbol)) {
-                  context_.Say(GetContext().directiveSource,
-                      "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
-                } else {
-                  objectSymbolList.insert(objectSymbol);
-                }
+                checkInteropVar(*interopVar, clause.source,
+                    /*requireDefinable=*/true);
               }
             },
             [&](const parser::OmpClause::Use &useClause) {
@@ -6128,16 +6138,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
               CheckTypeParamInquiry(
                   clause.source, *interopVar, llvm::omp::Clause::OMPC_use);
               if (interopVar) {
-                checkInteropVar(*interopVar, clause.source);
-              }
-              if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
-                const auto *objectSymbol{name->symbol};
-                if (llvm::is_contained(objectSymbolList, objectSymbol)) {
-                  context_.Say(GetContext().directiveSource,
-                      "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
-                } else {
-                  objectSymbolList.insert(objectSymbol);
-                }
+                checkInteropVar(*interopVar, clause.source,
+                    /*requireDefinable=*/false);
               }
             },
             [&](const auto &) {},
diff --git a/flang/test/Semantics/OpenMP/interop-construct.f90 b/flang/test/Semantics/OpenMP/interop-construct.f90
index 987f59536c9fe..2083c62b7b2eb 100644
--- a/flang/test/Semantics/OpenMP/interop-construct.f90
+++ b/flang/test/Semantics/OpenMP/interop-construct.f90
@@ -93,3 +93,59 @@ SUBROUTINE test_interop_11()
   !$OMP INTEROP DESTROY(arr(1))
   PRINT *, 'pass'
 END SUBROUTINE test_interop_11
+
+! Uniqueness is compared per complete designator: distinct array elements or
+! structure components are different interop-vars and must be accepted.
+SUBROUTINE test_interop_12()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND) :: arr(10)
+  !$OMP INTEROP INIT(TARGETSYNC: arr(1)) USE(arr(2))
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_12
+
+! Repeating the same designator in two action-clauses is a duplicate.
+SUBROUTINE test_interop_13()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND) :: arr(10)
+  !ERROR: Each interop-var may be specified for at most one action-clause of each INTEROP construct.
+  !$OMP INTEROP INIT(TARGETSYNC: arr(1)) USE(arr(1))
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_13
+
+! init and destroy store the new handle through the interop-var, so it must be
+! a definable variable, not a constant or other non-definable entity.
+SUBROUTINE test_interop_14()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND), PARAMETER :: handle = 0
+  !ERROR: The interop variable in an INTEROP construct must be a definable variable
+  !BECAUSE: 'handle' is not a variable
+  !$OMP INTEROP INIT(TARGETSYNC: handle)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_14
+
+SUBROUTINE test_interop_15(obj)
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND), INTENT(IN) :: obj
+  !ERROR: The interop variable in an INTEROP construct must be a definable variable
+  !BECAUSE: 'obj' is an INTENT(IN) dummy argument
+  !$OMP INTEROP DESTROY(obj)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_15
+
+! A use clause only reads the handle, so it does not require a definable
+! variable, but the interop-var must still be a variable (not a constant).
+SUBROUTINE test_interop_16()
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND), PARAMETER :: handle = 0
+  !ERROR: The interop variable in an INTEROP construct must be a variable
+  !$OMP INTEROP USE(handle)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_16
+
+! An INTENT(IN) dummy holding an initialized handle is a valid use interop-var.
+SUBROUTINE test_interop_17(obj)
+  USE omp_lib
+  INTEGER(OMP_INTEROP_KIND), INTENT(IN) :: obj
+  !$OMP INTEROP USE(obj)
+  PRINT *, 'pass'
+END SUBROUTINE test_interop_17



More information about the flang-commits mailing list