[flang-commits] [flang] [Flang][OpenMP] Implement OMP 5.2 implicit DECLARE TARGET procedure handling (PR #196826)

via flang-commits flang-commits at lists.llvm.org
Sun May 10 11:25:20 PDT 2026


https://github.com/blazie2004 updated https://github.com/llvm/llvm-project/pull/196826

>From c7e1e05d63da480e83cda910ba97ec47cdd35767 Mon Sep 17 00:00:00 2001
From: Jay Satish Kumar Patel <kumarpat at pe31.hpc.amslabs.hpecorp.net>
Date: Sun, 10 May 2026 13:04:32 -0500
Subject: [PATCH] Implement OMP 5.2 implicit DECLARE TARGET procedure handling

---
 flang/lib/Semantics/check-omp-structure.cpp   |  6 +++--
 flang/lib/Semantics/openmp-utils.cpp          |  4 ++-
 flang/lib/Semantics/resolve-directives.cpp    | 13 ++++++++++
 flang/lib/Semantics/resolve-names.cpp         | 25 ++++++++++++++++---
 .../OpenMP/declare-target-implicit-proc.f90   | 21 ++++++++++++++++
 5 files changed, 63 insertions(+), 6 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/declare-target-implicit-proc.f90

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 33ea727343cf4..4792aa6b36bbf 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1297,11 +1297,13 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
   llvm::omp::Directive directive{GetContext().directive};
 
   if (name->symbol->GetUltimate().IsSubprogram()) {
-    if (directive == llvm::omp::Directive::OMPD_threadprivate)
+    if (directive == llvm::omp::Directive::OMPD_threadprivate) {
       context_.Say(name->source,
           "The procedure name cannot be in a %s directive"_err_en_US,
           ContextDirectiveAsFortran());
-    // TODO: Check for procedure name in declare target directive.
+    }
+    // OMP 5.2 7.8.2 p10: a procedure name in DECLARE TARGET is valid
+    // (treated as external subroutine if not otherwise specified).
   } else if (name->symbol->attrs().test(Attr::PARAMETER)) {
     if (directive == llvm::omp::Directive::OMPD_threadprivate)
       context_.Say(name->source,
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 58aefe2e1fc52..167d4dc936d7e 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -190,7 +190,9 @@ bool IsVariableListItem(const Symbol &sym) {
 }
 
 bool IsExtendedListItem(const Symbol &sym) {
-  return IsVariableListItem(sym) || sym.IsSubprogram();
+  // Extended-list item: variable, procedure, or procedure pointer
+  return IsVariableListItem(sym) || sym.IsSubprogram() ||
+      sym.has<ProcEntityDetails>();
 }
 
 bool IsTypeParamInquiry(const Symbol &sym) {
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index b97f7ce58a1c0..495c128ee3275 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2972,6 +2972,19 @@ void OmpAttributeVisitor::ResolveOmpDesignator(
           name->symbol = func;
         }
       }
+      // OMP 5.2 §7.8.2 ¶10: If a name appears in a declare target directive
+      // and has not been explicitly typed as a variable or procedure, and
+      // no other declaration gives it a procedure property, treat it as an
+      // external subroutine.
+      if (symbol->has<EntityDetails>() &&
+          !symbol->attrs().test(Attr::EXTERNAL) &&
+          !symbol->test(Symbol::Flag::Function) &&
+          !symbol->test(Symbol::Flag::Subroutine)) {
+        // Symbol is still unspecialized EntityDetails - promote to external proc
+        symbol->attrs().set(Attr::EXTERNAL);
+        symbol->set_details(ProcEntityDetails{});
+        symbol->set(Symbol::Flag::Subroutine);
+      }
     }
     if (directive == llvm::omp::Directive::OMPD_target_data) {
       checkExclusivelists(symbol, Symbol::Flag::OmpUseDevicePtr, symbol,
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 4f824ef1321e9..7558e5ae9d8da 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -9165,18 +9165,37 @@ bool DeclarationVisitor::FindAndMarkDeclareTargetSymbol(
               return true;
             }
             // if we find a symbol that is not a function or subroutine, we
-            // currently escape without doing anything.
-            break;
+            // currently escape without doing anything. Do NOT fall through
+            // to create an implicit external procedure.
+            return false;
           }
 
           // This is our loop exit condition, as parent() has an inbuilt assert
           // if you call it on a top level scope, rather than returning a null
           // value.
           if (scope->IsTopLevel()) {
-            return false;
+            break;
           }
         }
       }
+
+      // OpenMP 5.2, 7.8.2 p10: a procedure name in DECLARE TARGET with no
+      // explicit data/procedure properties is treated as an external
+      // subroutine. Only apply this at program/module scope level, not inside
+      // subprograms where local variables could be forward-declared.
+      if (!isImplicitNoneType() &&
+          currScope().kind() != Scope::Kind::Subprogram &&
+          currScope().kind() != Scope::Kind::BlockConstruct) {
+        auto [it, inserted]{
+            currScope().try_emplace(name.source, Attrs{}, ProcEntityDetails{})};
+        Symbol &symbol{*it->second};
+        if (inserted || symbol.has<ProcEntityDetails>()) {
+          name.symbol = &symbol;
+          symbol.set(Symbol::Flag::Subroutine);
+          SetImplicitAttr(symbol, Attr::EXTERNAL);
+          return true;
+        }
+      }
     }
   }
   return false;
diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-proc.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-proc.f90
new file mode 100644
index 0000000000000..84f270fa511b9
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-target-implicit-proc.f90
@@ -0,0 +1,21 @@
+! RUN: %python %S/../test_symbols.py %s %flang_fc1 -fopenmp -fopenmp-version=52
+
+! Test OpenMP 5.2 §7.8.2 ¶10: implicit external procedure in DECLARE TARGET
+
+program test_implicit_declare_target
+  integer :: n = 10
+  !DEF: /test_implicit_declare_target/ext_sub (Subroutine) EXTERNAL ProcEntity
+  !$omp declare target(ext_sub)
+
+  !$omp target
+    !REF: /test_implicit_declare_target/ext_sub
+    call ext_sub(n)
+  !$omp end target
+end program
+
+! Verify the external subroutine definition works
+subroutine ext_sub(x)
+  !$omp declare target
+  integer, intent(in) :: x
+  print *, "Called with:", x
+end subroutine
\ No newline at end of file



More information about the flang-commits mailing list