[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 23:22:02 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 fdf658171033906623a2360f46f07eec19dca84c 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

Move conflict detection and symbol registration into ResolveOmpCommonBlock
so that CheckMultipleAppearances stays generic. Detect member conflicts
before AddToContextObjectWithExplicitDSA so FindObjectWithDSAByUltimate
only sees prior clauses, which is required for the firstprivate/lastprivate
exception. Report a single diagnostic using the block name, then remove
the CommonBlockDetails branch from CheckMultipleAppearances.
---
 flang/lib/Semantics/resolve-directives.cpp | 80 +++++++++++++---------
 1 file changed, 46 insertions(+), 34 deletions(-)

diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 86bc1e144a113..9ebb444df4fde 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -3199,6 +3199,21 @@ void OmpAttributeVisitor::PropagateOmpFlagToEquivalenceSet(
   }
 }
 
+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));
+}
+
 void OmpAttributeVisitor::ResolveOmpCommonBlock(
     const parser::Name &name, Symbol::Flag ompFlag) {
   bool cbResolved{false};
@@ -3214,6 +3229,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 +3243,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
@@ -3244,11 +3257,23 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
     bool cbCloned{cbResolved && name.symbol != originalCB};
     bool cloneCommonBlock{dataSharingAttributeFlags.test(ompFlag) && !cbCloned};
     CommonBlockDetails cloneDetails{symbol->name()};
+    bool memberConflict{false};
     for (auto [index, object] : llvm::enumerate(details.objects())) {
       if (auto *resolvedObject{ResolveOmp(*object, ompFlag, currScope())}) {
         if (dataCopyingAttributeFlags.test(ompFlag)) {
           CheckDataCopyingClause(name, *resolvedObject, ompFlag);
         } else {
+          // Check for member conflicts before recording this clause's DSA so
+          // that FindObjectWithDSAByUltimate only reflects prior clauses.
+          if (!memberConflict && !allowRepeatedAppearance &&
+              dataSharingAttributeFlags.test(ompFlag)) {
+            const Symbol &member{object->GetUltimate()};
+            if (HasDataSharingAttributeObject(member) &&
+                !WithMultipleAppearancesOmpException(member, ompFlag,
+                    GetContext().FindObjectWithDSAByUltimate(member))) {
+              memberConflict = true;
+            }
+          }
           AddToContextObjectWithExplicitDSA(*resolvedObject, ompFlag);
         }
         if (cloneCommonBlock) {
@@ -3263,6 +3288,22 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
         }
       }
     }
+    if (!dataCopyingAttributeFlags.test(ompFlag) && !allowRepeatedAppearance) {
+      const Symbol &blockUltimate{symbol->GetUltimate()};
+      bool conflicts{memberConflict ||
+          HasDataSharingAttributeObject(blockUltimate)};
+      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(blockUltimate);
+        for (const auto &object : details.objects()) {
+          AddDataSharingAttributeObject(*object);
+        }
+      }
+    }
     if (cloneCommonBlock) {
       name.symbol = &currScope().MakeSymbol(
           symbol->name(), symbol->attrs(), std::move(cloneDetails));
@@ -3336,21 +3377,6 @@ 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;
-  }
-  return (flag == Symbol::Flag::OmpFirstPrivate &&
-             symbol.test(Symbol::Flag::OmpLastPrivate)) ||
-      (flag == Symbol::Flag::OmpLastPrivate &&
-          symbol.test(Symbol::Flag::OmpFirstPrivate));
-}
-
 void OmpAttributeVisitor::CheckMultipleAppearances(
     const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
   const Symbol &ultimate{symbol.GetUltimate()};
@@ -3358,15 +3384,6 @@ void OmpAttributeVisitor::CheckMultipleAppearances(
   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()) {
-        if (HasDataSharingAttributeObject(*object) &&
-            !WithMultipleAppearancesOmpException(*object, ompFlag,
-                GetContext().FindObjectWithDSAByUltimate(*object))) {
-          conflicts = true;
-          break;
-        }
-      }
     }
   }
   if (conflicts && !WithMultipleAppearancesOmpException(symbol, ompFlag)) {
@@ -3376,11 +3393,6 @@ void OmpAttributeVisitor::CheckMultipleAppearances(
         name.ToString());
   } else {
     AddDataSharingAttributeObject(ultimate);
-    if (const auto *details{ultimate.detailsIf<CommonBlockDetails>()}) {
-      for (const auto &object : details->objects()) {
-        AddDataSharingAttributeObject(*object);
-      }
-    }
   }
 }
 



More information about the flang-commits mailing list