[flang-commits] [flang] [flang][OpenMP] Add type-param-inquiry checks for non-list clauses (PR #203059)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Thu Jun 11 11:00:31 PDT 2026


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/203059

>From cf623c67b39825832c71acfda2b993e9d8e5e8eb Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 10 Jun 2026 12:43:00 -0500
Subject: [PATCH 1/3] [flang][OpenMP] Add type-param-inquiry checks for
 non-list clauses

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.
---
 flang/lib/Semantics/check-omp-structure.cpp   | 92 ++++++++++++-------
 flang/lib/Semantics/check-omp-structure.h     |  6 +-
 .../Semantics/OpenMP/type-param-inquiry.f90   | 42 +++++++++
 3 files changed, 103 insertions(+), 37 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/type-param-inquiry.f90

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 8651678bb2f8a..99f43160ddd7b 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1768,7 +1768,8 @@ 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);
+      CheckTypeParamInquiry(
+          dirSpec.source, *object, llvm::omp::Directive::OMPD_threadprivate);
       CheckVarIsNotPartOfAnotherVar(dirSpec.source, *object);
       CheckThreadprivateOrDeclareTargetVar(*object);
     }
@@ -1867,6 +1868,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;
@@ -2146,7 +2150,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);
     }
   }
@@ -2477,7 +2482,8 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetDirective &x) {
     if (auto *object{GetArgumentObject(arg)}) {
       deviceConstructFound_ = true;
       CheckSymbolName(dirName.source, *object);
-      CheckTypeParamInquiry(dirName.source, *object);
+      CheckTypeParamInquiry(
+          dirName.source, *object, llvm::omp::Directive::OMPD_declare_target);
       CheckVarIsNotPartOfAnotherVar(dirName.source, *object);
       CheckThreadprivateOrDeclareTargetVar(*object);
     }
@@ -2671,7 +2677,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)) {
@@ -3772,6 +3777,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};
@@ -4282,21 +4291,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));
+    }
   }
 }
 
@@ -4543,6 +4556,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");
@@ -5900,42 +5915,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 e601273d81f67..3c8ae4043071e 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -334,9 +334,11 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
   void CheckDimsModifier(parser::CharBlock source, size_t numValues,
       const parser::OmpDimsModifier &x);
   void CheckTypeParamInquiry(
-      const parser::CharBlock &source, const parser::OmpObject &object);
+      const parser::CharBlock &source, const parser::OmpObject &object,
+      llvm::omp::Directive dirId);
   void CheckTypeParamInquiry(
-      const parser::CharBlock &source, const parser::OmpObjectList &objects);
+      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..913682f7d6af0
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/type-param-inquiry.f90
@@ -0,0 +1,42 @@
+!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
+

>From a8a6ddbd73821ad943cc96ed91ed6482296d42f7 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 10 Jun 2026 12:54:20 -0500
Subject: [PATCH 2/3] format

---
 flang/lib/Semantics/check-omp-structure.h | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 41c56eb0e1f6d..6e7f2b4015d02 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -333,12 +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,
-      llvm::omp::Directive dirId);
-  void CheckTypeParamInquiry(
-      const parser::CharBlock &source, const parser::OmpObject &object,
-      llvm::omp::Clause clauseId);
+  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,

>From 896793b8c4f3903800ee332d03c9325da93dfc81 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 11 Jun 2026 09:36:53 -0500
Subject: [PATCH 3/3] Update type-param-inquiry.f90

---
 flang/test/Semantics/OpenMP/type-param-inquiry.f90 | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flang/test/Semantics/OpenMP/type-param-inquiry.f90 b/flang/test/Semantics/OpenMP/type-param-inquiry.f90
index 913682f7d6af0..afe226f2797ba 100644
--- a/flang/test/Semantics/OpenMP/type-param-inquiry.f90
+++ b/flang/test/Semantics/OpenMP/type-param-inquiry.f90
@@ -39,4 +39,3 @@ subroutine f05
 !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