[flang-commits] [flang] [flang][OpenMP] Reuse canonical default mapper names for nested mappings - fix issue #210402 (PR #212251)

via flang-commits flang-commits at lists.llvm.org
Fri Aug 14 04:42:08 PDT 2026


https://github.com/laoshd updated https://github.com/llvm/llvm-project/pull/212251

>From 88d7dd49a00d078de3c3556fa8b8207343e9458b Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Mon, 27 Jul 2026 08:13:51 -0500
Subject: [PATCH 1/7] [flang][OpenMP] Reuse canonical default mapper names for
 nested mappings

---
 flang/include/flang/Utils/OpenMP.h            |  5 ++
 .../OpenMP/DoConcurrentConversion.cpp         |  3 +-
 flang/lib/Utils/OpenMP.cpp                    | 25 +++++++++-
 ...mapper-explicit-default-nested-pointer.f90 | 46 +++++++++++++++++++
 4 files changed, 76 insertions(+), 3 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90

diff --git a/flang/include/flang/Utils/OpenMP.h b/flang/include/flang/Utils/OpenMP.h
index e8627347fd578..0cb77e25af947 100644
--- a/flang/include/flang/Utils/OpenMP.h
+++ b/flang/include/flang/Utils/OpenMP.h
@@ -64,6 +64,11 @@ void cloneOrMapRegionOutsiders(
 using RecordMemberMapperMangler =
     std::function<void(std::string &mapperId, llvm::StringRef memberName)>;
 
+/// Build the canonical symbol name for a derived type's default mapper from
+/// the FIR record type. This matches the compiler-generated name shape used by
+/// explicit default declare mapper lowering.
+std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType);
+
 mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
     fir::FirOpBuilder &firOpBuilder, mlir::Location loc,
     fir::RecordType recordType, llvm::StringRef mapperNameStr,
diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
index 945250daf1dbe..b50f5ccf6a323 100644
--- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
@@ -621,7 +621,8 @@ class DoConcurrentConversion
     mlir::FlatSymbolRefAttr mapperId;
     if (requiresImplcitMapper) {
       std::string mapperIdName =
-          recordType.getName().str() + llvm::omp::OmpDefaultMapperName;
+          Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+              recordType);
       // TODO Add a mangler callback once nested record types are supported.
       mapperId = Fortran::utils::openmp::getOrGenImplicitDefaultDeclareMapper(
           builder, liveIn.getLoc(), recordType, mapperIdName);
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 9c22cc950e3f7..ebc5062eb39f0 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -13,11 +13,33 @@
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Dialect/FIROps.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Support/InternalNames.h"
 
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "mlir/Transforms/RegionUtils.h"
 
 namespace Fortran::utils::openmp {
+std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
+  auto [kind, deconstructed] =
+      fir::NameUniquer::deconstruct(recordType.getName());
+  if (kind != fir::NameUniquer::NameKind::DERIVED_TYPE)
+    return recordType.getName().str() + llvm::omp::OmpDefaultMapperName;
+
+  llvm::SmallVector<llvm::StringRef> modules;
+  llvm::SmallVector<llvm::StringRef> procs;
+  modules.reserve(deconstructed.modules.size());
+  procs.reserve(deconstructed.procs.size());
+  for (const std::string &module : deconstructed.modules)
+    modules.emplace_back(module);
+  for (const std::string &proc : deconstructed.procs) {
+    procs.emplace_back(proc);
+  }
+
+  std::string mapperName = deconstructed.name + llvm::omp::OmpDefaultMapperName;
+  return fir::NameUniquer::doGenerated(
+      modules, procs, deconstructed.blockId, mapperName);
+}
+
 mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
     mlir::Location loc, mlir::Value baseAddr, mlir::Value varPtrPtr,
     llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,
@@ -260,8 +282,7 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
     mlir::FlatSymbolRefAttr mapperId;
     if (auto recType = mlir::dyn_cast<fir::RecordType>(
             fir::getFortranElementType(memberType))) {
-      std::string mapperIdName =
-          recType.getName().str() + llvm::omp::OmpDefaultMapperName;
+      std::string mapperIdName = getCanonicalDefaultDeclareMapperName(recType);
       mangler(mapperIdName, memberName);
       mapperId = getOrGenImplicitDefaultDeclareMapper(
           firOpBuilder, loc, recType, mapperIdName, mangler);
diff --git a/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90 b/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
new file mode 100644
index 0000000000000..9c41cbb0a00b2
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
@@ -0,0 +1,46 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! Test that when an explicit default DECLARE MAPPER is defined for a type (newdata)
+! whose only component is a pointer, and that type is used as an allocatable component
+! of another type (newvec), the compiler-generated implicit mapper for newvec correctly
+! references the user-defined mapper for newdata rather than synthesising a new
+! implicit one that would silently skip the pointer component.
+!
+! An explicit `map(s)` on a newvec variable is the code-path that triggers implicit
+! mapper generation for newvec (unlike an implicit target capture, which suppresses
+! mapper generation for plain non-allocatable/non-pointer derived types).
+
+module m
+  type :: newdata
+    real(8), pointer :: value
+  end type
+  !$omp declare mapper(default: newdata :: v) map(tofrom: v%value)
+
+  type :: newvec
+    integer :: len
+    type(newdata), allocatable :: data(:)
+  end type
+end module
+
+program main
+  use m
+  implicit none
+  type(newvec) :: s
+
+  ! Explicit map(s) triggers implicit mapper generation for newvec.
+  !$omp target data map(s)
+    s%len = 0
+  !$omp end target data
+end program
+
+! The user-defined default mapper for newdata must have tofrom map for v%value.
+! CHECK-DAG: omp.declare_mapper @_QQMmnewdata_omp_default_mapper
+! CHECK-DAG: map_clauses(tofrom)
+! CHECK-DAG: {name = "v%value"}
+
+! The implicit default mapper for newvec must reference the user-defined newdata
+! mapper by its canonical name.  Before the fix this referenced a separately-
+! synthesised bogus mapper (@_QMmTnewdata_omp_default_mapper) that had no maps
+! for pointer components, causing a null-address device fault at runtime.
+! CHECK-DAG: omp.declare_mapper @_QQMmnewvec_omp_default_mapper
+! CHECK-DAG: mapper(@_QQMmnewdata_omp_default_mapper)
\ No newline at end of file

>From 63da3e7b443ac77aaf15ed0fbce7b01696162551 Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Mon, 27 Jul 2026 12:41:15 -0500
Subject: [PATCH 2/7] [flang][OpenMP] Preserve PDT kinds in implicit mapper
 canonical names

---
 flang/lib/Utils/OpenMP.cpp                    | 16 ++++++++-
 ...lare-mapper-implicit-default-pdt-kinds.f90 | 35 +++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90

diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index ebc5062eb39f0..4023c8bd21542 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -20,6 +20,18 @@
 
 namespace Fortran::utils::openmp {
 std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
+  auto appendKinds = [](std::string &name,
+                        llvm::ArrayRef<std::int64_t> kinds) {
+    for (std::int64_t kind : kinds) {
+      name.append("K");
+      if (kind < 0) {
+        name.append("N");
+        kind = -kind;
+      }
+      name.append(std::to_string(kind));
+    }
+  };
+
   auto [kind, deconstructed] =
       fir::NameUniquer::deconstruct(recordType.getName());
   if (kind != fir::NameUniquer::NameKind::DERIVED_TYPE)
@@ -35,7 +47,9 @@ std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
     procs.emplace_back(proc);
   }
 
-  std::string mapperName = deconstructed.name + llvm::omp::OmpDefaultMapperName;
+  std::string mapperName = deconstructed.name;
+  appendKinds(mapperName, deconstructed.kinds);
+  mapperName.append(llvm::omp::OmpDefaultMapperName);
   return fir::NameUniquer::doGenerated(
       modules, procs, deconstructed.blockId, mapperName);
 }
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
new file mode 100644
index 0000000000000..7deea93f07930
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
@@ -0,0 +1,35 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! Check that implicit default mapper generation does not alias parameterized
+! derived type instantiations with different kind parameters.
+! Before the fix both pdt(4) and pdt(8) nested mappings could bind to the same
+! mapper symbol due to kind-less name canonicalization.
+
+module m
+  type :: pdt(k)
+    integer, kind :: k
+    real(k) :: x
+  end type
+
+  type :: holder4
+    type(pdt(4)), allocatable :: a(:)
+  end type
+
+  type :: holder8
+    type(pdt(8)), allocatable :: a(:)
+  end type
+contains
+  subroutine s(h4, h8)
+    type(holder4) :: h4
+    type(holder8) :: h8
+    !$omp target data map(h4, h8)
+    !$omp end target data
+  end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @_QQMmholder4_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @_QQMmholder8_omp_default_mapper
+! CHECK-DAG: mapper(@_QQMmpdtK4_omp_default_mapper)
+! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)

>From f9914d7dc364bafa5f22bf91b9a2b9fca1c3ea13 Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Mon, 27 Jul 2026 13:09:15 -0500
Subject: [PATCH 3/7] Update code format

---
 flang/lib/Utils/OpenMP.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 4023c8bd21542..9c64dd52ce84e 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -20,8 +20,7 @@
 
 namespace Fortran::utils::openmp {
 std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
-  auto appendKinds = [](std::string &name,
-                        llvm::ArrayRef<std::int64_t> kinds) {
+  auto appendKinds = [](std::string &name, llvm::ArrayRef<std::int64_t> kinds) {
     for (std::int64_t kind : kinds) {
       name.append("K");
       if (kind < 0) {

>From 2008807d25dee6665656a832ceeaca395015d3d8 Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Wed, 29 Jul 2026 18:31:39 -0500
Subject: [PATCH 4/7] [flang][OpenMP] Reuse explicit default mappers for PDT
 nested mapping

---
 flang/lib/Utils/OpenMP.cpp                    | 33 +++++++++++++++
 ...er-implicit-default-pdt-explicit-reuse.f90 | 41 +++++++++++++++++++
 2 files changed, 74 insertions(+)
 create mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90

diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 9c64dd52ce84e..0d01af8b96aaf 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -209,6 +209,29 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
     fir::FirOpBuilder &firOpBuilder, mlir::Location loc,
     fir::RecordType recordType, llvm::StringRef mapperNameStr,
     RecordMemberMapperMangler mangler) {
+  auto getKindlessDefaultMapperName =
+      [](fir::RecordType recType) -> std::string {
+    auto [nameKind, deconstructed] =
+        fir::NameUniquer::deconstruct(recType.getName());
+    if (nameKind != fir::NameUniquer::NameKind::DERIVED_TYPE ||
+        deconstructed.kinds.empty())
+      return {};
+
+    llvm::SmallVector<llvm::StringRef> modules;
+    llvm::SmallVector<llvm::StringRef> procs;
+    modules.reserve(deconstructed.modules.size());
+    procs.reserve(deconstructed.procs.size());
+    for (const std::string &module : deconstructed.modules)
+      modules.emplace_back(module);
+    for (const std::string &proc : deconstructed.procs)
+      procs.emplace_back(proc);
+
+    std::string mapperName =
+        deconstructed.name + llvm::omp::OmpDefaultMapperName;
+    return fir::NameUniquer::doGenerated(
+        modules, procs, deconstructed.blockId, mapperName);
+  };
+
   if (mapperNameStr.empty())
     return {};
 
@@ -217,6 +240,16 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
     return mlir::FlatSymbolRefAttr::get(
         firOpBuilder.getContext(), mapperNameStr);
 
+  if (std::string kindlessMapperName =
+          getKindlessDefaultMapperName(recordType);
+      !kindlessMapperName.empty() && kindlessMapperName != mapperNameStr) {
+    if (auto explicitMapper = moduleOp.lookupSymbol<mlir::omp::DeclareMapperOp>(
+            kindlessMapperName);
+        explicitMapper && explicitMapper.getType() == recordType)
+      return mlir::FlatSymbolRefAttr::get(
+          firOpBuilder.getContext(), kindlessMapperName);
+  }
+
   mlir::OpBuilder::InsertionGuard guard(firOpBuilder);
 
   firOpBuilder.setInsertionPointToStart(moduleOp.getBody());
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
new file mode 100644
index 0000000000000..fe4395254a61f
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
@@ -0,0 +1,41 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! Check that nested implicit default mapper generation for PDT components reuses
+! an explicit default declare mapper(default:) when available for that exact
+! instantiated type.
+
+module m
+  type :: pdt(k)
+    integer, kind :: k
+    real(k) :: x
+  end type
+
+  !$omp declare mapper(default: pdt(4) :: v) map(tofrom: v%x)
+
+  type :: holder4
+    type(pdt(4)), allocatable :: a(:)
+  end type
+
+  type :: holder8
+    type(pdt(8)), allocatable :: a(:)
+  end type
+contains
+  subroutine s(h4, h8)
+    type(holder4) :: h4
+    type(holder8) :: h8
+    !$omp target data map(h4, h8)
+    !$omp end target data
+  end subroutine
+end module
+
+! Explicit mapper for pdt(4) keeps the historical kindless symbol spelling.
+! CHECK-DAG: omp.declare_mapper @_QQMmpdt_omp_default_mapper : !fir.type<_QMmTpdtK4
+
+! Implicit mapper for pdt(8) remains distinct and kind-qualified.
+! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper : !fir.type<_QMmTpdtK8
+
+! holder4 nested mapping must reuse the explicit pdt(4) mapper, not synthesize
+! a pdtK4 implicit default mapper.
+! CHECK-DAG: mapper(@_QQMmpdt_omp_default_mapper)
+! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)
+! CHECK-NOT: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper

>From 59322202d521f6acf007b4d23c00ec022491b1bf Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Thu, 30 Jul 2026 10:30:23 -0500
Subject: [PATCH 5/7] Update code format; Consolidate the three test files into
 one.

---
 flang/lib/Utils/OpenMP.cpp                    |  3 +-
 ...mapper-explicit-default-nested-pointer.f90 | 46 ----------
 ...are-mapper-implicit-default-nested-pdt.f90 | 86 +++++++++++++++++++
 ...er-implicit-default-pdt-explicit-reuse.f90 | 41 ---------
 ...lare-mapper-implicit-default-pdt-kinds.f90 | 35 --------
 5 files changed, 87 insertions(+), 124 deletions(-)
 delete mode 100644 flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
 create mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
 delete mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
 delete mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90

diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 0d01af8b96aaf..0d7954f2e4838 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -240,8 +240,7 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
     return mlir::FlatSymbolRefAttr::get(
         firOpBuilder.getContext(), mapperNameStr);
 
-  if (std::string kindlessMapperName =
-          getKindlessDefaultMapperName(recordType);
+  if (std::string kindlessMapperName = getKindlessDefaultMapperName(recordType);
       !kindlessMapperName.empty() && kindlessMapperName != mapperNameStr) {
     if (auto explicitMapper = moduleOp.lookupSymbol<mlir::omp::DeclareMapperOp>(
             kindlessMapperName);
diff --git a/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90 b/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
deleted file mode 100644
index 9c41cbb0a00b2..0000000000000
--- a/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
+++ /dev/null
@@ -1,46 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
-!
-! Test that when an explicit default DECLARE MAPPER is defined for a type (newdata)
-! whose only component is a pointer, and that type is used as an allocatable component
-! of another type (newvec), the compiler-generated implicit mapper for newvec correctly
-! references the user-defined mapper for newdata rather than synthesising a new
-! implicit one that would silently skip the pointer component.
-!
-! An explicit `map(s)` on a newvec variable is the code-path that triggers implicit
-! mapper generation for newvec (unlike an implicit target capture, which suppresses
-! mapper generation for plain non-allocatable/non-pointer derived types).
-
-module m
-  type :: newdata
-    real(8), pointer :: value
-  end type
-  !$omp declare mapper(default: newdata :: v) map(tofrom: v%value)
-
-  type :: newvec
-    integer :: len
-    type(newdata), allocatable :: data(:)
-  end type
-end module
-
-program main
-  use m
-  implicit none
-  type(newvec) :: s
-
-  ! Explicit map(s) triggers implicit mapper generation for newvec.
-  !$omp target data map(s)
-    s%len = 0
-  !$omp end target data
-end program
-
-! The user-defined default mapper for newdata must have tofrom map for v%value.
-! CHECK-DAG: omp.declare_mapper @_QQMmnewdata_omp_default_mapper
-! CHECK-DAG: map_clauses(tofrom)
-! CHECK-DAG: {name = "v%value"}
-
-! The implicit default mapper for newvec must reference the user-defined newdata
-! mapper by its canonical name.  Before the fix this referenced a separately-
-! synthesised bogus mapper (@_QMmTnewdata_omp_default_mapper) that had no maps
-! for pointer components, causing a null-address device fault at runtime.
-! CHECK-DAG: omp.declare_mapper @_QQMmnewvec_omp_default_mapper
-! CHECK-DAG: mapper(@_QQMmnewdata_omp_default_mapper)
\ No newline at end of file
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
new file mode 100644
index 0000000000000..84e98523cd7b9
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
@@ -0,0 +1,86 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! This file groups related OpenMP mapper-name regressions:
+! 1) nested default mapper reuse for pointer components
+! 2) distinct implicit mapper names for PDT kind instantiations
+! 3) nested PDT reuse of an explicit declare mapper(default:)
+
+module ptr_case
+  type :: newdata
+    real(8), pointer :: value
+  end type
+  !$omp declare mapper(default: newdata :: v) map(tofrom: v%value)
+
+  type :: newvec
+    integer :: len
+    type(newdata), allocatable :: data(:)
+  end type
+contains
+  subroutine trigger
+    type(newvec) :: s
+    !$omp target data map(s)
+      s%len = 0
+    !$omp end target data
+  end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}newdata_omp_default_mapper
+! CHECK-DAG: map_clauses(tofrom)
+! CHECK-DAG: {name = "v%value"}
+! CHECK-DAG: omp.declare_mapper @{{.*}}newvec_omp_default_mapper
+! CHECK-DAG: mapper(@{{.*}}newdata_omp_default_mapper)
+
+module kinds_case
+  type :: pdt(k)
+    integer, kind :: k
+    real(k) :: x
+  end type
+
+  type :: holder4_kinds
+    type(pdt(4)), allocatable :: a(:)
+  end type
+
+  type :: holder8_kinds
+    type(pdt(8)), allocatable :: a(:)
+  end type
+contains
+  subroutine trigger
+    type(holder4_kinds) :: h4
+    type(holder8_kinds) :: h8
+    !$omp target data map(h4, h8)
+    !$omp end target data
+  end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK4_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK8_omp_default_mapper
+! CHECK-DAG: mapper(@{{.*}}pdtK4_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
+
+module reuse_case
+  type :: pdt(k)
+    integer, kind :: k
+    real(k) :: x
+  end type
+
+  !$omp declare mapper(default: pdt(4) :: v) map(tofrom: v%x)
+
+  type :: holder4_reuse
+    type(pdt(4)), allocatable :: a(:)
+  end type
+
+  type :: holder8_reuse
+    type(pdt(8)), allocatable :: a(:)
+  end type
+contains
+  subroutine trigger
+    type(holder4_reuse) :: h4
+    type(holder8_reuse) :: h8
+    !$omp target data map(h4, h8)
+    !$omp end target data
+  end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}pdt_omp_default_mapper : !fir.type<{{.*}}TpdtK4
+! CHECK-DAG: mapper(@{{.*}}pdt_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
deleted file mode 100644
index fe4395254a61f..0000000000000
--- a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
+++ /dev/null
@@ -1,41 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
-!
-! Check that nested implicit default mapper generation for PDT components reuses
-! an explicit default declare mapper(default:) when available for that exact
-! instantiated type.
-
-module m
-  type :: pdt(k)
-    integer, kind :: k
-    real(k) :: x
-  end type
-
-  !$omp declare mapper(default: pdt(4) :: v) map(tofrom: v%x)
-
-  type :: holder4
-    type(pdt(4)), allocatable :: a(:)
-  end type
-
-  type :: holder8
-    type(pdt(8)), allocatable :: a(:)
-  end type
-contains
-  subroutine s(h4, h8)
-    type(holder4) :: h4
-    type(holder8) :: h8
-    !$omp target data map(h4, h8)
-    !$omp end target data
-  end subroutine
-end module
-
-! Explicit mapper for pdt(4) keeps the historical kindless symbol spelling.
-! CHECK-DAG: omp.declare_mapper @_QQMmpdt_omp_default_mapper : !fir.type<_QMmTpdtK4
-
-! Implicit mapper for pdt(8) remains distinct and kind-qualified.
-! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper : !fir.type<_QMmTpdtK8
-
-! holder4 nested mapping must reuse the explicit pdt(4) mapper, not synthesize
-! a pdtK4 implicit default mapper.
-! CHECK-DAG: mapper(@_QQMmpdt_omp_default_mapper)
-! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)
-! CHECK-NOT: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
deleted file mode 100644
index 7deea93f07930..0000000000000
--- a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
+++ /dev/null
@@ -1,35 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
-!
-! Check that implicit default mapper generation does not alias parameterized
-! derived type instantiations with different kind parameters.
-! Before the fix both pdt(4) and pdt(8) nested mappings could bind to the same
-! mapper symbol due to kind-less name canonicalization.
-
-module m
-  type :: pdt(k)
-    integer, kind :: k
-    real(k) :: x
-  end type
-
-  type :: holder4
-    type(pdt(4)), allocatable :: a(:)
-  end type
-
-  type :: holder8
-    type(pdt(8)), allocatable :: a(:)
-  end type
-contains
-  subroutine s(h4, h8)
-    type(holder4) :: h4
-    type(holder8) :: h8
-    !$omp target data map(h4, h8)
-    !$omp end target data
-  end subroutine
-end module
-
-! CHECK-DAG: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @_QQMmholder4_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @_QQMmholder8_omp_default_mapper
-! CHECK-DAG: mapper(@_QQMmpdtK4_omp_default_mapper)
-! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)

>From 5c335b2fcc5d79ad08cfa76e6607d8ea1fde1cba Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Wed, 12 Aug 2026 05:28:44 -0500
Subject: [PATCH 6/7] [flang][OpenMP] I210402: Fix direct PDT default-mapper
 naming and add regression

Fix direct PDT default mapper ID construction to be kind-aware in OpenMP
lowering paths so direct mappings of pdt(4)/pdt(8) do not alias to the same
mapper symbol.

Also extend the consolidated OpenMP mapper regression to cover the direct-PDT
case and tighten checks to avoid cross-matching in a grouped test file.
---
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 12 +++++++--
 flang/lib/Lower/OpenMP/Utils.cpp              | 11 ++++++--
 ...are-mapper-implicit-default-nested-pdt.f90 | 27 +++++++++++++++----
 3 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 9807023935784..ebde2e8b4f299 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -3989,8 +3989,16 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
         const semantics::DerivedTypeSpec *typeSpec =
             sym.GetType() ? sym.GetType()->AsDerived() : nullptr;
         if (typeSpec) {
-          std::string mapperIdName =
-              typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+          std::string mapperIdName;
+          if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
+                  converter.genType(*typeSpec))) {
+            mapperIdName =
+                Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+                    recordType);
+          } else {
+            mapperIdName =
+                typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+          }
           if (auto *mapperSym =
                   converter.getCurrentScope().FindSymbol(mapperIdName))
             mapperIdName = converter.mangleName(
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 8f57f00d59c58..15926ff26c1fd 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -1094,8 +1094,15 @@ getDefaultMapperID(Fortran::lower::AbstractConverter &converter,
       !typeSpec)
     return {};
 
-  std::string mapperIdName =
-      typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+  std::string mapperIdName;
+  if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
+          converter.genType(*typeSpec))) {
+    mapperIdName = Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+        recordType);
+  } else {
+    mapperIdName =
+        typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+  }
   if (auto *sym = converter.getCurrentScope().FindSymbol(mapperIdName)) {
     mapperIdName =
         converter.mangleName(mapperIdName, sym->GetUltimate().owner());
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
index 84e98523cd7b9..2be4e8a1fe12e 100644
--- a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
@@ -52,10 +52,8 @@ subroutine trigger
   end subroutine
 end module
 
-! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK4_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK8_omp_default_mapper
-! CHECK-DAG: mapper(@{{.*}}pdtK4_omp_default_mapper)
-! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
+! CHECK-DAG: omp.declare_mapper @{{.*}}kinds_casepdtK4_omp_default_mapper : !fir.type<{{.*}}TpdtK4
+! CHECK-DAG: omp.declare_mapper @{{.*}}kinds_casepdtK8_omp_default_mapper : !fir.type<{{.*}}TpdtK8
 
 module reuse_case
   type :: pdt(k)
@@ -83,4 +81,23 @@ subroutine trigger
 
 ! CHECK-DAG: omp.declare_mapper @{{.*}}pdt_omp_default_mapper : !fir.type<{{.*}}TpdtK4
 ! CHECK-DAG: mapper(@{{.*}}pdt_omp_default_mapper)
-! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}reuse_casepdtK8_omp_default_mapper)
+
+module direct_pdt_case
+  type :: direct_pdt(k)
+    integer, kind :: k
+    real(k), allocatable :: a(:)
+  end type
+contains
+  subroutine trigger
+    type(direct_pdt(4)) :: h4
+    type(direct_pdt(8)) :: h8
+    !$omp target data map(h4, h8)
+    !$omp end target data
+  end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}direct_pdtK4_omp_default_mapper : !fir.type<{{.*}}Tdirect_pdtK4
+! CHECK-DAG: omp.declare_mapper @{{.*}}direct_pdtK8_omp_default_mapper : !fir.type<{{.*}}Tdirect_pdtK8
+! CHECK-DAG: mapper(@{{.*}}direct_pdtK4_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}direct_pdtK8_omp_default_mapper)

>From fe74b56c492c1dd11833f230f1e23c424d433f19 Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Fri, 14 Aug 2026 06:41:25 -0500
Subject: [PATCH 7/7] [flang][OpenMP] Use canonical mapper names for
 parameterized types

Use kind-aware mapper names for parameterized derived types while preserving legacy names for ISO C types such as c_ptr. This prevents mapper collisions between PDT instances without changing existing built-in mapper symbols.

Update both OpenMP lowering paths and the shared mapper-name helper.

Isue #210402 and PR #212251.
---
 flang/lib/Lower/OpenMP/OpenMP.cpp | 14 +++++++-------
 flang/lib/Lower/OpenMP/Utils.cpp  | 16 ++++++++--------
 flang/lib/Utils/OpenMP.cpp        |  6 ++++++
 3 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index ebde2e8b4f299..5f626307f0c06 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -3989,15 +3989,15 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
         const semantics::DerivedTypeSpec *typeSpec =
             sym.GetType() ? sym.GetType()->AsDerived() : nullptr;
         if (typeSpec) {
-          std::string mapperIdName;
+          std::string mapperIdName =
+            typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+            if (!semantics::IsIsoCType(typeSpec) &&
+              !typeSpec->parameters().empty()) {
           if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
-                  converter.genType(*typeSpec))) {
+              converter.genType(*typeSpec)))
             mapperIdName =
-                Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
-                    recordType);
-          } else {
-            mapperIdName =
-                typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+              Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+                recordType);
           }
           if (auto *mapperSym =
                   converter.getCurrentScope().FindSymbol(mapperIdName))
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 15926ff26c1fd..dbe94b1a22ad3 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -1094,14 +1094,14 @@ getDefaultMapperID(Fortran::lower::AbstractConverter &converter,
       !typeSpec)
     return {};
 
-  std::string mapperIdName;
-  if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
-          converter.genType(*typeSpec))) {
-    mapperIdName = Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
-        recordType);
-  } else {
-    mapperIdName =
-        typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+  std::string mapperIdName =
+      typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+  if (!semantics::IsIsoCType(typeSpec) && !typeSpec->parameters().empty()) {
+    if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
+            converter.genType(*typeSpec)))
+      mapperIdName =
+          Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+              recordType);
   }
   if (auto *sym = converter.getCurrentScope().FindSymbol(mapperIdName)) {
     mapperIdName =
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 0d7954f2e4838..745b54005fc0b 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -36,6 +36,12 @@ std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
   if (kind != fir::NameUniquer::NameKind::DERIVED_TYPE)
     return recordType.getName().str() + llvm::omp::OmpDefaultMapperName;
 
+  // Preserve legacy symbol spelling for non-parameterized types.
+  // Rebuilding through doGenerated() can duplicate module prefixes for
+  // intrinsic-derived names like __fortran_builtins::c_ptr.
+  if (deconstructed.kinds.empty())
+    return recordType.getName().str() + llvm::omp::OmpDefaultMapperName;
+
   llvm::SmallVector<llvm::StringRef> modules;
   llvm::SmallVector<llvm::StringRef> procs;
   modules.reserve(deconstructed.modules.size());



More information about the flang-commits mailing list