[flang-commits] [flang] [flang][acc] Disallow duplicate variables in use_device clause (PR #176217)
Razvan Lupusoru via flang-commits
flang-commits at lists.llvm.org
Thu Jan 15 10:57:43 PST 2026
https://github.com/razvanlupusoru updated https://github.com/llvm/llvm-project/pull/176217
>From a6ee4e0c7530b16a4bfd43a6ac8408e87ef541dc Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Thu, 15 Jan 2026 10:33:06 -0800
Subject: [PATCH 1/4] [flang][acc] Disallow duplicate variables in use_device
clause
Add a semantic check to detect when the same variable appears multiple
times in `use_device` clauses on the same `host_data` directive. While
the OpenACC specification does not explicitly prohibit this, allowing
duplicates is likely a user error and provides no additional semantics.
A similar restriction was already in place for `private`,
`firstprivate`, and `reduction` clauses on compute constructs. This change
extends that behavior to `use_device` on `host_data`.
Error message:
"'<var>' appears in more than one USE_DEVICE clause on the same
HOST_DATA directive"
---
flang/docs/OpenACC.md | 6 ++++
flang/lib/Semantics/resolve-directives.cpp | 32 +++++++++++++++++++
.../test/Semantics/OpenACC/acc-host-data.f90 | 8 +++++
3 files changed, 46 insertions(+)
diff --git a/flang/docs/OpenACC.md b/flang/docs/OpenACC.md
index f1fe69e57bf37..a83c6b233152a 100644
--- a/flang/docs/OpenACC.md
+++ b/flang/docs/OpenACC.md
@@ -30,6 +30,12 @@ local:
* The OpenACC specification disallows a variable appearing multiple times in
clauses of `!$acc declare` directives for a function, subroutine, program,
or module, but it is allowed with a warning when same clause is used.
+* The OpenACC specification does not disallow the same variable from appearing
+ in multiple data clauses, but this is disallowed for variables appearing in
+ `private`, `firstprivate`, or `reduction` clauses.
+* The OpenACC specification does not disallow the same variable from appearing
+ multiple times in a `use_device` clause on a `host_data` construct, but this
+ is disallowed.
## Remarks about incompatibilities with other implementations
* Array element references in the data clauses are equivalent to array sections
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 6467abf872c16..48793e6c08319 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -334,6 +334,28 @@ class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
bool Pre(const parser::AccClause::UseDevice &x) {
ResolveAccObjectList(x.v, Symbol::Flag::AccUseDevice);
+ // use_device is only valid on host_data directive
+ assert(GetContext().directive == llvm::acc::Directive::ACCD_host_data &&
+ "use_device clause is only valid on host_data directive");
+ // Check for duplicate use_device variables
+ for (const auto &accObject : x.v.v) {
+ if (const auto *designator{
+ std::get_if<parser::Designator>(&accObject.u)}) {
+ if (const auto *name{
+ parser::GetDesignatorNameIfDataRef(*designator)}) {
+ if (name->symbol) {
+ if (HasUseDeviceObject(*name->symbol)) {
+ context_.Say(name->source,
+ "'%s' appears in more than one USE_DEVICE clause "
+ "on the same HOST_DATA directive"_err_en_US,
+ name->ToString());
+ } else {
+ AddUseDeviceObject(*name->symbol);
+ }
+ }
+ }
+ }
+ }
return false;
}
@@ -379,6 +401,15 @@ class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
const llvm::acc::Clause clause, const parser::AccObjectList &objectList);
void AddRoutineInfoToSymbol(
Symbol &, const parser::OpenACCRoutineConstruct &);
+
+ // Track use_device variables
+ void AddUseDeviceObject(SymbolRef object) { useDeviceObjects_.insert(object); }
+ void ClearUseDeviceObjects() { useDeviceObjects_.clear(); }
+ bool HasUseDeviceObject(const Symbol &object) {
+ return useDeviceObjects_.find(object) != useDeviceObjects_.end();
+ }
+ UnorderedSymbolSet useDeviceObjects_;
+
Scope *topScope_;
};
@@ -1185,6 +1216,7 @@ bool AccAttributeVisitor::Pre(const parser::OpenACCBlockConstruct &x) {
break;
}
ClearDataSharingAttributeObjects();
+ ClearUseDeviceObjects();
return true;
}
diff --git a/flang/test/Semantics/OpenACC/acc-host-data.f90 b/flang/test/Semantics/OpenACC/acc-host-data.f90
index f5aa4d7f320ff..e6d76e373347b 100644
--- a/flang/test/Semantics/OpenACC/acc-host-data.f90
+++ b/flang/test/Semantics/OpenACC/acc-host-data.f90
@@ -38,4 +38,12 @@ program openacc_host_data_validity
!$acc host_data use_device(aa, bb) if(.true.) if(ifCondition)
!$acc end host_data
+ !ERROR: 'aa' appears in more than one USE_DEVICE clause on the same HOST_DATA directive
+ !$acc host_data use_device(aa) use_device(aa)
+ !$acc end host_data
+
+ !ERROR: 'bb' appears in more than one USE_DEVICE clause on the same HOST_DATA directive
+ !$acc host_data use_device(bb, bb)
+ !$acc end host_data
+
end program openacc_host_data_validity
>From d241455390bd9386a207b5b4ad6172483ef2c3d5 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Thu, 15 Jan 2026 10:44:30 -0800
Subject: [PATCH 2/4] Fix format
---
flang/lib/Semantics/resolve-directives.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 48793e6c08319..682f8f29b490b 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -341,8 +341,7 @@ class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
for (const auto &accObject : x.v.v) {
if (const auto *designator{
std::get_if<parser::Designator>(&accObject.u)}) {
- if (const auto *name{
- parser::GetDesignatorNameIfDataRef(*designator)}) {
+ if (const auto *name{parser::GetDesignatorNameIfDataRef(*designator)}) {
if (name->symbol) {
if (HasUseDeviceObject(*name->symbol)) {
context_.Say(name->source,
@@ -403,7 +402,9 @@ class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
Symbol &, const parser::OpenACCRoutineConstruct &);
// Track use_device variables
- void AddUseDeviceObject(SymbolRef object) { useDeviceObjects_.insert(object); }
+ void AddUseDeviceObject(SymbolRef object) {
+ useDeviceObjects_.insert(object);
+ }
void ClearUseDeviceObjects() { useDeviceObjects_.clear(); }
bool HasUseDeviceObject(const Symbol &object) {
return useDeviceObjects_.find(object) != useDeviceObjects_.end();
>From f3283babb0d826bcec20f1c1ff6c0cd1037883c6 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Thu, 15 Jan 2026 10:57:15 -0800
Subject: [PATCH 3/4] Move error checking into AddUseDeviceObject
---
flang/lib/Semantics/resolve-directives.cpp | 25 ++++++++++------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 682f8f29b490b..b3c4da396fb88 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -343,14 +343,7 @@ class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
std::get_if<parser::Designator>(&accObject.u)}) {
if (const auto *name{parser::GetDesignatorNameIfDataRef(*designator)}) {
if (name->symbol) {
- if (HasUseDeviceObject(*name->symbol)) {
- context_.Say(name->source,
- "'%s' appears in more than one USE_DEVICE clause "
- "on the same HOST_DATA directive"_err_en_US,
- name->ToString());
- } else {
- AddUseDeviceObject(*name->symbol);
- }
+ AddUseDeviceObject(*name->symbol, *name);
}
}
}
@@ -401,14 +394,18 @@ class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
void AddRoutineInfoToSymbol(
Symbol &, const parser::OpenACCRoutineConstruct &);
- // Track use_device variables
- void AddUseDeviceObject(SymbolRef object) {
- useDeviceObjects_.insert(object);
+ // Track use_device variables and check for duplicates.
+ // Emits an error if the object was already added.
+ void AddUseDeviceObject(const Symbol &object, const parser::Name &name) {
+ auto result = useDeviceObjects_.insert(object);
+ if (!result.second) {
+ context_.Say(name.source,
+ "'%s' appears in more than one USE_DEVICE clause "
+ "on the same HOST_DATA directive"_err_en_US,
+ name.ToString());
+ }
}
void ClearUseDeviceObjects() { useDeviceObjects_.clear(); }
- bool HasUseDeviceObject(const Symbol &object) {
- return useDeviceObjects_.find(object) != useDeviceObjects_.end();
- }
UnorderedSymbolSet useDeviceObjects_;
Scope *topScope_;
>From 403e0bc1b28146be0c331bcc918d662a7ad0dc41 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Thu, 15 Jan 2026 10:57:28 -0800
Subject: [PATCH 4/4] Avoid repeated use of disallow
---
flang/docs/OpenACC.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/docs/OpenACC.md b/flang/docs/OpenACC.md
index a83c6b233152a..85e9430a203ec 100644
--- a/flang/docs/OpenACC.md
+++ b/flang/docs/OpenACC.md
@@ -30,10 +30,10 @@ local:
* The OpenACC specification disallows a variable appearing multiple times in
clauses of `!$acc declare` directives for a function, subroutine, program,
or module, but it is allowed with a warning when same clause is used.
-* The OpenACC specification does not disallow the same variable from appearing
+* The OpenACC specification does not prohibit the same variable from appearing
in multiple data clauses, but this is disallowed for variables appearing in
`private`, `firstprivate`, or `reduction` clauses.
-* The OpenACC specification does not disallow the same variable from appearing
+* The OpenACC specification does not prohibit the same variable from appearing
multiple times in a `use_device` clause on a `host_data` construct, but this
is disallowed.
More information about the flang-commits
mailing list