[flang-commits] [flang] [flang][OpenMP] Implicit declarations of procedures in DECLARE_TARGET (PR #201935)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Mon Jun 8 11:53:27 PDT 2026
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/201935
>From 350a72b4b38ee72ab11f9c60e19d4a696dddbc33 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 5 Jun 2026 10:36:56 -0500
Subject: [PATCH 1/5] [flang][OpenMP] Implicit declarations of procedures in
DECLARE_TARGET
This replaces commit 8f5df8891840b, since it was rejecting the following
case:
```
function baz(a)
!$omp declare target to(baz)
real, intent(in) :: a
baz = a
end
program main
real :: a
!$omp declare target(baz)
integer, save :: baz ! error: 'baz' is already declared
end
```
Instead of flagging an error, the 'baz' in the directive should be
resolved to the explicitly declared variable.
The original motivating example was to allow the case where the main
program (from the above snippet) looked like the following:
```
program main
real :: a
!$omp declare target(baz) ! 'baz' should be resolved to the
!$omp target ! external function
a = baz(a) ! <- because of this call
!$omp end target
end
```
The problem is that "declare_target(baz)" despite being the same in both
cases, should lead to two different outcomes in symbol resolution.
This fix will treat declarations introduced by a DECLARE_TARGET as
eligible for overriding with a potentially conflicting declaration
stemming from the use of that name in a language construct or expression.
Since a mere mention of a name alone declares an object, such conflict
occurs when the name would have been otherwise resolved to a procedure.
The function HandleProcedureName was modified to "undeclare" names
implicitly declared due to their appearance in a DECLARE_TARGET.
---
flang/lib/Semantics/resolve-names.cpp | 180 ++++++++++--------
.../OpenMP/declare-target-symbols.f90 | 35 ++++
.../Semantics/OpenMP/declare-target08.f90 | 8 +-
3 files changed, 137 insertions(+), 86 deletions(-)
create mode 100644 flang/test/Semantics/OpenMP/declare-target-symbols.f90
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index a92d73ff1bc80..bb9001e46c9a7 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -598,6 +598,7 @@ class ScopeHandler : public ImplicitRulesVisitor {
Symbol &MakeSymbol(const SourceName &, Attrs = Attrs{});
Symbol &MakeSymbol(const parser::Name &, Attrs = Attrs{});
Symbol &MakeHostAssocSymbol(const parser::Name &, const Symbol &);
+ Symbol &MakeHostAssocSymbol(Scope &, const parser::Name &, const Symbol &);
template <typename D>
common::IfNoLvalue<Symbol &, D> MakeSymbol(
@@ -763,8 +764,6 @@ class ScopeHandler : public ImplicitRulesVisitor {
std::vector<const std::list<parser::EquivalenceObject> *> equivalenceSets;
// Names of all common block objects in the scope
std::set<SourceName> commonBlockObjects;
- // Names of all names that show in a declare target declaration
- std::set<SourceName> declareTargetNames;
// Info about SAVE statements and attributes in current scope
struct {
std::optional<SourceName> saveAll; // "SAVE" without entity list
@@ -1272,7 +1271,6 @@ class DeclarationVisitor : public ArraySpecVisitor,
const parser::Name *FindComponent(const parser::Name *, const parser::Name &);
void Initialization(const parser::Name &, const parser::Initialization &,
bool inComponentDecl);
- bool FindAndMarkDeclareTargetSymbol(const parser::Name &);
bool PassesLocalityChecks(
const parser::Name &name, Symbol &symbol, Symbol::Flag flag);
bool CheckForHostAssociatedImplicit(const parser::Name &);
@@ -1763,49 +1761,73 @@ class OmpVisitor : public virtual DeclarationVisitor {
bool Pre(const parser::OmpClause::To &);
bool Pre(const parser::OmpClause::From &);
+ // Make sure that the following code is properly handled:
+ //
+ // function baz(a)
+ // !$omp declare target to(baz)
+ // real, intent(in) :: a
+ // baz = a
+ // end
+ //
+ // subroutine foo
+ // !$omp declare target(baz) ! 'baz' should resolve to the array
+ // integer, save :: baz(10)
+ // end
+ //
+ // subroutine bar
+ // real :: a
+ // !$omp declare target(baz) ! 'baz' should resolve to the external
+ // !$omp target ! function
+ // a = baz(a)
+ // !$omp end target
+ // end
+ //
+ // The problem is that "declare_target(baz)" despite being the same
+ // in both foo and bar, should lead to two different outcomes in symbol
+ // resolution.
+
+ // The approach is to treat declarations introduced by a DECLARE_TARGET
+ // as eligible for overriding with a potentially conflicting declaration
+ // stemming from the use of that name in a language construct or expression.
+ // Since a mere mention of a name alone declares an object, such conflict
+ // occurs when the name would have been otherwise resolved to a procedure.
+ // The overriding happens in HandleProcedureName.
+ //
+ // Here in Pre/Post we'll record the symbols that were created specifically
+ // for names appearing in a DECLARE_TARGET.
bool Pre(const parser::OmpDeclareTargetDirective &x) {
- auto addObjectName{[&](const parser::OmpObject &object) {
- common::visit(
- common::visitors{
- [&](const parser::Designator &designator) {
- if (const auto *name{
- parser::GetDesignatorNameIfDataRef(designator)}) {
- specPartState_.declareTargetNames.insert(name->source);
- }
- },
- [&](const parser::Name &name) {
- specPartState_.declareTargetNames.insert(name.source);
- },
- [&](const parser::OmpObject::Invalid &invalid) {
- switch (invalid.v) {
- SWITCH_COVERS_ALL_CASES
- case parser::OmpObject::Invalid::Kind::BlankCommonBlock:
- context().Say(invalid.source,
- "Blank common blocks are not allowed as directive or clause arguments"_err_en_US);
- break;
- }
- },
- },
- object.u);
- }};
-
+ // Save names appearing in this DECLARE_TARGET.
+ declareTargetNames_.clear();
for (const parser::OmpArgument &arg : x.v.Arguments().v) {
if (auto *object{parser::omp::GetArgumentObject(arg)}) {
- addObjectName(*object);
+ if (auto *name = parser::Unwrap<parser::Name>(*object)) {
+ declareTargetNames_.insert(name);
+ }
}
}
-
for (const parser::OmpClause &clause : x.v.Clauses().v) {
if (auto *objects{parser::omp::GetOmpObjectList(clause)}) {
for (const parser::OmpObject &object : objects->v) {
- addObjectName(object);
+ if (auto *name = parser::Unwrap<parser::Name>(object)) {
+ declareTargetNames_.insert(name);
+ }
}
}
}
-
- SkipImplicitTyping(true);
return true;
}
+
+ void Post(const parser::OmpDeclareTargetDirective &x) {
+ for (const parser::Name *name : declareTargetNames_) {
+ // The source location of the symbol's name() is the location of the
+ // declaration.
+ if (name->symbol &&
+ name->source.begin() == name->symbol->name().begin()) {
+ declaredByDeclareTarget_.insert(name->symbol);
+ }
+ }
+ }
+
bool Pre(const parser::OmpClause &x) {
if (NeedsScope(x)) {
PushScopeWithSource(Scope::Kind::OtherClause, x.source);
@@ -1874,6 +1896,10 @@ class OmpVisitor : public virtual DeclarationVisitor {
messageHandler().set_currStmtSource(std::nullopt);
}
+ bool WasDeclaredByOmpDeclareTarget(const Symbol *sym) {
+ return declaredByDeclareTarget_.erase(sym);
+ }
+
private:
void ResolveMapperModifier(const parser::OmpMapper &mapper);
void ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec,
@@ -1884,6 +1910,8 @@ class OmpVisitor : public virtual DeclarationVisitor {
void ResolveCriticalName(const parser::OmpArgument &arg);
std::vector<const parser::OpenMPDeclarativeConstruct *> declaratives_;
+ std::set<const parser::Name *> declareTargetNames_;
+ std::set<const Symbol *> declaredByDeclareTarget_;
};
bool OmpVisitor::NeedsScope(const parser::OmpClause &x) {
@@ -3245,9 +3273,12 @@ Symbol &ScopeHandler::MakeSymbol(const parser::Name &name, Attrs attrs) {
}
Symbol &ScopeHandler::MakeHostAssocSymbol(
const parser::Name &name, const Symbol &hostSymbol) {
- Symbol &symbol{*NonDerivedTypeScope()
- .try_emplace(name.source, HostAssocDetails{hostSymbol})
- .first->second};
+ return MakeHostAssocSymbol(NonDerivedTypeScope(), name, hostSymbol);
+}
+Symbol &ScopeHandler::MakeHostAssocSymbol(
+ Scope &scope, const parser::Name &name, const Symbol &hostSymbol) {
+ Symbol &symbol{*scope.try_emplace(name.source, HostAssocDetails{hostSymbol})
+ .first->second};
name.symbol = &symbol;
symbol.attrs() = hostSymbol.attrs(); // TODO: except PRIVATE, PUBLIC?
// These attributes can be redundantly reapplied without error
@@ -9213,11 +9244,7 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
// If implicit types are allowed, ensure name is in the symbol table.
// Otherwise, report an error if it hasn't been declared.
const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
- if (!FindSymbol(name)) {
- if (FindAndMarkDeclareTargetSymbol(name)) {
- return &name;
- }
- }
+ FindSymbol(name);
if (CheckForHostAssociatedImplicit(name)) {
NotePossibleBadForwardRef(name);
return &name;
@@ -9421,47 +9448,6 @@ const parser::Name *DeclarationVisitor::FindComponent(
return nullptr;
}
-bool DeclarationVisitor::FindAndMarkDeclareTargetSymbol(
- const parser::Name &name) {
- if (!specPartState_.declareTargetNames.empty()) {
- if (specPartState_.declareTargetNames.count(name.source)) {
- if (!currScope().IsTopLevel()) {
- // Search preceding scopes until we find a matching symbol or run out
- // of scopes to search, we skip the current scope as it's already been
- // designated as implicit here.
- for (auto *scope = &currScope().parent();; scope = &scope->parent()) {
- if (Symbol * symbol{scope->FindSymbol(name.source)}) {
- if (symbol->test(Symbol::Flag::Subroutine) ||
- symbol->test(Symbol::Flag::Function)) {
- const auto [sym, success]{currScope().try_emplace(
- symbol->name(), Attrs{}, HostAssocDetails{*symbol})};
- assert(success &&
- "FindAndMarkDeclareTargetSymbol could not emplace new "
- "subroutine/function symbol");
- name.symbol = &*sym->second;
- symbol->test(Symbol::Flag::Subroutine)
- ? name.symbol->set(Symbol::Flag::Subroutine)
- : name.symbol->set(Symbol::Flag::Function);
- return true;
- }
- // if we find a symbol that is not a function or subroutine, we
- // currently escape without doing anything.
- break;
- }
-
- // 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;
- }
- }
- }
- }
- }
- return false;
-}
-
void DeclarationVisitor::Initialization(const parser::Name &name,
const parser::Initialization &init, bool inComponentDecl) {
// Traversal of the initializer was deferred to here so that the
@@ -9756,6 +9742,28 @@ void ResolveNamesVisitor::HandleProcedureName(
Symbol::Flag flag, const parser::Name &name) {
CHECK(flag == Symbol::Flag::Function || flag == Symbol::Flag::Subroutine);
auto *symbol{FindSymbol(NonDerivedTypeScope(), name)};
+ // A symbol listed on OpenMP declare_target directive may be a variable
+ // or a procedure. If the directive is the first occurrence of the name,
+ // it will create an implicit declaration of an object (since the name
+ // is not used in a call at that location). If the name turns out to be
+ // that of a procedure, this is going to create a problem.
+ // If a symbol was created because of its appearance in a declare_target,
+ // a use in a call should override it with the procedure symbol.
+ Scope *ompDTScope{nullptr};
+ // A name implicitly declared by a DECLARE_TARGET may have been followed
+ // by an explcit declaration. Make sure the symbol is still implicit
+ // before doing anything.
+ if (WasDeclaredByOmpDeclareTarget(symbol) &&
+ symbol->flags().test(Symbol::Flag::Implicit)) {
+ // Implicit declaration of a symbol caused by being on a declare_target
+ // should only declare it as an object, not a procedure. This is because
+ // the 'x' in declare_target(x) looks like a use of a variable, not a
+ // procedure.
+ assert(!IsProcedure(*symbol) && "Should not be a procedure");
+ ompDTScope = const_cast<Scope *>(&symbol->owner());
+ ompDTScope->erase(symbol->name());
+ symbol = nullptr;
+ }
if (!symbol) {
if (IsIntrinsic(name.source, flag)) {
symbol = &MakeSymbol(InclusiveScope(), name.source, Attrs{});
@@ -9778,6 +9786,14 @@ void ResolveNamesVisitor::HandleProcedureName(
// Create a place-holder HostAssocDetails symbol to preclude later
// use of this name as a local symbol; but don't actually use this new
// HostAssocDetails symbol in expressions.
+ if (ompDTScope && &currScope() != ompDTScope &&
+ ompDTScope->Contains(currScope())) {
+ // If we're recreating a symbol previously declared due to an
+ // OpenMP declare_target, we need to create one in the scope
+ // where the declare_target was located. The use in a call that
+ // we're handling here may be in a nested scope.
+ MakeHostAssocSymbol(*ompDTScope, name, *symbol);
+ }
MakeHostAssocSymbol(name, *symbol);
name.symbol = symbol;
}
diff --git a/flang/test/Semantics/OpenMP/declare-target-symbols.f90 b/flang/test/Semantics/OpenMP/declare-target-symbols.f90
new file mode 100644
index 0000000000000..8ca8c2786f230
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-target-symbols.f90
@@ -0,0 +1,35 @@
+!RUN: %flang_fc1 -fdebug-dump-symbols %openmp_flags %s | FileCheck %s
+
+function baz(a)
+ !$omp declare target to(baz)
+ real, intent(in) :: a
+ baz = a
+end
+
+subroutine foo
+ !$omp declare target(baz)
+ integer, save :: baz(10)
+end
+
+subroutine bar
+ real :: a
+ !$omp declare target(baz)
+ a = 1.0
+ !$omp target
+ a = baz(a)
+ !$omp end target
+end
+
+!CHECK: Subprogram scope: baz size=8 alignment=4
+!CHECK: a, INTENT(IN) size=4 offset=4: ObjectEntity dummy type: REAL(4)
+!CHECK: baz (Implicit, OmpDeclareTarget) size=4 offset=0: ObjectEntity funcResult type: REAL(4)
+!CHECK: OtherClause scope: size=0 alignment=1
+!CHECK: Subprogram scope: foo size=40 alignment=4 sourceRange=69 bytes
+!CHECK: baz, SAVE (OmpDeclareTarget) size=40 offset=0: ObjectEntity type: INTEGER(4) shape: 1_8:10_8 OmpDeclareTargetFlags:(enter)
+!CHECK: foo (Subroutine): HostAssoc => foo (Subroutine): Subprogram ()
+!CHECK: Subprogram scope: bar size=4 alignment=4
+!CHECK: a size=4 offset=0: ObjectEntity type: REAL(4)
+!CHECK: bar (Subroutine): HostAssoc => bar (Subroutine): Subprogram ()
+!CHECK: baz, EXTERNAL (Function, OmpDeclareTarget): HostAssoc => baz, EXTERNAL (Function, OmpDeclareTarget): Subprogram result:REAL(4) baz (REAL(4) a) OmpDeclareTargetFlags:(enter to)
+!CHECK: OtherConstruct scope: size=0 alignment=1
+!CHECK: baz, EXTERNAL (Function, OmpDeclareTarget): HostAssoc => baz, EXTERNAL (Function, OmpDeclareTarget): Subprogram result:REAL(4) baz (REAL(4) a) OmpDeclareTargetFlags:(enter to)
diff --git a/flang/test/Semantics/OpenMP/declare-target08.f90 b/flang/test/Semantics/OpenMP/declare-target08.f90
index 91598d9528ae9..7cf1a9c3d9382 100644
--- a/flang/test/Semantics/OpenMP/declare-target08.f90
+++ b/flang/test/Semantics/OpenMP/declare-target08.f90
@@ -28,8 +28,8 @@ program main
external ext_routine
integer ext_function
external ext_function
-!CHECK: bar (Subroutine, OmpDeclareTarget): HostAssoc
-!CHECK: baz (Function, OmpDeclareTarget): HostAssoc
+!CHECK: bar, EXTERNAL (Subroutine, OmpDeclareTarget): HostAssoc
+!CHECK: baz, EXTERNAL (Function, OmpDeclareTarget): HostAssoc
!CHECK: ext_function, EXTERNAL (Function, OmpDeclareTarget): ProcEntity {{.*}}
!CHECK: ext_routine, EXTERNAL (OmpDeclareTarget): ProcEntity
!$omp declare target(bar)
@@ -46,8 +46,8 @@ program main
subroutine foo(a)
real a
integer i
-!CHECK: bar (Subroutine, OmpDeclareTarget): HostAssoc
-!CHECK: baz (Function, OmpDeclareTarget): HostAssoc
+!CHECK: bar, EXTERNAL (Subroutine, OmpDeclareTarget): HostAssoc
+!CHECK: baz, EXTERNAL (Function, OmpDeclareTarget): HostAssoc
!$omp declare target(bar)
!$omp declare target(baz)
!$omp target
>From c72e280ea1d8bc82291630cb9173a6b8fa27f715 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Sat, 6 Jun 2026 08:16:46 -0500
Subject: [PATCH 2/5] Don't replace symbols that have been equivalenced
---
flang/lib/Semantics/resolve-names.cpp | 23 +++++++++++--------
.../OpenMP/declare-target-equivalence.f90 | 23 +++++++++++++++++++
2 files changed, 36 insertions(+), 10 deletions(-)
create mode 100644 flang/test/Semantics/OpenMP/declare-target-equivalence.f90
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index bb9001e46c9a7..0689a117d8f8a 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -9753,16 +9753,19 @@ void ResolveNamesVisitor::HandleProcedureName(
// A name implicitly declared by a DECLARE_TARGET may have been followed
// by an explcit declaration. Make sure the symbol is still implicit
// before doing anything.
- if (WasDeclaredByOmpDeclareTarget(symbol) &&
- symbol->flags().test(Symbol::Flag::Implicit)) {
- // Implicit declaration of a symbol caused by being on a declare_target
- // should only declare it as an object, not a procedure. This is because
- // the 'x' in declare_target(x) looks like a use of a variable, not a
- // procedure.
- assert(!IsProcedure(*symbol) && "Should not be a procedure");
- ompDTScope = const_cast<Scope *>(&symbol->owner());
- ompDTScope->erase(symbol->name());
- symbol = nullptr;
+ if (WasDeclaredByOmpDeclareTarget(symbol)) {
+ bool isImplicit{symbol->flags().test(Symbol::Flag::Implicit)};
+ bool inEquivalence{FindEquivalenceSet(*symbol) != nullptr};
+ if (isImplicit && !inEquivalence) {
+ // Implicit declaration of a symbol caused by being on a declare_target
+ // should only declare it as an object, not a procedure. This is because
+ // the 'x' in declare_target(x) looks like a use of a variable, not a
+ // procedure.
+ assert(!IsProcedure(*symbol) && "Should not be a procedure");
+ ompDTScope = const_cast<Scope *>(&symbol->owner());
+ ompDTScope->erase(symbol->name());
+ symbol = nullptr;
+ }
}
if (!symbol) {
if (IsIntrinsic(name.source, flag)) {
diff --git a/flang/test/Semantics/OpenMP/declare-target-equivalence.f90 b/flang/test/Semantics/OpenMP/declare-target-equivalence.f90
new file mode 100644
index 0000000000000..9c4e15e77e7eb
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-target-equivalence.f90
@@ -0,0 +1,23 @@
+!RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine baz(x)
+ integer :: x
+end
+
+subroutine f
+!ERROR: A variable in a DECLARE TARGET directive cannot appear in an EQUIVALENCE statement
+ !$omp declare target(baz)
+ integer :: p
+ equivalence(baz, p)
+!ERROR: Cannot call function 'baz' like a subroutine
+ call baz(p)
+end
+
+subroutine g
+!ERROR: A variable in a DECLARE TARGET directive cannot appear in an EQUIVALENCE statement
+ !$omp declare target(baz)
+ integer :: p, q
+ equivalence(baz, p)
+!ERROR: 'baz' is not a callable procedure
+ q = baz(p)
+end
>From 638abbbe9f865a904fa4ccdea6b1b0a536c89afe Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Sat, 6 Jun 2026 09:29:19 -0500
Subject: [PATCH 3/5] Don't replace symbols that are in a common block
---
flang/lib/Semantics/resolve-names.cpp | 5 ++--
.../OpenMP/declare-target-common-block2.f90 | 23 +++++++++++++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
create mode 100644 flang/test/Semantics/OpenMP/declare-target-common-block2.f90
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 0689a117d8f8a..b24391b60ba4c 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -9754,9 +9754,10 @@ void ResolveNamesVisitor::HandleProcedureName(
// by an explcit declaration. Make sure the symbol is still implicit
// before doing anything.
if (WasDeclaredByOmpDeclareTarget(symbol)) {
- bool isImplicit{symbol->flags().test(Symbol::Flag::Implicit)};
+ bool isImplicit{symbol->test(Symbol::Flag::Implicit)};
bool inEquivalence{FindEquivalenceSet(*symbol) != nullptr};
- if (isImplicit && !inEquivalence) {
+ bool inCommonBlock{symbol->test(Symbol::Flag::InCommonBlock)};
+ if (isImplicit && !inEquivalence && !inCommonBlock) {
// Implicit declaration of a symbol caused by being on a declare_target
// should only declare it as an object, not a procedure. This is because
// the 'x' in declare_target(x) looks like a use of a variable, not a
diff --git a/flang/test/Semantics/OpenMP/declare-target-common-block2.f90 b/flang/test/Semantics/OpenMP/declare-target-common-block2.f90
new file mode 100644
index 0000000000000..ce867006f6b2b
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-target-common-block2.f90
@@ -0,0 +1,23 @@
+!RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine baz(x)
+ integer :: x
+end
+
+subroutine f
+!ERROR: A variable in a DECLARE TARGET directive cannot be an element of a common block
+ !$omp declare target(baz)
+ integer :: p
+ common /xx/ baz, p
+!ERROR: Cannot call function 'baz' like a subroutine
+ call baz(p)
+end
+
+subroutine g
+!ERROR: A variable in a DECLARE TARGET directive cannot be an element of a common block
+ !$omp declare target(baz)
+ integer :: p, q
+ common /yy/ baz, p
+!ERROR: 'baz' is not a callable procedure
+ q = baz(p)
+end
>From 307cb2f3541fc1a0cfaff81e90d57f3af4cd5125 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 8 Jun 2026 08:13:50 -0500
Subject: [PATCH 4/5] Reset declared-by-declare-target when encountered in
designator
---
flang/lib/Semantics/resolve-names.cpp | 10 ++++
.../OpenMP/declare-target-common-block2.f90 | 23 ---------
.../OpenMP/declare-target-equivalence.f90 | 23 ---------
.../OpenMP/declare-target-resolve.f90 | 51 +++++++++++++++++++
4 files changed, 61 insertions(+), 46 deletions(-)
delete mode 100644 flang/test/Semantics/OpenMP/declare-target-common-block2.f90
delete mode 100644 flang/test/Semantics/OpenMP/declare-target-equivalence.f90
create mode 100644 flang/test/Semantics/OpenMP/declare-target-resolve.f90
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index b24391b60ba4c..28ccaec2dc18f 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10527,6 +10527,16 @@ bool ResolveNamesVisitor::Pre(const parser::PointerAssignmentStmt &x) {
return false;
}
void ResolveNamesVisitor::Post(const parser::Designator &x) {
+ // If the name of this designator first appeared in OpenMP declare_target,
+ // it was implicitly declared as an object, but with the possibility of
+ // becoming a procedure. When the name is used in a designator, it cannot
+ // subsequently be turned into a procedure. Unmark the corresponding symbol
+ // as declared by a declare_target directive.
+ if (auto *name{parser::Unwrap<parser::Name>(x)}) {
+ if (auto *symbol{currScope().FindSymbol(name->source)}) {
+ WasDeclaredByOmpDeclareTarget(symbol);
+ }
+ }
ResolveDesignator(x);
}
void ResolveNamesVisitor::Post(const parser::SubstringInquiry &x) {
diff --git a/flang/test/Semantics/OpenMP/declare-target-common-block2.f90 b/flang/test/Semantics/OpenMP/declare-target-common-block2.f90
deleted file mode 100644
index ce867006f6b2b..0000000000000
--- a/flang/test/Semantics/OpenMP/declare-target-common-block2.f90
+++ /dev/null
@@ -1,23 +0,0 @@
-!RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
-
-subroutine baz(x)
- integer :: x
-end
-
-subroutine f
-!ERROR: A variable in a DECLARE TARGET directive cannot be an element of a common block
- !$omp declare target(baz)
- integer :: p
- common /xx/ baz, p
-!ERROR: Cannot call function 'baz' like a subroutine
- call baz(p)
-end
-
-subroutine g
-!ERROR: A variable in a DECLARE TARGET directive cannot be an element of a common block
- !$omp declare target(baz)
- integer :: p, q
- common /yy/ baz, p
-!ERROR: 'baz' is not a callable procedure
- q = baz(p)
-end
diff --git a/flang/test/Semantics/OpenMP/declare-target-equivalence.f90 b/flang/test/Semantics/OpenMP/declare-target-equivalence.f90
deleted file mode 100644
index 9c4e15e77e7eb..0000000000000
--- a/flang/test/Semantics/OpenMP/declare-target-equivalence.f90
+++ /dev/null
@@ -1,23 +0,0 @@
-!RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
-
-subroutine baz(x)
- integer :: x
-end
-
-subroutine f
-!ERROR: A variable in a DECLARE TARGET directive cannot appear in an EQUIVALENCE statement
- !$omp declare target(baz)
- integer :: p
- equivalence(baz, p)
-!ERROR: Cannot call function 'baz' like a subroutine
- call baz(p)
-end
-
-subroutine g
-!ERROR: A variable in a DECLARE TARGET directive cannot appear in an EQUIVALENCE statement
- !$omp declare target(baz)
- integer :: p, q
- equivalence(baz, p)
-!ERROR: 'baz' is not a callable procedure
- q = baz(p)
-end
diff --git a/flang/test/Semantics/OpenMP/declare-target-resolve.f90 b/flang/test/Semantics/OpenMP/declare-target-resolve.f90
new file mode 100644
index 0000000000000..771a3dd6209c6
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-target-resolve.f90
@@ -0,0 +1,51 @@
+!RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine baz(x)
+ integer :: x
+end
+
+subroutine f00
+!ERROR: A variable in a DECLARE TARGET directive cannot appear in an EQUIVALENCE statement
+ !$omp declare target(baz)
+ integer :: p
+ equivalence(baz, p)
+!ERROR: Cannot call function 'baz' like a subroutine
+ call baz(p)
+end
+
+subroutine f01
+!ERROR: A variable in a DECLARE TARGET directive cannot appear in an EQUIVALENCE statement
+ !$omp declare target(baz)
+ integer :: p, q
+ equivalence(baz, p)
+!ERROR: 'baz' is not a callable procedure
+ q = baz(p)
+end
+
+subroutine f02
+!ERROR: A variable in a DECLARE TARGET directive cannot be an element of a common block
+ !$omp declare target(baz)
+ integer :: p
+ common /xx/ baz, p
+!ERROR: Cannot call function 'baz' like a subroutine
+ call baz(p)
+end
+
+subroutine f03
+!ERROR: A variable in a DECLARE TARGET directive cannot be an element of a common block
+ !$omp declare target(baz)
+ integer :: p, q
+ common /yy/ baz, p
+!ERROR: 'baz' is not a callable procedure
+ q = baz(p)
+end
+
+subroutine f04
+ real :: a
+!ERROR: A variable that appears in a DECLARE TARGET directive must be declared in the scope of a module or have the SAVE attribute, either explicitly or implicitly
+ !$omp declare target(baz)
+ a = baz
+!ERROR: 'baz' is not a callable procedure
+ a = baz(a)
+end subroutine
+
>From 57297d5b8ad70e3ea224f834cd3537bee56ce4f1 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 8 Jun 2026 08:39:16 -0500
Subject: [PATCH 5/5] Limit name collection to extended list items
---
flang/lib/Semantics/resolve-names.cpp | 6 ++++
.../OpenMP/declare-target-resolve.f90 | 36 ++++++++++++-------
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 28ccaec2dc18f..173d2ac9d308f 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1806,6 +1806,12 @@ class OmpVisitor : public virtual DeclarationVisitor {
}
}
for (const parser::OmpClause &clause : x.v.Clauses().v) {
+ llvm::omp::Clause clauseId{clause.Id()};
+ // Only "enter" and "to" take an extended list item.
+ if (clauseId != llvm::omp::Clause::OMPC_enter &&
+ clauseId != llvm::omp::Clause::OMPC_to) {
+ continue;
+ }
if (auto *objects{parser::omp::GetOmpObjectList(clause)}) {
for (const parser::OmpObject &object : objects->v) {
if (auto *name = parser::Unwrap<parser::Name>(object)) {
diff --git a/flang/test/Semantics/OpenMP/declare-target-resolve.f90 b/flang/test/Semantics/OpenMP/declare-target-resolve.f90
index 771a3dd6209c6..c32d1cf2ffd9c 100644
--- a/flang/test/Semantics/OpenMP/declare-target-resolve.f90
+++ b/flang/test/Semantics/OpenMP/declare-target-resolve.f90
@@ -1,5 +1,9 @@
!RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+function bar(x)
+ integer :: bar, x
+end
+
subroutine baz(x)
integer :: x
end
@@ -15,11 +19,11 @@ subroutine f00
subroutine f01
!ERROR: A variable in a DECLARE TARGET directive cannot appear in an EQUIVALENCE statement
- !$omp declare target(baz)
+ !$omp declare target(bar)
integer :: p, q
- equivalence(baz, p)
-!ERROR: 'baz' is not a callable procedure
- q = baz(p)
+ equivalence(bar, p)
+!ERROR: 'bar' is not a callable procedure
+ q = bar(p)
end
subroutine f02
@@ -33,19 +37,27 @@ subroutine f02
subroutine f03
!ERROR: A variable in a DECLARE TARGET directive cannot be an element of a common block
- !$omp declare target(baz)
+ !$omp declare target(bar)
integer :: p, q
- common /yy/ baz, p
-!ERROR: 'baz' is not a callable procedure
- q = baz(p)
+ common /yy/ bar, p
+!ERROR: 'bar' is not a callable procedure
+ q = bar(p)
end
subroutine f04
real :: a
!ERROR: A variable that appears in a DECLARE TARGET directive must be declared in the scope of a module or have the SAVE attribute, either explicitly or implicitly
- !$omp declare target(baz)
- a = baz
-!ERROR: 'baz' is not a callable procedure
- a = baz(a)
+ !$omp declare target(bar)
+ a = bar
+!ERROR: 'bar' is not a callable procedure
+ a = bar(a)
+end subroutine
+
+subroutine f05
+ real :: a
+!ERROR: A variable that appears in a DECLARE TARGET directive must be declared in the scope of a module or have the SAVE attribute, either explicitly or implicitly
+ !$omp declare target link(bar)
+!ERROR: 'bar' is not a callable procedure
+ a = bar(a)
end subroutine
More information about the flang-commits
mailing list