[flang-commits] [flang] [flang][OpenMP] Detect conflicting data-sharing clauses for common blocks (PR #213913)

via flang-commits flang-commits at lists.llvm.org
Wed Sep 2 00:13:59 PDT 2026


https://github.com/ejose02 updated https://github.com/llvm/llvm-project/pull/213913

>From 97b57c3c6d64b042e6941f22c0ba4d44e16bdb25 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Wed, 5 Aug 2026 07:04:49 +0000
Subject: [PATCH 1/4] [flang][OpenMP] Detect conflicting data-sharing clauses
 for common blocks

OpenMP 2.15.3 treats a named common block in a data-sharing clause as equivalent to listing every explicit member. Extend CheckMultipleAppearances to detect overlap between a common block and its members, register explicit members when a common block is listed, and consult FindSymbolWithDSA in the existing firstprivate/lastprivate multiple-appearance exception. Added a regression test.

Fixes #205779
---
 flang/lib/Semantics/resolve-directives.cpp    | 57 +++++++++++++++++--
 .../OpenMP/common-block-data-sharing.f90      | 11 ++++
 2 files changed, 64 insertions(+), 4 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/common-block-data-sharing.f90

diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index dba3809c110e3..8733aa5abb9eb 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -73,6 +73,19 @@ template <typename T> class DirectiveAttributeVisitor {
       return std::nullopt;
     }
 
+    std::optional<Symbol::Flag> FindExplicitDSAForMember(const Symbol &symbol) {
+      if (auto flag{FindSymbolWithDSA(symbol)}) {
+        return flag;
+      }
+      const Symbol &ultimate{symbol.GetUltimate()};
+      for (const auto &entry : objectWithDSA) {
+        if (entry.first->GetUltimate() == ultimate) {
+          return entry.second;
+        }
+      }
+      return std::nullopt;
+    }
+
     bool withinConstruct{false};
     std::int64_t associatedLoopLevel{0};
   };
@@ -603,6 +616,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
 
   bool Pre(const parser::OmpDeclareSimdDirective &x) {
     PushContext(x.source, llvm::omp::Directive::OMPD_declare_simd);
+    ClearDataSharingAttributeObjects();
     for (const parser::OmpArgument &arg : x.v.Arguments().v) {
       if (auto *object{parser::omp::GetArgumentObject(arg)}) {
         ResolveOmpObject(*object, Symbol::Flag::OmpDeclareSimd);
@@ -3219,7 +3233,7 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
                   !it->second.test(Symbol::Flag::OmpUseDeviceAddr)))};
       it->second.set(ompFlag);
       if (!allowRepeatedAppearance) {
-        CheckMultipleAppearances(name, *symbol, Symbol::Flag::OmpCommonBlock);
+        CheckMultipleAppearances(name, *symbol, ompFlag);
       }
     }
     // 2.15.3 When a named common block appears in a list, it has the
@@ -3329,6 +3343,14 @@ static bool WithMultipleAppearancesOmpException(
           symbol.test(Symbol::Flag::OmpFirstPrivate));
 }
 
+static bool IsFirstPrivateLastPrivatePair(
+    Symbol::Flag flag, Symbol::Flag prevFlag) {
+  return (flag == Symbol::Flag::OmpFirstPrivate &&
+             prevFlag == Symbol::Flag::OmpLastPrivate) ||
+      (flag == Symbol::Flag::OmpLastPrivate &&
+          prevFlag == Symbol::Flag::OmpFirstPrivate);
+}
+
 void OmpAttributeVisitor::CheckMultipleAppearances(
     const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
   const auto *target{&symbol};
@@ -3337,14 +3359,41 @@ void OmpAttributeVisitor::CheckMultipleAppearances(
       target = &details->symbol();
     }
   }
-  if (HasDataSharingAttributeObject(target->GetUltimate()) &&
-      !WithMultipleAppearancesOmpException(symbol, ompFlag)) {
+  const Symbol &ultimate{target->GetUltimate()};
+  bool conflicts{HasDataSharingAttributeObject(ultimate)};
+  if (!conflicts) {
+    if (const Symbol *commonBlock{FindCommonBlockContaining(ultimate)}) {
+      conflicts = HasDataSharingAttributeObject(*commonBlock);
+    } else if (const auto *details{ultimate.detailsIf<CommonBlockDetails>()}) {
+      for (const auto &object : details->objects()) {
+        const Symbol &member{object->GetUltimate()};
+        if (HasDataSharingAttributeObject(member)) {
+          bool allowed{WithMultipleAppearancesOmpException(member, ompFlag)};
+          if (!allowed) {
+            if (auto prevFlag{GetContext().FindExplicitDSAForMember(member)}) {
+              allowed = IsFirstPrivateLastPrivatePair(ompFlag, *prevFlag);
+            }
+          }
+          if (!allowed) {
+            conflicts = true;
+            break;
+          }
+        }
+      }
+    }
+  }
+  if (conflicts && !WithMultipleAppearancesOmpException(symbol, ompFlag)) {
     context_.Say(name.source,
         "'%s' appears in more than one data-sharing clause "
         "on the same OpenMP directive"_err_en_US,
         name.ToString());
   } else {
-    AddDataSharingAttributeObject(target->GetUltimate());
+    AddDataSharingAttributeObject(ultimate);
+    if (const auto *details{ultimate.detailsIf<CommonBlockDetails>()}) {
+      for (const auto &object : details->objects()) {
+        AddDataSharingAttributeObject(object->GetUltimate());
+      }
+    }
   }
 }
 
diff --git a/flang/test/Semantics/OpenMP/common-block-data-sharing.f90 b/flang/test/Semantics/OpenMP/common-block-data-sharing.f90
new file mode 100644
index 0000000000000..f0ddf8e048441
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/common-block-data-sharing.f90
@@ -0,0 +1,11 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp
+
+! a common block in a data-sharing clause is equivalent to
+! listing every explicit member of the common block.
+
+subroutine common_block_dsa()
+  common /c/ x, y
+  !ERROR: 'x' appears in more than one data-sharing clause on the same OpenMP directive
+  !$omp parallel private(/c/) shared(x)
+  !$omp end parallel
+end subroutine

>From 3d589c0f0eab528a5611cebef69640020c7d6a0e Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Mon, 17 Aug 2026 11:25:31 +0000
Subject: [PATCH 2/4] Fold the firstprivate/lastprivate exception into
 WithMultipleAppearancesOmpException via an optional prevFlag, remove the
 duplicate helper, and simplify the common-block member loop using
 FindObjectWithDSAByUltimate for scoped ultimate-symbol DSA lookup.

---
 flang/lib/Semantics/resolve-directives.cpp | 38 +++++++++-------------
 1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 8733aa5abb9eb..da4b21059b6aa 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -73,7 +73,8 @@ template <typename T> class DirectiveAttributeVisitor {
       return std::nullopt;
     }
 
-    std::optional<Symbol::Flag> FindExplicitDSAForMember(const Symbol &symbol) {
+    std::optional<Symbol::Flag> FindObjectWithDSAByUltimate(
+        const Symbol &symbol) {
       if (auto flag{FindSymbolWithDSA(symbol)}) {
         return flag;
       }
@@ -3335,22 +3336,21 @@ Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity(
   return &object;
 }
 
-static bool WithMultipleAppearancesOmpException(
-    const Symbol &symbol, Symbol::Flag flag) {
+static bool WithMultipleAppearancesOmpException(const Symbol &symbol,
+    Symbol::Flag flag, std::optional<Symbol::Flag> prevFlag = std::nullopt) {
+  if (prevFlag &&
+      ((flag == Symbol::Flag::OmpFirstPrivate &&
+           *prevFlag == Symbol::Flag::OmpLastPrivate) ||
+          (flag == Symbol::Flag::OmpLastPrivate &&
+              *prevFlag == Symbol::Flag::OmpFirstPrivate))) {
+    return true;
+  }
   return (flag == Symbol::Flag::OmpFirstPrivate &&
              symbol.test(Symbol::Flag::OmpLastPrivate)) ||
       (flag == Symbol::Flag::OmpLastPrivate &&
           symbol.test(Symbol::Flag::OmpFirstPrivate));
 }
 
-static bool IsFirstPrivateLastPrivatePair(
-    Symbol::Flag flag, Symbol::Flag prevFlag) {
-  return (flag == Symbol::Flag::OmpFirstPrivate &&
-             prevFlag == Symbol::Flag::OmpLastPrivate) ||
-      (flag == Symbol::Flag::OmpLastPrivate &&
-          prevFlag == Symbol::Flag::OmpFirstPrivate);
-}
-
 void OmpAttributeVisitor::CheckMultipleAppearances(
     const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
   const auto *target{&symbol};
@@ -3367,17 +3367,11 @@ void OmpAttributeVisitor::CheckMultipleAppearances(
     } else if (const auto *details{ultimate.detailsIf<CommonBlockDetails>()}) {
       for (const auto &object : details->objects()) {
         const Symbol &member{object->GetUltimate()};
-        if (HasDataSharingAttributeObject(member)) {
-          bool allowed{WithMultipleAppearancesOmpException(member, ompFlag)};
-          if (!allowed) {
-            if (auto prevFlag{GetContext().FindExplicitDSAForMember(member)}) {
-              allowed = IsFirstPrivateLastPrivatePair(ompFlag, *prevFlag);
-            }
-          }
-          if (!allowed) {
-            conflicts = true;
-            break;
-          }
+        if (HasDataSharingAttributeObject(member) &&
+            !WithMultipleAppearancesOmpException(member, ompFlag,
+                GetContext().FindObjectWithDSAByUltimate(member))) {
+          conflicts = true;
+          break;
         }
       }
     }

>From d5188b34bb7bff3ff96ca860b42f667f04efe6fc Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Tue, 18 Aug 2026 06:51:07 +0000
Subject: [PATCH 3/4] Simplify CheckMultipleAppearances per review Use
 symbol.GetUltimate() directly and drop redundant GetUltimate() calls on
 common-block members.

---
 flang/lib/Semantics/resolve-directives.cpp | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index da4b21059b6aa..86bc1e144a113 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -3353,23 +3353,16 @@ static bool WithMultipleAppearancesOmpException(const Symbol &symbol,
 
 void OmpAttributeVisitor::CheckMultipleAppearances(
     const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
-  const auto *target{&symbol};
-  if (ompFlagsRequireNewSymbol.test(ompFlag)) {
-    if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) {
-      target = &details->symbol();
-    }
-  }
-  const Symbol &ultimate{target->GetUltimate()};
+  const Symbol &ultimate{symbol.GetUltimate()};
   bool conflicts{HasDataSharingAttributeObject(ultimate)};
   if (!conflicts) {
     if (const Symbol *commonBlock{FindCommonBlockContaining(ultimate)}) {
       conflicts = HasDataSharingAttributeObject(*commonBlock);
     } else if (const auto *details{ultimate.detailsIf<CommonBlockDetails>()}) {
       for (const auto &object : details->objects()) {
-        const Symbol &member{object->GetUltimate()};
-        if (HasDataSharingAttributeObject(member) &&
-            !WithMultipleAppearancesOmpException(member, ompFlag,
-                GetContext().FindObjectWithDSAByUltimate(member))) {
+        if (HasDataSharingAttributeObject(*object) &&
+            !WithMultipleAppearancesOmpException(*object, ompFlag,
+                GetContext().FindObjectWithDSAByUltimate(*object))) {
           conflicts = true;
           break;
         }
@@ -3385,7 +3378,7 @@ void OmpAttributeVisitor::CheckMultipleAppearances(
     AddDataSharingAttributeObject(ultimate);
     if (const auto *details{ultimate.detailsIf<CommonBlockDetails>()}) {
       for (const auto &object : details->objects()) {
-        AddDataSharingAttributeObject(object->GetUltimate());
+        AddDataSharingAttributeObject(*object);
       }
     }
   }

>From cdd8265fb2571470d585aed26320bfafbfc49872 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Tue, 1 Sep 2026 09:27:02 +0000
Subject: [PATCH 4/4] [flang][OpenMP] Check common-block DSA overlap at block
 level

Keep CheckMultipleAppearances on the common block symbol after member
resolution. Per-member duplicate checks misreport conflicts on members
when the block was already listed via another clause.

Extend CheckMultipleAppearances to treat a listed common block as its
members for overlap detection and registration, per OpenMP 2.15.3.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 flang/lib/Semantics/resolve-directives.cpp | 39 +++++-----------------
 1 file changed, 9 insertions(+), 30 deletions(-)

diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 86bc1e144a113..0f3a519256026 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -73,20 +73,6 @@ template <typename T> class DirectiveAttributeVisitor {
       return std::nullopt;
     }
 
-    std::optional<Symbol::Flag> FindObjectWithDSAByUltimate(
-        const Symbol &symbol) {
-      if (auto flag{FindSymbolWithDSA(symbol)}) {
-        return flag;
-      }
-      const Symbol &ultimate{symbol.GetUltimate()};
-      for (const auto &entry : objectWithDSA) {
-        if (entry.first->GetUltimate() == ultimate) {
-          return entry.second;
-        }
-      }
-      return std::nullopt;
-    }
-
     bool withinConstruct{false};
     std::int64_t associatedLoopLevel{0};
   };
@@ -3214,6 +3200,7 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
   parser::Name cbName{name};
   Symbol *originalCB{ResolveOmpCommonBlockName(&cbName)};
   if (auto *symbol{cbResolved ? name.symbol : originalCB}) {
+    bool allowRepeatedAppearance{false};
     if (!dataCopyingAttributeFlags.test(ompFlag)) {
       const Symbol::Flags mapFlags{Symbol::Flag::OmpMapTo,
           Symbol::Flag::OmpMapFrom, Symbol::Flag::OmpMapToFrom,
@@ -3227,15 +3214,12 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
       if (isTargetData) {
         allowedRepeatFlags.set(Symbol::Flag::OmpUseDeviceAddr);
       }
-      bool allowRepeatedAppearance{!inserted &&
+      allowRepeatedAppearance = !inserted &&
           (it->second & ~allowedRepeatFlags).none() &&
           (mapFlags.test(ompFlag) ||
               (isTargetData && ompFlag == Symbol::Flag::OmpUseDeviceAddr &&
-                  !it->second.test(Symbol::Flag::OmpUseDeviceAddr)))};
+                  !it->second.test(Symbol::Flag::OmpUseDeviceAddr)));
       it->second.set(ompFlag);
-      if (!allowRepeatedAppearance) {
-        CheckMultipleAppearances(name, *symbol, ompFlag);
-      }
     }
     // 2.15.3 When a named common block appears in a list, it has the
     // same meaning as if every explicit member of the common block
@@ -3263,6 +3247,9 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
         }
       }
     }
+    if (!dataCopyingAttributeFlags.test(ompFlag) && !allowRepeatedAppearance) {
+      CheckMultipleAppearances(name, *symbol, ompFlag);
+    }
     if (cloneCommonBlock) {
       name.symbol = &currScope().MakeSymbol(
           symbol->name(), symbol->attrs(), std::move(cloneDetails));
@@ -3336,15 +3323,8 @@ Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity(
   return &object;
 }
 
-static bool WithMultipleAppearancesOmpException(const Symbol &symbol,
-    Symbol::Flag flag, std::optional<Symbol::Flag> prevFlag = std::nullopt) {
-  if (prevFlag &&
-      ((flag == Symbol::Flag::OmpFirstPrivate &&
-           *prevFlag == Symbol::Flag::OmpLastPrivate) ||
-          (flag == Symbol::Flag::OmpLastPrivate &&
-              *prevFlag == Symbol::Flag::OmpFirstPrivate))) {
-    return true;
-  }
+static bool WithMultipleAppearancesOmpException(
+    const Symbol &symbol, Symbol::Flag flag) {
   return (flag == Symbol::Flag::OmpFirstPrivate &&
              symbol.test(Symbol::Flag::OmpLastPrivate)) ||
       (flag == Symbol::Flag::OmpLastPrivate &&
@@ -3361,8 +3341,7 @@ void OmpAttributeVisitor::CheckMultipleAppearances(
     } else if (const auto *details{ultimate.detailsIf<CommonBlockDetails>()}) {
       for (const auto &object : details->objects()) {
         if (HasDataSharingAttributeObject(*object) &&
-            !WithMultipleAppearancesOmpException(*object, ompFlag,
-                GetContext().FindObjectWithDSAByUltimate(*object))) {
+            !WithMultipleAppearancesOmpException(*object, ompFlag)) {
           conflicts = true;
           break;
         }



More information about the flang-commits mailing list