[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:21:47 PDT 2026
https://github.com/blazie2004 created https://github.com/llvm/llvm-project/pull/196826
This implements OpenMP 5.2 && 7.8.2 , which states that if a name appears in a `[DECLARE TARGET] `directive and has not been explicitly typed as a variable or procedure, it should be treated as an external subroutine.
The following OpenMP code was being rejected when compiled with `-fopenmp -fopenmp-version=52 -c `
```
program my_fib
integer :: N = 8
!$omp declare target(fib)
!$omp target
call fib(N)
!$omp end target
end program
subroutine fib(N)
integer :: N
!$omp declare target
print*,"hello from fib"
!...
end subroutine
```
## Error message:
```
error: Cannot call function 'fib' like a subroutine
call fib(N)
^^^
Implicit declaration of 'fib'
!$omp declare target(fib)
```
## Summary
This fix enables procedure names (including forward-referenced subroutines) to be correctly handled in OpenMP `DECLARE TARGET` directives.
### Changes
- `resolve-names.cpp`
Creates an implicit `ProcEntityDetails` symbol for unknown names at program/module scope while respecting `IMPLICIT NONE` and avoiding incorrect forward references to local variables inside subprograms.
- `resolve-directives.cpp`
Promotes unspecialized `EntityDetails` symbols to `ProcEntityDetails`, adding the `EXTERNAL` attribute and `Subroutine` flag when needed for OpenMP procedure handling.
- `openmp-utils.cpp`
Extends `IsExtendedListItem()` to recognize `ProcEntityDetails` as valid extended-list items in OpenMP directives.
- `check-omp-structure.cpp`
Removes the outdated TODO and updates semantic checks to allow procedure names in `DECLARE TARGET` directives.
>From daeb7d373ffc4d44ea932a3f1b20d58a0b5067ba 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 ++++++++++++++++++---
4 files changed, 42 insertions(+), 6 deletions(-)
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;
More information about the flang-commits
mailing list