[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