[flang-commits] [flang] da88ce2 - [flang][OpenMP] Add type-param-inquiry checks for non-list clauses (#203059)
via flang-commits
flang-commits at lists.llvm.org
Thu Jun 11 10:58:36 PDT 2026
Author: Krzysztof Parzyszek
Date: 2026-06-11T12:58:31-05:00
New Revision: da88ce239d718d0f985fdd2268e0d111138ca506
URL: https://github.com/llvm/llvm-project/commit/da88ce239d718d0f985fdd2268e0d111138ca506
DIFF: https://github.com/llvm/llvm-project/commit/da88ce239d718d0f985fdd2268e0d111138ca506.diff
LOG: [flang][OpenMP] Add type-param-inquiry checks for non-list clauses (#203059)
Clauses that take lists of objects have these objects checked in a
single place. There are still several clauses that take variables, but
not via a list. Those clauses still need individual checks for
type-param inquiries.
Added:
flang/test/Semantics/OpenMP/type-param-inquiry.f90
Modified:
flang/lib/Semantics/check-omp-structure.cpp
flang/lib/Semantics/check-omp-structure.h
Removed:
################################################################################
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 046fc98c7d80c..4eb3885b41a7c 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1743,7 +1743,8 @@ void OmpStructureChecker::Leave(const parser::OmpThreadprivateDirective &x) {
const parser::OmpDirectiveSpecification &dirSpec{x.v};
for (const parser::OmpArgument &arg : x.v.Arguments().v) {
if (auto *object{GetArgumentObject(arg)}) {
- CheckTypeParamInquiry(dirSpec.source, *object);
+ CheckTypeParamInquiry(
+ dirSpec.source, *object, llvm::omp::Directive::OMPD_threadprivate);
CheckVarIsNotPartOfAnotherVar(dirSpec.source, *object);
CheckThreadprivateOrDeclareTargetVar(*object);
}
@@ -1842,6 +1843,9 @@ void OmpStructureChecker::CheckInitOnDepobj(
"The INIT clause is not allowed when the DEPOBJ directive has an argument"_err_en_US);
}
+ CheckTypeParamInquiry(initClause.source, std::get<parser::OmpObject>(init.t),
+ llvm::omp::Clause::OMPC_init);
+
if (!OmpVerifyModifiers(
init, llvm::omp::Clause::OMPC_init, initClause.source, context_)) {
return;
@@ -2121,7 +2125,8 @@ void OmpStructureChecker::CheckIndividualAllocateDirective(
if (!IsTypeParamInquiry(*symbol)) {
checkSymbol(*symbol, arg.source);
}
- CheckTypeParamInquiry(dirName.source, *object);
+ CheckTypeParamInquiry(
+ dirName.source, *object, llvm::omp::Directive::OMPD_allocate);
CheckVarIsNotPartOfAnotherVar(dirName.source, *object);
}
}
@@ -2419,7 +2424,8 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetDirective &x) {
for (const parser::OmpArgument &arg : x.v.Arguments().v) {
if (auto *object{GetArgumentObject(arg)}) {
deviceConstructFound_ = true;
- CheckTypeParamInquiry(dirName.source, *object);
+ CheckTypeParamInquiry(
+ dirName.source, *object, llvm::omp::Directive::OMPD_declare_target);
CheckVarIsNotPartOfAnotherVar(dirName.source, *object);
CheckThreadprivateOrDeclareTargetVar(*object);
}
@@ -2612,7 +2618,6 @@ 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)) {
@@ -3713,6 +3718,10 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
void OmpStructureChecker::Enter(const parser::OmpClause::Destroy &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_destroy);
+ if (auto &present{x.v}) {
+ CheckTypeParamInquiry(
+ GetContext().clauseSource, present->v, llvm::omp::Clause::OMPC_destroy);
+ }
llvm::omp::Directive dir{GetContext().directive};
unsigned version{context_.langOptions().OpenMPVersion};
@@ -4223,21 +4232,25 @@ 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) {
+void OmpStructureChecker::CheckTypeParamInquiry(const parser::CharBlock &source,
+ const parser::OmpObject &object, llvm::omp::Directive dirId) {
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());
+ GetUpperName(dirId, context_.langOptions().OpenMPVersion));
}
}
}
-void OmpStructureChecker::CheckTypeParamInquiry(
- const parser::CharBlock &source, const parser::OmpObjectList &objects) {
- for (const parser::OmpObject &object : objects.v) {
- CheckTypeParamInquiry(source, object);
+void OmpStructureChecker::CheckTypeParamInquiry(const parser::CharBlock &source,
+ const parser::OmpObject &object, llvm::omp::Clause clauseId) {
+ if (const Symbol *symbol{GetObjectSymbol(object)}) {
+ if (IsTypeParamInquiry(*symbol)) {
+ context_.Say(source,
+ "A type parameter inquiry cannot appear on the %s clause"_err_en_US,
+ GetUpperName(clauseId, context_.langOptions().OpenMPVersion));
+ }
}
}
@@ -4484,6 +4497,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Detach &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_detach);
}
+ CheckTypeParamInquiry(
+ GetContext().clauseSource, x.v.v, llvm::omp::Clause::OMPC_detach);
// OpenMP 5.2: 12.5.2 Detach clause restrictions
if (version >= 52) {
CheckVarIsNotPartOfAnotherVar(GetContext().clauseSource, x.v.v, "DETACH");
@@ -5809,42 +5824,49 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
desc.name.str());
}
}
- const auto &interopVar{parser::Unwrap<parser::OmpObject>(
+ const auto *interopVar{parser::Unwrap<parser::OmpObject>(
std::get<parser::OmpObject>(initClause.v.t))};
- const auto *name{parser::Unwrap<parser::Name>(interopVar)};
- const auto *objectSymbol{name->symbol};
- if (llvm::is_contained(objectSymbolList, objectSymbol)) {
- context_.Say(GetContext().directiveSource,
- "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
- } else {
- objectSymbolList.insert(objectSymbol);
+ CheckTypeParamInquiry(
+ clause.source, *interopVar, llvm::omp::Clause::OMPC_init);
+ if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
+ const auto *objectSymbol{name->symbol};
+ if (llvm::is_contained(objectSymbolList, objectSymbol)) {
+ context_.Say(GetContext().directiveSource,
+ "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
+ } else {
+ objectSymbolList.insert(objectSymbol);
+ }
}
},
[&](const parser::OmpClause::Depend &dependClause) {
isDependClauseOccurred = true;
},
[&](const parser::OmpClause::Destroy &destroyClause) {
- const auto &interopVar{
+ const auto *interopVar{
parser::Unwrap<parser::OmpObject>(destroyClause.v)};
- const auto *name{parser::Unwrap<parser::Name>(interopVar)};
- const auto *objectSymbol{name->symbol};
- if (llvm::is_contained(objectSymbolList, objectSymbol)) {
- context_.Say(GetContext().directiveSource,
- "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
- } else {
- objectSymbolList.insert(objectSymbol);
+ if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
+ const auto *objectSymbol{name->symbol};
+ if (llvm::is_contained(objectSymbolList, objectSymbol)) {
+ context_.Say(GetContext().directiveSource,
+ "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
+ } else {
+ objectSymbolList.insert(objectSymbol);
+ }
}
},
[&](const parser::OmpClause::Use &useClause) {
- const auto &interopVar{
+ const auto *interopVar{
parser::Unwrap<parser::OmpObject>(useClause.v)};
- const auto *name{parser::Unwrap<parser::Name>(interopVar)};
- const auto *objectSymbol{name->symbol};
- if (llvm::is_contained(objectSymbolList, objectSymbol)) {
- context_.Say(GetContext().directiveSource,
- "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
- } else {
- objectSymbolList.insert(objectSymbol);
+ CheckTypeParamInquiry(
+ clause.source, *interopVar, llvm::omp::Clause::OMPC_use);
+ if (const auto *name{parser::Unwrap<parser::Name>(interopVar)}) {
+ const auto *objectSymbol{name->symbol};
+ if (llvm::is_contained(objectSymbolList, objectSymbol)) {
+ context_.Say(GetContext().directiveSource,
+ "Each interop-var may be specified for at most one action-clause of each INTEROP construct."_err_en_US);
+ } else {
+ objectSymbolList.insert(objectSymbol);
+ }
}
},
[&](const auto &) {},
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 66211d58e030c..42ab0c2ef5ef1 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -333,10 +333,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, llvm::omp::Directive dirId);
+ void CheckTypeParamInquiry(const parser::CharBlock &source,
+ const parser::OmpObject &object, llvm::omp::Clause clauseId);
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
const parser::OmpObject &object, llvm::StringRef clause = "");
void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
diff --git a/flang/test/Semantics/OpenMP/type-param-inquiry.f90 b/flang/test/Semantics/OpenMP/type-param-inquiry.f90
new file mode 100644
index 0000000000000..afe226f2797ba
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/type-param-inquiry.f90
@@ -0,0 +1,41 @@
+!RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=60
+
+subroutine f00
+ integer :: x
+!ERROR: A type parameter inquiry cannot appear on the INIT clause
+ !$omp interop init(x%kind)
+end
+
+subroutine f01
+ integer :: x
+!ERROR: A type parameter inquiry cannot appear on the USE clause
+ !$omp interop use(x%kind)
+end
+
+subroutine f02
+ integer :: x
+!ERROR: A type parameter inquiry cannot appear on the DESTROY clause
+ !$omp interop destroy(x%kind)
+end
+
+subroutine f03
+ integer :: x
+!ERROR: A type parameter inquiry cannot appear on the DETACH clause
+ !$omp task detach(x%kind)
+ !$omp end task
+end
+
+subroutine f04
+ integer :: x
+!ERROR: DEPOBJ syntax with no argument is not handled yet
+!ERROR: A type parameter inquiry cannot appear on the INIT clause
+!ERROR: The 'depinfo-modifier' modifier is required on a DEPOBJ construct
+ !$omp depobj init(x%kind)
+end
+
+subroutine f05
+ integer :: x
+!ERROR: DEPOBJ syntax with no argument is not handled yet
+!ERROR: A type parameter inquiry cannot appear on the DESTROY clause
+ !$omp depobj destroy(x%kind)
+end
More information about the flang-commits
mailing list