[flang-commits] [flang] [flang][OpenMP] Separate checks for type-parameter inquiry and subobject (PR #201324)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Wed Jun 3 04:32:39 PDT 2026
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/201324
>From 9877fa75ab9e63b8c705ddaf9e840781975c732c Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Sun, 17 May 2026 07:18:36 -0500
Subject: [PATCH 1/2] [flang][OpenMP] Separate checks for type-parameter
inquiry and subobject
This will make it possible to diagnose these situations independently.
This isn't perfect, but will be improved gradually in the future.
---
flang/lib/Semantics/check-omp-structure.cpp | 77 +++++++++++++--------
flang/lib/Semantics/check-omp-structure.h | 6 +-
2 files changed, 54 insertions(+), 29 deletions(-)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 1ac43b666977b..055fa2325f5a1 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1630,6 +1630,7 @@ void OmpStructureChecker::Leave(const parser::OmpThreadprivateDirective &x) {
for (const parser::OmpArgument &arg : x.v.Arguments().v) {
if (auto *object{GetArgumentObject(arg)}) {
CheckSymbolName(dirSpec.source, *object);
+ CheckTypeParamInquiry(dirSpec.source, *object);
CheckVarIsNotPartOfAnotherVar(dirSpec.source, *object);
CheckThreadprivateOrDeclareTargetVar(*object);
}
@@ -2007,6 +2008,7 @@ void OmpStructureChecker::CheckIndividualAllocateDirective(
if (!IsTypeParamInquiry(*symbol)) {
checkSymbol(*symbol, arg.source);
}
+ CheckTypeParamInquiry(dirName.source, *object);
CheckVarIsNotPartOfAnotherVar(dirName.source, *object);
}
}
@@ -2337,6 +2339,7 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetDirective &x) {
if (auto *object{GetArgumentObject(arg)}) {
deviceConstructFound_ = true;
CheckSymbolName(dirName.source, *object);
+ CheckTypeParamInquiry(dirName.source, *object);
CheckVarIsNotPartOfAnotherVar(dirName.source, *object);
CheckThreadprivateOrDeclareTargetVar(*object);
}
@@ -2382,6 +2385,7 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetDirective &x) {
std::is_same_v<TypeC, parser::OmpClause::To>) {
auto &objList{*GetOmpObjectList(c)};
CheckSymbolNames(dirName.source, objList);
+ CheckTypeParamInquiry(dirName.source, objList);
CheckVarIsNotPartOfAnotherVar(dirName.source, objList);
CheckThreadprivateOrDeclareTargetVar(objList);
}
@@ -2530,6 +2534,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPAllocatorsConstruct &x) {
continue;
}
for (auto &object : DEREF(GetOmpObjectList(clause)).v) {
+ CheckTypeParamInquiry(dirName.source, object);
CheckVarIsNotPartOfAnotherVar(dirName.source, object);
if (auto *symbol{GetObjectSymbol(object, /*ultimate=*/true)}) {
if (IsStructureComponent(*symbol)) {
@@ -4171,6 +4176,7 @@ void OmpStructureChecker::CheckSharedBindingInOuterContext(
void OmpStructureChecker::Enter(const parser::OmpClause::Shared &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_shared);
+ CheckTypeParamInquiry(GetContext().clauseSource, x.v);
CheckVarIsNotPartOfAnotherVar(GetContext().clauseSource, x.v, "SHARED");
CheckCrayPointee(x.v, "SHARED");
}
@@ -4178,6 +4184,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
SymbolSourceMap symbols;
GetSymbolsInObjectList(x.v, symbols);
CheckAllowedClause(llvm::omp::Clause::OMPC_private);
+ CheckTypeParamInquiry(GetContext().clauseSource, x.v);
CheckVarIsNotPartOfAnotherVar(GetContext().clauseSource, x.v, "PRIVATE");
CheckIntentInPointer(symbols, llvm::omp::Clause::OMPC_private);
CheckCrayPointee(x.v, "PRIVATE");
@@ -4188,6 +4195,24 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Nowait &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_nowait);
}
+void OmpStructureChecker::CheckTypeParamInquiry(
+ const parser::CharBlock &source, const parser::OmpObject &object) {
+ if (const Symbol *symbol{GetObjectSymbol(object)}) {
+ if (IsTypeParamInquiry(*symbol)) {
+ context_.Say(source,
+ "A type parameter inquiry cannot appear on the %s directive"_err_en_US,
+ ContextDirectiveAsFortran());
+ }
+ }
+}
+
+void OmpStructureChecker::CheckTypeParamInquiry(
+ const parser::CharBlock &source, const parser::OmpObjectList &objects) {
+ for (const parser::OmpObject &object : objects.v) {
+ CheckTypeParamInquiry(source, object);
+ }
+}
+
void OmpStructureChecker::CheckVarIsNotPartOfAnotherVar(
const parser::CharBlock &source, const parser::OmpObjectList &objList,
llvm::StringRef clause) {
@@ -4197,40 +4222,33 @@ void OmpStructureChecker::CheckVarIsNotPartOfAnotherVar(
}
void OmpStructureChecker::CheckVarIsNotPartOfAnotherVar(
- const parser::CharBlock &source, const parser::OmpObject &ompObject,
+ const parser::CharBlock &source, const parser::OmpObject &object,
llvm::StringRef clause) {
- common::visit(
- common::visitors{
- [&](const parser::Designator &designator) {
- if (auto *symbol{GetLastName(designator).symbol};
- symbol && IsTypeParamInquiry(*symbol)) {
- context_.Say(source,
- "A type parameter inquiry cannot appear on the %s directive"_err_en_US,
- ContextDirectiveAsFortran());
- } else if (std::holds_alternative<parser::DataRef>(designator.u)) {
- if (parser::Unwrap<parser::StructureComponent>(ompObject) ||
- parser::Unwrap<parser::ArrayElement>(ompObject)) {
- if (llvm::omp::nonPartialVarSet.test(GetContext().directive)) {
- context_.Say(source,
- "A variable that is part of another variable (as an array or structure element) cannot appear on the %s directive"_err_en_US,
- ContextDirectiveAsFortran());
- } else {
- context_.Say(source,
- "A variable that is part of another variable (as an array or structure element) cannot appear in a %s clause"_err_en_US,
- clause.data());
- }
- }
- }
- },
- [&](const parser::Name &name) {},
- [&](const parser::OmpObject::Invalid &invalid) {},
- },
- ompObject.u);
+ bool report{false};
+ if (auto *symbol{GetObjectSymbol(object)}) {
+ if (IsTypeParamInquiry(*symbol)) {
+ return;
+ }
+ report = IsStructureComponent(*symbol);
+ }
+
+ if (report || parser::Unwrap<parser::ArrayElement>(object)) {
+ if (llvm::omp::nonPartialVarSet.test(GetContext().directive)) {
+ context_.Say(source,
+ "A variable that is part of another variable (as an array or structure element) cannot appear on the %s directive"_err_en_US,
+ ContextDirectiveAsFortran());
+ } else {
+ context_.Say(source,
+ "A variable that is part of another variable (as an array or structure element) cannot appear in a %s clause"_err_en_US,
+ clause.str());
+ }
+ }
}
void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_firstprivate);
+ CheckTypeParamInquiry(GetContext().clauseSource, x.v);
CheckVarIsNotPartOfAnotherVar(GetContext().clauseSource, x.v, "FIRSTPRIVATE");
CheckCrayPointee(x.v, "FIRSTPRIVATE");
@@ -4434,6 +4452,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Detach &x) {
// OpenMP 5.0: 2.10.1 Task construct restrictions
CheckAllowedClause(llvm::omp::Clause::OMPC_detach);
}
+
+ CheckTypeParamInquiry(GetContext().clauseSource, x.v.v);
// OpenMP 5.2: 12.5.2 Detach clause restrictions
if (version >= 52) {
CheckVarIsNotPartOfAnotherVar(GetContext().clauseSource, x.v.v, "DETACH");
@@ -4899,6 +4919,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_lastprivate);
const auto &objectList{*GetOmpObjectList(x)};
+ CheckTypeParamInquiry(GetContext().clauseSource, objectList);
CheckVarIsNotPartOfAnotherVar(
GetContext().clauseSource, objectList, "LASTPRIVATE");
CheckCrayPointee(objectList, "LASTPRIVATE");
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 6e693fa7b8e48..2baec90c90ca6 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -334,8 +334,12 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
void CheckDoacross(const parser::OmpDoacross &doa);
void CheckDimsModifier(parser::CharBlock source, size_t numValues,
const parser::OmpDimsModifier &x);
+ void CheckTypeParamInquiry(const parser::CharBlock &source,
+ const parser::OmpObject &object);
+ void CheckTypeParamInquiry(const parser::CharBlock &source,
+ const parser::OmpObjectList &objects);
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
- const parser::OmpObject &obj, llvm::StringRef clause = "");
+ const parser::OmpObject &object, llvm::StringRef clause = "");
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
const parser::OmpObjectList &objList, llvm::StringRef clause = "");
void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
>From 5961e1fe9432d66242e3cbbda04765ac37e77b65 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 3 Jun 2026 06:32:25 -0500
Subject: [PATCH 2/2] format
---
flang/lib/Semantics/check-omp-structure.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 2baec90c90ca6..8a85f489eeb4c 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -334,10 +334,10 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
void CheckDoacross(const parser::OmpDoacross &doa);
void CheckDimsModifier(parser::CharBlock source, size_t numValues,
const parser::OmpDimsModifier &x);
- void CheckTypeParamInquiry(const parser::CharBlock &source,
- const parser::OmpObject &object);
- void CheckTypeParamInquiry(const parser::CharBlock &source,
- const parser::OmpObjectList &objects);
+ void CheckTypeParamInquiry(
+ const parser::CharBlock &source, const parser::OmpObject &object);
+ void CheckTypeParamInquiry(
+ const parser::CharBlock &source, const parser::OmpObjectList &objects);
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
const parser::OmpObject &object, llvm::StringRef clause = "");
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
More information about the flang-commits
mailing list