https://github.com/agozillon updated 
https://github.com/llvm/llvm-project/pull/228748

>From 83586e75ff7e6394331cce76e548011bd8d2bb55 Mon Sep 17 00:00:00 2001
From: agozillon <[email protected]>
Date: Fri, 2 Oct 2026 06:45:12 -0500
Subject: [PATCH 1/3] [Flang][OpenMP] Flag for switching off implicit
 allocatable member mapping via default declare mapper

Part of the OpenMP specification requires implicitly mappiing allocatable 
members in derived types.
However, it is quite an expensive overhead to perform implicit allocatable 
member mapping as it
requires a mapper to do so due to the nature of possibly nested allocatable 
derived types etc.
Alongside a fairly comprehensive map of the record, this in particular comes at 
a fairly substantial
cost for arrays of derived types that trigger this behaviour. Some of this may 
or may not be
mitigatable over time.

But for the moment this PR seeks to follow the example of other Fortran OpenMP 
compilers (Cray
in particular I think) and utilise a flag that can switch this behaviour on and 
off, so that
applications not depending on the crutch of this implicit mapping can deactivte 
it and not pay
the overhead, and those that like the compiler to do this for them can continue 
to do so.
---
 clang/include/clang/Options/FlangOptions.td   |  6 ++
 clang/lib/Driver/ToolChains/Flang.cpp         | 10 +++
 .../include/flang/Frontend/CodeGenOptions.def |  1 +
 flang/include/flang/Support/Flags.h           |  1 +
 flang/lib/Frontend/CompilerInvocation.cpp     |  5 ++
 flang/lib/Frontend/FrontendActions.cpp        |  6 ++
 flang/lib/Lower/OpenMP/OpenMP.cpp             |  4 +-
 flang/lib/Lower/OpenMP/Utils.cpp              | 13 ++-
 flang/lib/Lower/OpenMP/Utils.h                |  3 +-
 flang/lib/Support/Flags.cpp                   |  6 ++
 flang/test/Driver/omp-driver-offload.f90      | 41 ++++++++++
 ...efault-mapper-allocatable-members-flag.f90 | 81 +++++++++++++++++++
 12 files changed, 172 insertions(+), 5 deletions(-)
 create mode 100644 
flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90

diff --git a/clang/include/clang/Options/FlangOptions.td 
b/clang/include/clang/Options/FlangOptions.td
index b07a6bdd1e606a..ad39d052bee6af 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -317,6 +317,12 @@ def fdo_concurrent_to_openmp_EQ : Joined<["-"], 
"fdo-concurrent-to-openmp=">,
   HelpText<"Try to map `do concurrent` loops to OpenMP [none|host|device]">,
       Values<"none, host, device">;
 
+def fimplicit_default_mapper_allocatable_members : Flag<["-"], 
"fimplicit-default-mapper-allocatable-members">,
+  Group<f_Group>, HelpText<"Enable implicit allocatable member maps in 
compiler-generated OpenMP default mappers">;
+def fno_implicit_default_mapper_allocatable_members : Flag<["-"], 
"fno-implicit-default-mapper-allocatable-members">,
+  Group<f_Group>, HelpText<"Disable implicit allocatable member maps in 
compiler-generated OpenMP default mappers">;
+
+
 def J : JoinedOrSeparate<["-"], "J">,
   Flags<[RenderJoined]>, Group<gfortran_Group>, Alias<module_dir>;
 
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp 
b/clang/lib/Driver/ToolChains/Flang.cpp
index 94b092e711be64..08ac0e8fd8e190 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -880,6 +880,16 @@ void Flang::addOffloadOptions(Compilation &C, const 
InputInfoList &Inputs,
                    /*Default=*/false))
     CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
 
+  // This forwards the option to switch off/on mapper generation for scenarios
+  // where the compiler considers it neccessary to generate a mapper to cover
+  // implicit allocatable member mapping inside of derived types to adhere to
+  // specification compliance.
+  if (!Args.hasFlag(
+          options::OPT_fimplicit_default_mapper_allocatable_members,
+          options::OPT_fno_implicit_default_mapper_allocatable_members,
+          /*Default=*/true))
+    CmdArgs.push_back("-fno-implicit-default-mapper-allocatable-members");
+
   if (IsOpenMPDevice) {
     // -fopenmp-is-target-device is passed along to tell the frontend that it 
is
     // generating code for a device, so that only the relevant code is emitted.
diff --git a/flang/include/flang/Frontend/CodeGenOptions.def 
b/flang/include/flang/Frontend/CodeGenOptions.def
index 569a6aa289ca31..bae78887f4ce09 100644
--- a/flang/include/flang/Frontend/CodeGenOptions.def
+++ b/flang/include/flang/Frontend/CodeGenOptions.def
@@ -63,6 +63,7 @@ CODEGENOPT(DwarfVersion, 3, 0) ///< Dwarf version
 CODEGENOPT(DebugInfoForProfiling, 1, 0)  ///< Emit extra debug info to make 
sample profile more accurate.
 CODEGENOPT(PseudoProbeForProfiling, 1, 0) ///< Emit pseudo probes for sample 
profiling.
 CODEGENOPT(UniqueInternalLinkageNames, 1, 0) ///< Append MD5 hash to internal 
linkage symbols.
+CODEGENOPT(ImplicitDefaultMapperAllocatableMembers, 1, 1) ///< Map allocatable 
members in generated OpenMP default mappers.
 
 CODEGENOPT(Underscoring, 1, 1)
 ENUM_CODEGENOPT(FPMaxminBehavior, Fortran::common::FPMaxminBehavior, 2, 
Fortran::common::FPMaxminBehavior::Legacy)
diff --git a/flang/include/flang/Support/Flags.h 
b/flang/include/flang/Support/Flags.h
index bcbb72f8e50d05..1dbfa249b87bd0 100644
--- a/flang/include/flang/Support/Flags.h
+++ b/flang/include/flang/Support/Flags.h
@@ -13,5 +13,6 @@
 
 extern llvm::cl::opt<bool> enableDelayedPrivatization;
 extern llvm::cl::opt<bool> enableDelayedPrivatizationStaging;
+extern llvm::cl::opt<bool> enableImplicitDefaultMapperAllocatableMembers;
 
 #endif // FORTRAN_SUPPORT_FLAGS_H_
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp 
b/flang/lib/Frontend/CompilerInvocation.cpp
index 107fdd37dbd3e9..4372ccaa0fb5ab 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -567,6 +567,11 @@ static void 
parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
     opts.Underscoring = 0;
   }
 
+  opts.ImplicitDefaultMapperAllocatableMembers = args.hasFlag(
+      clang::options::OPT_fimplicit_default_mapper_allocatable_members,
+      clang::options::OPT_fno_implicit_default_mapper_allocatable_members,
+      /*Default=*/true);
+
   if (const llvm::opt::Arg *arg =
           args.getLastArg(clang::options::OPT_complex_range_EQ)) {
     llvm::StringRef argValue = llvm::StringRef(arg->getValue());
diff --git a/flang/lib/Frontend/FrontendActions.cpp 
b/flang/lib/Frontend/FrontendActions.cpp
index 823b437d6e83fc..65cdc0efc2df55 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -27,6 +27,7 @@
 #include "flang/Optimizer/Transforms/Passes.h"
 #include "flang/Semantics/runtime-type-info.h"
 #include "flang/Semantics/unparse-with-symbols.h"
+#include "flang/Support/Flags.h"
 #include "flang/Support/default-kinds.h"
 #include "flang/Tools/CrossToolHelpers.h"
 
@@ -255,6 +256,11 @@ bool CodeGenAction::beginSourceFileAction() {
   if (!res)
     return res;
 
+  enableImplicitDefaultMapperAllocatableMembers.setValue(
+      ci.getInvocation()
+          .getCodeGenOpts()
+          .ImplicitDefaultMapperAllocatableMembers);
+
   timingScopeParse.stop();
   mlir::TimingScope timingScopeMLIRGen = timingScopeRoot.nest(
       mlir::TimingIdentifier::get(timingIdMLIRGen, timingMgr));
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp 
b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 3ce793989dee30..a150f921610dc4 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -4249,7 +4249,9 @@ genTargetOp(lower::AbstractConverter &converter, 
lower::SymMap &symTable,
             // where the record type contains an allocatable.
             if (!isPointer &&
                 (hasDefaultMapper ||
-                 (requiresImplicitDefaultDeclareMapper(*typeSpec)))) {
+                 (requiresImplicitDefaultDeclareMapper(
+                     *typeSpec,
+                     enableImplicitDefaultMapperAllocatableMembers)))) {
               if (!hasDefaultMapper) {
                 if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
                         converter.genType(*typeSpec)))
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 87016d2022e536..f4fc67ddfcaa7e 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -37,6 +37,7 @@
 #include <flang/Semantics/symbol.h>
 #include <flang/Semantics/tools.h>
 #include <flang/Semantics/type.h>
+#include <flang/Support/Flags.h>
 #include <flang/Utils/OpenMP.h>
 #include <llvm/ADT/STLExtras.h>
 #include <llvm/ADT/SmallPtrSet.h>
@@ -76,7 +77,13 @@ namespace Fortran {
 namespace lower {
 namespace omp {
 bool requiresImplicitDefaultDeclareMapper(
-    const semantics::DerivedTypeSpec &typeSpec) {
+    const semantics::DerivedTypeSpec &typeSpec,
+    bool enableImplicitDefaultMapperAllocatableMembers) {
+  // If disabled via -fno-implicit-default-mapper-allocatable-members
+  // return false, as we do not need to emit allocatable member maps.
+  if (!enableImplicitDefaultMapperAllocatableMembers)
+    return false;
+
   llvm::SmallPtrSet<const semantics::DerivedTypeSpec *, 8> visited;
 
   std::function<bool(const semantics::DerivedTypeSpec &)> requiresMapper =
@@ -1278,8 +1285,8 @@ mlir::FlatSymbolRefAttr resolveMapperId(
       bool isImplicitMap =
           (mapTypeBits & mlir::omp::ClauseMapFlags::implicit) ==
           mlir::omp::ClauseMapFlags::implicit;
-      bool needsDefaultMapper =
-          requiresImplicitDefaultDeclareMapper(*objectTypeSpec);
+      bool needsDefaultMapper = requiresImplicitDefaultDeclareMapper(
+          *objectTypeSpec, enableImplicitDefaultMapperAllocatableMembers);
       // For implicit captures, avoid synthesizing default mappers for
       // pointer entities (which can over-map pointer payloads) and for
       // plain non-allocatable/non-pointer entities. Keep implicit mapper
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 16775f8facbc53..475769bebc3388 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -146,7 +146,8 @@ mlir::Value createParentSymAndGenIntermediateMaps(
     mlir::omp::ClauseMapFlags mapTypeBits);
 
 bool requiresImplicitDefaultDeclareMapper(
-    const semantics::DerivedTypeSpec &typeSpec);
+    const semantics::DerivedTypeSpec &typeSpec,
+    bool enableImplicitDefaultMapperAllocatableMembers);
 
 omp::ObjectList gatherObjectsOf(omp::Object derivedTypeMember,
                                 semantics::SemanticsContext &semaCtx);
diff --git a/flang/lib/Support/Flags.cpp b/flang/lib/Support/Flags.cpp
index 250232448ee94e..ea5428590e5d91 100644
--- a/flang/lib/Support/Flags.cpp
+++ b/flang/lib/Support/Flags.cpp
@@ -18,3 +18,9 @@ llvm::cl::opt<bool> enableDelayedPrivatizationStaging(
     llvm::cl::desc("For partially supported constructs, emit private/local "
                    "variables as clauses/specifiers on MLIR ops."),
     llvm::cl::init(false));
+
+llvm::cl::opt<bool> enableImplicitDefaultMapperAllocatableMembers(
+    "enable-implicit-default-mapper-allocatable-members",
+    llvm::cl::desc("Emit implicit mappers for implicit allocatable member "
+                   "mapping in derived types for specification compliance"),
+    llvm::cl::init(true));
diff --git a/flang/test/Driver/omp-driver-offload.f90 
b/flang/test/Driver/omp-driver-offload.f90
index fccd0771d040cb..4d8c9148592ce7 100644
--- a/flang/test/Driver/omp-driver-offload.f90
+++ b/flang/test/Driver/omp-driver-offload.f90
@@ -230,3 +230,44 @@
 ! OFFLOAD-TARGETS-NOT: --offload-targets
 ! OFFLOAD-TARGETS: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"x86_64-unknown-linux-gnu"
 ! OFFLOAD-TARGETS-SAME: "--offload-targets=amdgpu-amd-amdhsa"
+
+! Verify the implicit default mapper allocatable members flags are applied to 
both host
+! and device phases of the offload compilation when the negative flag is used 
and ignored
+! in the positive case as it is the default.
+
+! RUN: %flang -S -### %s -o %t 2>&1 \
+! RUN: -fopenmp -fimplicit-default-mapper-allocatable-members 
--offload-arch=gfx90a \
+! RUN: --target=x86_64-unknown-linux-gnu -nogpulib \
+! RUN:   | FileCheck %s --check-prefix=ENABLE-IMP-MAPPER
+
+! ENABLE-IMP-MAPPER: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"x86_64-unknown-linux-gnu"
+! ENABLE-IMP-MAPPER-SAME: "-fopenmp"
+! ENABLE-IMP-MAPPER-SAME: "--offload-targets=amdgpu-amd-amdhsa"
+! ENABLE-IMP-MAPPER-NOT: implicit-default-mapper-allocatable-members
+! ENABLE-IMP-MAPPER-NEXT: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"amdgpu9.0a-amd-amdhsa"
+! ENABLE-IMP-MAPPER-SAME: "-fopenmp"
+! ENABLE-IMP-MAPPER-NOT: implicit-default-mapper-allocatable-members
+
+! RUN: %flang -S -### %s -o %t 2>&1 \
+! RUN: -fopenmp -fno-implicit-default-mapper-allocatable-members 
--offload-arch=gfx90a \
+! RUN: --target=x86_64-unknown-linux-gnu -nogpulib \
+! RUN:   | FileCheck %s --check-prefix=DISABLE-IMP-MAPPER
+
+! DISABLE-IMP-MAPPER: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"x86_64-unknown-linux-gnu"
+! DISABLE-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
+! DISABLE-IMP-MAPPER-NEXT: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"amdgpu9.0a-amd-amdhsa"
+! DISABLE-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
+
+! Verify when multiple flags passed the final flag wins out
+
+! RUN: %flang -S -### %s -o %t 2>&1 \
+! RUN: -fopenmp -fimplicit-default-mapper-allocatable-members \
+! RUN:  -fimplicit-default-mapper-allocatable-members \
+! RUN: --offload-arch=gfx90a -fno-implicit-default-mapper-allocatable-members \
+! RUN: --target=x86_64-unknown-linux-gnu -nogpulib \
+! RUN:   | FileCheck %s --check-prefix=MULTI-IMP-MAPPER
+
+! MULTI-IMP-MAPPER: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"x86_64-unknown-linux-gnu"
+! MULTI-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
+! MULTI-IMP-MAPPER-NEXT: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"amdgpu9.0a-amd-amdhsa"
+! MULTI-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
diff --git 
a/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90
new file mode 100644
index 00000000000000..2504dc86eb95d5
--- /dev/null
+++ 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90
@@ -0,0 +1,81 @@
+! RUN: rm -rf %t && split-file %s %t
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/implicit.f90 -o 
- | FileCheck %s --check-prefix=IMPLICIT-ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fimplicit-default-mapper-allocatable-members %t/implicit.f90 -o - | FileCheck 
%s --check-prefix=IMPLICIT-ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %t/implicit.f90 -o - | 
FileCheck %s --check-prefix=IMPLICIT-OFF
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/explicit.f90 -o 
- | FileCheck %s --check-prefix=EXPLICIT-ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fimplicit-default-mapper-allocatable-members %t/explicit.f90 -o - | FileCheck 
%s --check-prefix=EXPLICIT-ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %t/explicit.f90 -o - | 
FileCheck %s --check-prefix=EXPLICIT-OFF
+
+! Check the -f[no-]implicit-default-mapper-allocatable-members switch.
+!
+! With the default/on setting, compiler-generated implicit default mappers for
+! derived types include maps for allocatable and nested-record components.
+! With the off setting, those component maps are suppressed. Cover both:
+!   1. an implicit target-region capture; and
+!   2. an explicit whole-object map that would otherwise synthesize a default
+!      mapper for the derived type.
+
+!--- implicit.f90
+program implicit_capture
+  implicit none
+
+  type :: t
+    integer, allocatable :: a(:)
+  end type
+
+  type(t) :: x
+
+  allocate(x%a(1))
+
+  !$omp target
+    x%a(1) = 1
+  !$omp end target
+end program
+
+!--- explicit.f90
+program explicit_whole_object_map
+  implicit none
+
+  type :: t
+    integer :: scalar
+    integer, allocatable :: a(:)
+  end type
+
+  type(t) :: x
+
+  allocate(x%a(1))
+  x%scalar = 1
+
+  !$omp target map(tofrom: x)
+    x%scalar = x%scalar + 1
+    x%a(1) = x%a(1) + 1
+  !$omp end target
+end program
+
+! IMPLICIT-ON: omp.declare_mapper @[[IM_MAPPER:_QQFt_omp_default_mapper]]
+! IMPLICIT-ON: %[[COORD:.*]] = fir.coordinate_of %{{.*}}#0, a
+! IMPLICIT-ON: %[[PTEE:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(implicit, tofrom, ref_ptee)
+! IMPLICIT-ON: %[[ATTACH:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(attach, ref_ptee)
+! IMPLICIT-ON: %[[PARENT:.*]] = omp.map.info {{.*}}members(%[[PTEE]] : [0]
+! IMPLICIT-ON: omp.declare_mapper.info map_entries(%[[PARENT]], %[[PTEE]], 
%[[ATTACH]]
+! IMPLICIT-ON: omp.map.info {{.*}}map_clauses(implicit, tofrom) capture(ByRef) 
mapper(@[[IM_MAPPER]]) name("x")
+! IMPLICIT-ON: omp.target
+
+! IMPLICIT-OFF-NOT: omp.declare_mapper
+! IMPLICIT-OFF: %[[IM_MAP:.*]] = omp.map.info var_ptr(%{{.*}}) 
map_clauses(implicit, tofrom) capture(ByRef) name("x")
+! IMPLICIT-OFF-NOT: mapper(
+! IMPLICIT-OFF: omp.target {{.*}}map_entries(%[[IM_MAP]] ->
+
+! EXPLICIT-ON: omp.declare_mapper @[[EX_MAPPER:_QQFt_omp_default_mapper]]
+! EXPLICIT-ON: %[[COORD:.*]] = fir.coordinate_of %{{.*}}#0, a
+! EXPLICIT-ON: %[[PTEE:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(implicit, tofrom, ref_ptee)
+! EXPLICIT-ON: %[[ATTACH:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(attach, ref_ptee)
+! EXPLICIT-ON: %[[PARENT:.*]] = omp.map.info {{.*}}members(%[[PTEE]] : [1]
+! EXPLICIT-ON: omp.declare_mapper.info map_entries(%[[PARENT]], %[[PTEE]], 
%[[ATTACH]]
+! EXPLICIT-ON: omp.map.info {{.*}}map_clauses(tofrom) capture(ByRef) 
mapper(@[[EX_MAPPER]]) name("x")
+! EXPLICIT-ON: omp.target
+
+! EXPLICIT-OFF-NOT: omp.declare_mapper
+! EXPLICIT-OFF: %[[EX_MAP:.*]] = omp.map.info var_ptr(%{{.*}}) 
map_clauses(tofrom) capture(ByRef) name("x")
+! EXPLICIT-OFF-NOT: mapper(
+! EXPLICIT-OFF: omp.target {{.*}}map_entries(%[[EX_MAP]] ->

>From f3bf2bbb95d180d0b95513ee67db1c04cbd8c744 Mon Sep 17 00:00:00 2001
From: agozillon <[email protected]>
Date: Thu, 22 Oct 2026 13:14:02 -0500
Subject: [PATCH 2/3] [Flang][OpenMP] Address recent comments

---
 flang/test/Driver/omp-driver-offload.f90      | 45 +++++++----
 ...-allocatable-members-flag-explicit-map.f90 | 39 +++++++++
 ...ocatable-members-flag-implicit-capture.f90 | 40 +++++++++
 ...efault-mapper-allocatable-members-flag.f90 | 81 -------------------
 4 files changed, 107 insertions(+), 98 deletions(-)
 create mode 100644 
flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-explicit-map.f90
 create mode 100644 
flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-implicit-capture.f90
 delete mode 100644 
flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90

diff --git a/flang/test/Driver/omp-driver-offload.f90 
b/flang/test/Driver/omp-driver-offload.f90
index 4d8c9148592ce7..57668ec64f2696 100644
--- a/flang/test/Driver/omp-driver-offload.f90
+++ b/flang/test/Driver/omp-driver-offload.f90
@@ -235,39 +235,50 @@
 ! and device phases of the offload compilation when the negative flag is used 
and ignored
 ! in the positive case as it is the default.
 
-! RUN: %flang -S -### %s -o %t 2>&1 \
+! RUN: %flang -### %s 2>&1 \
 ! RUN: -fopenmp -fimplicit-default-mapper-allocatable-members 
--offload-arch=gfx90a \
 ! RUN: --target=x86_64-unknown-linux-gnu -nogpulib \
 ! RUN:   | FileCheck %s --check-prefix=ENABLE-IMP-MAPPER
 
-! ENABLE-IMP-MAPPER: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"x86_64-unknown-linux-gnu"
+! ENABLE-IMP-MAPPER: "-fc1" "-triple" "x86_64-unknown-linux-gnu"
 ! ENABLE-IMP-MAPPER-SAME: "-fopenmp"
 ! ENABLE-IMP-MAPPER-SAME: "--offload-targets=amdgpu-amd-amdhsa"
 ! ENABLE-IMP-MAPPER-NOT: implicit-default-mapper-allocatable-members
-! ENABLE-IMP-MAPPER-NEXT: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"amdgpu9.0a-amd-amdhsa"
+! ENABLE-IMP-MAPPER-NEXT: "-fc1" "-triple" "amdgpu9.0a-amd-amdhsa"
 ! ENABLE-IMP-MAPPER-SAME: "-fopenmp"
 ! ENABLE-IMP-MAPPER-NOT: implicit-default-mapper-allocatable-members
 
-! RUN: %flang -S -### %s -o %t 2>&1 \
+! RUN: %flang -### %s 2>&1 \
 ! RUN: -fopenmp -fno-implicit-default-mapper-allocatable-members 
--offload-arch=gfx90a \
 ! RUN: --target=x86_64-unknown-linux-gnu -nogpulib \
 ! RUN:   | FileCheck %s --check-prefix=DISABLE-IMP-MAPPER
 
-! DISABLE-IMP-MAPPER: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"x86_64-unknown-linux-gnu"
+! Verify when multiple flags passed the final flag wins out
+
+! RUN: %flang -### %s 2>&1 \
+! RUN: -fopenmp --offload-arch=gfx90a \
+! RUN: -fimplicit-default-mapper-allocatable-members \
+! RUN: -fimplicit-default-mapper-allocatable-members \
+! RUN: -fno-implicit-default-mapper-allocatable-members \
+! RUN: --target=x86_64-unknown-linux-gnu -nogpulib \
+! RUN:   | FileCheck %s --check-prefix=DISABLE-IMP-MAPPER
+
+! DISABLE-IMP-MAPPER: "-fc1" "-triple" "x86_64-unknown-linux-gnu"
 ! DISABLE-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
-! DISABLE-IMP-MAPPER-NEXT: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"amdgpu9.0a-amd-amdhsa"
+! DISABLE-IMP-MAPPER-NEXT: "-fc1" "-triple" "amdgpu9.0a-amd-amdhsa"
 ! DISABLE-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
 
-! Verify when multiple flags passed the final flag wins out
+! Verify when no implicit-default-mapper flags passed we do not inadvertently 
add the flag
 
-! RUN: %flang -S -### %s -o %t 2>&1 \
-! RUN: -fopenmp -fimplicit-default-mapper-allocatable-members \
-! RUN:  -fimplicit-default-mapper-allocatable-members \
-! RUN: --offload-arch=gfx90a -fno-implicit-default-mapper-allocatable-members \
+! RUN: %flang -### %s 2>&1 \
+! RUN: -fopenmp --offload-arch=gfx90a \
 ! RUN: --target=x86_64-unknown-linux-gnu -nogpulib \
-! RUN:   | FileCheck %s --check-prefix=MULTI-IMP-MAPPER
-
-! MULTI-IMP-MAPPER: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"x86_64-unknown-linux-gnu"
-! MULTI-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
-! MULTI-IMP-MAPPER-NEXT: "{{[^"]*}}flang{{[^"]*}}" "-fc1" "-triple" 
"amdgpu9.0a-amd-amdhsa"
-! MULTI-IMP-MAPPER-SAME: "-fopenmp" {{.*}} 
"-fno-implicit-default-mapper-allocatable-members"
+! RUN:   | FileCheck %s --check-prefix=NO-IMP-MAPPER
+
+! NO-IMP-MAPPER: "-fc1" "-triple" "x86_64-unknown-linux-gnu"
+! NO-IMP-MAPPER-SAME: "-fopenmp"
+! NO-IMP-MAPPER-SAME: "--offload-targets=amdgpu-amd-amdhsa"
+! NO-IMP-MAPPER-NOT: "-fno-implicit-default-mapper-allocatable-members"
+! NO-IMP-MAPPER-NEXT: "-fc1" "-triple" "amdgpu9.0a-amd-amdhsa"
+! NO-IMP-MAPPER-SAME: "-fopenmp"
+! NO-IMP-MAPPER-NOT: "-fno-implicit-default-mapper-allocatable-members"
diff --git 
a/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-explicit-map.f90
 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-explicit-map.f90
new file mode 100644
index 00000000000000..ad95fcfb05aa1d
--- /dev/null
+++ 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-explicit-map.f90
@@ -0,0 +1,39 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck 
%s --check-prefix=ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fimplicit-default-mapper-allocatable-members %s -o - | FileCheck %s 
--check-prefix=ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %s -o - | FileCheck %s 
--check-prefix=OFF
+
+! Check the -f[no-]implicit-default-mapper-allocatable-members switch for
+! explicit maps that synthesize an implicit default mapper for a derived
+! type containing an allocatable.
+!
+! With the default/on setting, compiler-generated implicit default mappers for
+! derived types include maps for allocatable components. With the off setting,
+! those component maps are suppressed.
+
+program explicit_map
+  implicit none
+
+  type :: t
+    integer :: scalar
+    integer, allocatable :: a(:)
+  end type
+
+  type(t) :: x
+
+  !$omp target map(tofrom: x)
+  !$omp end target
+end program
+
+! ON: omp.declare_mapper @[[MAPPER:_QQFt_omp_default_mapper]]
+! ON: %[[COORD:.*]] = fir.coordinate_of %{{.*}}#0, a
+! ON: %[[PTEE:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(implicit, tofrom, ref_ptee)
+! ON: %[[ATTACH:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(attach, ref_ptee)
+! ON: %[[PARENT:.*]] = omp.map.info {{.*}}members(%[[PTEE]] : [1]
+! ON: omp.declare_mapper.info map_entries(%[[PARENT]], %[[PTEE]], %[[ATTACH]]
+! ON: omp.map.info {{.*}}map_clauses(tofrom) capture(ByRef) 
mapper(@[[MAPPER]]) name("x")
+! ON: omp.target
+
+! OFF-NOT: omp.declare_mapper
+! OFF: %[[MAP:.*]] = omp.map.info var_ptr(%{{.*}}) map_clauses(tofrom) 
capture(ByRef) name("x")
+! OFF-NOT: mapper(
+! OFF: omp.target {{.*}}map_entries(%[[MAP]] ->
diff --git 
a/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-implicit-capture.f90
 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-implicit-capture.f90
new file mode 100644
index 00000000000000..3ed87985df0f7c
--- /dev/null
+++ 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-implicit-capture.f90
@@ -0,0 +1,40 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck 
%s --check-prefix=ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fimplicit-default-mapper-allocatable-members %s -o - | FileCheck %s 
--check-prefix=ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %s -o - | FileCheck %s 
--check-prefix=OFF
+
+! Check the -f[no-]implicit-default-mapper-allocatable-members switch for
+! compiler-generated implicit target-region captures that synthesize an 
implicit
+! default mapper for a derived type containing an allocatable.
+!
+! With the default/on setting, compiler-generated implicit default mappers for
+! derived types include maps for allocatable components. With the off setting,
+! those component maps are suppressed.
+
+
+program implicit_capture
+  implicit none
+
+  type :: t
+    integer, allocatable :: a(:)
+  end type
+
+  type(t) :: x
+
+  !$omp target
+    x%a(1) = 1
+  !$omp end target
+end program
+
+! ON: omp.declare_mapper @[[MAPPER:_QQFt_omp_default_mapper]]
+! ON: %[[COORD:.*]] = fir.coordinate_of %{{.*}}#0, a
+! ON: %[[PTEE:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(implicit, tofrom, ref_ptee)
+! ON: %[[ATTACH:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(attach, ref_ptee)
+! ON: %[[PARENT:.*]] = omp.map.info {{.*}}members(%[[PTEE]] : [0]
+! ON: omp.declare_mapper.info map_entries(%[[PARENT]], %[[PTEE]], %[[ATTACH]]
+! ON: omp.map.info {{.*}}map_clauses(implicit, tofrom) capture(ByRef) 
mapper(@[[MAPPER]]) name("x")
+! ON: omp.target
+
+! OFF-NOT: omp.declare_mapper
+! OFF: %[[MAP:.*]] = omp.map.info var_ptr(%{{.*}}) map_clauses(implicit, 
tofrom) capture(ByRef) name("x")
+! OFF-NOT: mapper(
+! OFF: omp.target {{.*}}map_entries(%[[MAP]] ->
diff --git 
a/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90
deleted file mode 100644
index 2504dc86eb95d5..00000000000000
--- 
a/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag.f90
+++ /dev/null
@@ -1,81 +0,0 @@
-! RUN: rm -rf %t && split-file %s %t
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/implicit.f90 -o 
- | FileCheck %s --check-prefix=IMPLICIT-ON
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fimplicit-default-mapper-allocatable-members %t/implicit.f90 -o - | FileCheck 
%s --check-prefix=IMPLICIT-ON
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %t/implicit.f90 -o - | 
FileCheck %s --check-prefix=IMPLICIT-OFF
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/explicit.f90 -o 
- | FileCheck %s --check-prefix=EXPLICIT-ON
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fimplicit-default-mapper-allocatable-members %t/explicit.f90 -o - | FileCheck 
%s --check-prefix=EXPLICIT-ON
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %t/explicit.f90 -o - | 
FileCheck %s --check-prefix=EXPLICIT-OFF
-
-! Check the -f[no-]implicit-default-mapper-allocatable-members switch.
-!
-! With the default/on setting, compiler-generated implicit default mappers for
-! derived types include maps for allocatable and nested-record components.
-! With the off setting, those component maps are suppressed. Cover both:
-!   1. an implicit target-region capture; and
-!   2. an explicit whole-object map that would otherwise synthesize a default
-!      mapper for the derived type.
-
-!--- implicit.f90
-program implicit_capture
-  implicit none
-
-  type :: t
-    integer, allocatable :: a(:)
-  end type
-
-  type(t) :: x
-
-  allocate(x%a(1))
-
-  !$omp target
-    x%a(1) = 1
-  !$omp end target
-end program
-
-!--- explicit.f90
-program explicit_whole_object_map
-  implicit none
-
-  type :: t
-    integer :: scalar
-    integer, allocatable :: a(:)
-  end type
-
-  type(t) :: x
-
-  allocate(x%a(1))
-  x%scalar = 1
-
-  !$omp target map(tofrom: x)
-    x%scalar = x%scalar + 1
-    x%a(1) = x%a(1) + 1
-  !$omp end target
-end program
-
-! IMPLICIT-ON: omp.declare_mapper @[[IM_MAPPER:_QQFt_omp_default_mapper]]
-! IMPLICIT-ON: %[[COORD:.*]] = fir.coordinate_of %{{.*}}#0, a
-! IMPLICIT-ON: %[[PTEE:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(implicit, tofrom, ref_ptee)
-! IMPLICIT-ON: %[[ATTACH:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(attach, ref_ptee)
-! IMPLICIT-ON: %[[PARENT:.*]] = omp.map.info {{.*}}members(%[[PTEE]] : [0]
-! IMPLICIT-ON: omp.declare_mapper.info map_entries(%[[PARENT]], %[[PTEE]], 
%[[ATTACH]]
-! IMPLICIT-ON: omp.map.info {{.*}}map_clauses(implicit, tofrom) capture(ByRef) 
mapper(@[[IM_MAPPER]]) name("x")
-! IMPLICIT-ON: omp.target
-
-! IMPLICIT-OFF-NOT: omp.declare_mapper
-! IMPLICIT-OFF: %[[IM_MAP:.*]] = omp.map.info var_ptr(%{{.*}}) 
map_clauses(implicit, tofrom) capture(ByRef) name("x")
-! IMPLICIT-OFF-NOT: mapper(
-! IMPLICIT-OFF: omp.target {{.*}}map_entries(%[[IM_MAP]] ->
-
-! EXPLICIT-ON: omp.declare_mapper @[[EX_MAPPER:_QQFt_omp_default_mapper]]
-! EXPLICIT-ON: %[[COORD:.*]] = fir.coordinate_of %{{.*}}#0, a
-! EXPLICIT-ON: %[[PTEE:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(implicit, tofrom, ref_ptee)
-! EXPLICIT-ON: %[[ATTACH:.*]] = omp.map.info var_ptr(%[[COORD]] {{.*}}) 
map_clauses(attach, ref_ptee)
-! EXPLICIT-ON: %[[PARENT:.*]] = omp.map.info {{.*}}members(%[[PTEE]] : [1]
-! EXPLICIT-ON: omp.declare_mapper.info map_entries(%[[PARENT]], %[[PTEE]], 
%[[ATTACH]]
-! EXPLICIT-ON: omp.map.info {{.*}}map_clauses(tofrom) capture(ByRef) 
mapper(@[[EX_MAPPER]]) name("x")
-! EXPLICIT-ON: omp.target
-
-! EXPLICIT-OFF-NOT: omp.declare_mapper
-! EXPLICIT-OFF: %[[EX_MAP:.*]] = omp.map.info var_ptr(%{{.*}}) 
map_clauses(tofrom) capture(ByRef) name("x")
-! EXPLICIT-OFF-NOT: mapper(
-! EXPLICIT-OFF: omp.target {{.*}}map_entries(%[[EX_MAP]] ->

>From 4d716936aa4278430470f43ea6a64e5b7908d282 Mon Sep 17 00:00:00 2001
From: agozillon <[email protected]>
Date: Fri, 30 Oct 2026 15:39:26 -0500
Subject: [PATCH 3/3] [Flang][OpenMP] Don't block mapper attachment to nested
 components when flag is used and allow for cases where no allocatable
 involved

---
 flang/include/flang/Utils/OpenMP.h            |   3 +-
 flang/lib/Lower/OpenMP/OpenMP.cpp             |   5 +-
 flang/lib/Lower/OpenMP/Utils.cpp              |  51 +++++---
 flang/lib/Lower/OpenMP/Utils.h                |   1 +
 flang/lib/Utils/OpenMP.cpp                    |   8 +-
 ...atable-members-flag-nested-user-mapper.f90 |  39 +++++++
 ...mapper-multiple-nested-default-mappers.f90 | 109 ++++++++++++++++++
 ...t-mapper-nested-default-mapper-carrier.f90 |  37 ++++++
 8 files changed, 231 insertions(+), 22 deletions(-)
 create mode 100644 
flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-nested-user-mapper.f90
 create mode 100644 
flang/test/Lower/OpenMP/implicit-default-mapper-multiple-nested-default-mappers.f90
 create mode 100644 
flang/test/Lower/OpenMP/implicit-default-mapper-nested-default-mapper-carrier.f90

diff --git a/flang/include/flang/Utils/OpenMP.h 
b/flang/include/flang/Utils/OpenMP.h
index 0cb77e25af9475..ee2ec231128af3 100644
--- a/flang/include/flang/Utils/OpenMP.h
+++ b/flang/include/flang/Utils/OpenMP.h
@@ -72,7 +72,8 @@ std::string 
getCanonicalDefaultDeclareMapperName(fir::RecordType recordType);
 mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
     fir::FirOpBuilder &firOpBuilder, mlir::Location loc,
     fir::RecordType recordType, llvm::StringRef mapperNameStr,
-    RecordMemberMapperMangler mangler = {});
+    RecordMemberMapperMangler mangler = {},
+    bool emitAllocatableMemberMaps = true);
 } // namespace Fortran::utils::openmp
 
 #endif // FORTRAN_UTILS_OPENMP_H_
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp 
b/flang/lib/Lower/OpenMP/OpenMP.cpp
index a150f921610dc4..75e9439c4c2bf2 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -4250,7 +4250,7 @@ genTargetOp(lower::AbstractConverter &converter, 
lower::SymMap &symTable,
             if (!isPointer &&
                 (hasDefaultMapper ||
                  (requiresImplicitDefaultDeclareMapper(
-                     *typeSpec,
+                     converter, firOpBuilder, *typeSpec,
                      enableImplicitDefaultMapperAllocatableMembers)))) {
               if (!hasDefaultMapper) {
                 if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
@@ -4261,7 +4261,8 @@ genTargetOp(lower::AbstractConverter &converter, 
lower::SymMap &symTable,
                       [&](std::string &mapperIdName,
                           llvm::StringRef memberName) {
                         defaultMangler(converter, mapperIdName, memberName);
-                      });
+                      },
+                      enableImplicitDefaultMapperAllocatableMembers);
               } else {
                 mapperId = mlir::FlatSymbolRefAttr::get(
                     &converter.getMLIRContext(), mapperIdName);
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index f4fc67ddfcaa7e..48746a4566f38b 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -76,14 +76,22 @@ llvm::cl::opt<bool> treatIndexAsSection(
 namespace Fortran {
 namespace lower {
 namespace omp {
+
+static bool
+hasUserDefinedDefaultMapper(Fortran::lower::AbstractConverter &converter,
+                            const semantics::DerivedTypeSpec &typeSpec) {
+  std::string mapperName =
+      typeSpec.name().ToString() + llvm::omp::OmpDefaultMapperName;
+  if (auto *sym = converter.getCurrentScope().FindSymbol(mapperName))
+    return sym->GetUltimate().detailsIf<semantics::MapperDetails>();
+
+  return false;
+}
+
 bool requiresImplicitDefaultDeclareMapper(
+    lower::AbstractConverter &converter, fir::FirOpBuilder &firOpBuilder,
     const semantics::DerivedTypeSpec &typeSpec,
     bool enableImplicitDefaultMapperAllocatableMembers) {
-  // If disabled via -fno-implicit-default-mapper-allocatable-members
-  // return false, as we do not need to emit allocatable member maps.
-  if (!enableImplicitDefaultMapperAllocatableMembers)
-    return false;
-
   llvm::SmallPtrSet<const semantics::DerivedTypeSpec *, 8> visited;
 
   std::function<bool(const semantics::DerivedTypeSpec &)> requiresMapper =
@@ -93,13 +101,21 @@ bool requiresImplicitDefaultDeclareMapper(
 
     semantics::DirectComponentIterator directComponents{spec};
     for (const semantics::Symbol &component : directComponents) {
-      if (component.attrs().test(semantics::Attr::ALLOCATABLE))
+      if (enableImplicitDefaultMapperAllocatableMembers &&
+          component.attrs().test(semantics::Attr::ALLOCATABLE))
         return true;
 
-      if (const semantics::DeclTypeSpec *declType = component.GetType())
-        if (const auto *nested = declType->AsDerived())
-          if (requiresMapper(*nested))
-            return true;
+      if (const semantics::DeclTypeSpec *declType = component.GetType()) {
+        const auto *nested = declType->AsDerived();
+        if (!nested)
+          continue;
+
+        if (hasUserDefinedDefaultMapper(converter, *nested))
+          return true;
+
+        if (requiresMapper(*nested))
+          return true;
+      }
     }
     return false;
   };
@@ -1218,7 +1234,8 @@ findMapperIfTypeMatch(Fortran::lower::AbstractConverter 
&converter,
 static mlir::FlatSymbolRefAttr
 addImplicitMapper(Fortran::lower::AbstractConverter &converter,
                   mlir::Location loc, const omp::Object &object,
-                  std::string &mapperIdName, bool allowGenerate) {
+                  std::string &mapperIdName, bool allowGenerate,
+                  bool emitAllocatableMemberMaps) {
   if (!allowGenerate || mapperIdName.empty())
     return mlir::FlatSymbolRefAttr();
 
@@ -1239,7 +1256,8 @@ addImplicitMapper(Fortran::lower::AbstractConverter 
&converter,
       converter.getFirOpBuilder(), loc, recordType, mapperIdName,
       [&](std::string &mapperIdName, llvm::StringRef memberName) {
         defaultMangler(converter, mapperIdName, memberName);
-      });
+      },
+      emitAllocatableMemberMaps);
 }
 
 mlir::FlatSymbolRefAttr resolveMapperId(
@@ -1286,15 +1304,18 @@ mlir::FlatSymbolRefAttr resolveMapperId(
           (mapTypeBits & mlir::omp::ClauseMapFlags::implicit) ==
           mlir::omp::ClauseMapFlags::implicit;
       bool needsDefaultMapper = requiresImplicitDefaultDeclareMapper(
-          *objectTypeSpec, enableImplicitDefaultMapperAllocatableMembers);
+          converter, firOpBuilder, *objectTypeSpec,
+          enableImplicitDefaultMapperAllocatableMembers);
       // For implicit captures, avoid synthesizing default mappers for
       // pointer entities (which can over-map pointer payloads) and for
       // plain non-allocatable/non-pointer entities. Keep implicit mapper
       // support for allocatables.
       if (isImplicitMap && (isPointer || !isAllocOrPointer))
         needsDefaultMapper = false;
-      mapperId = addImplicitMapper(converter, loc, object, mapperIdName,
-                                   /*allowGenerate=*/needsDefaultMapper);
+      mapperId =
+          addImplicitMapper(converter, loc, object, mapperIdName,
+                            /*allowGenerate=*/needsDefaultMapper,
+                            enableImplicitDefaultMapperAllocatableMembers);
     }
   }
 
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 475769bebc3388..a8cc125aabe1a2 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -146,6 +146,7 @@ mlir::Value createParentSymAndGenIntermediateMaps(
     mlir::omp::ClauseMapFlags mapTypeBits);
 
 bool requiresImplicitDefaultDeclareMapper(
+    lower::AbstractConverter &converter, fir::FirOpBuilder &firOpBuilder,
     const semantics::DerivedTypeSpec &typeSpec,
     bool enableImplicitDefaultMapperAllocatableMembers);
 
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index aa5ef994252f76..292d9f6ba99f99 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -214,7 +214,7 @@ void cloneOrMapRegionOutsiders(
 mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
     fir::FirOpBuilder &firOpBuilder, mlir::Location loc,
     fir::RecordType recordType, llvm::StringRef mapperNameStr,
-    RecordMemberMapperMangler mangler) {
+    RecordMemberMapperMangler mangler, bool emitAllocatableMemberMaps) {
   auto getKindlessDefaultMapperName =
       [](fir::RecordType recType) -> std::string {
     auto [nameKind, deconstructed] =
@@ -336,12 +336,12 @@ mlir::FlatSymbolRefAttr 
getOrGenImplicitDefaultDeclareMapper(
       std::string mapperIdName = getCanonicalDefaultDeclareMapperName(recType);
       if (mangler)
         mangler(mapperIdName, memberName);
-      mapperId = getOrGenImplicitDefaultDeclareMapper(
-          firOpBuilder, loc, recType, mapperIdName, mangler);
+      mapperId = getOrGenImplicitDefaultDeclareMapper(firOpBuilder, loc,
+          recType, mapperIdName, mangler, emitAllocatableMemberMaps);
     }
 
     bool isAllocatable = 
fir::isAllocatableType(fir::unwrapRefType(memberType));
-    if (isAllocatable ||
+    if ((isAllocatable && emitAllocatableMemberMaps) ||
         mlir::isa<fir::RecordType>(fir::getFortranElementType(memberType))) {
       auto ref =
           getFieldRef(declareOp.getBase(), memberName, memberType, recordType);
diff --git 
a/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-nested-user-mapper.f90
 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-nested-user-mapper.f90
new file mode 100644
index 00000000000000..c038353a9f9b3d
--- /dev/null
+++ 
b/flang/test/Lower/OpenMP/implicit-default-mapper-allocatable-members-flag-nested-user-mapper.f90
@@ -0,0 +1,39 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %s -o - | FileCheck %s
+
+! Check that -fno-implicit-default-mapper-allocatable-members does not suppress
+! generation of an implicit default mapper when a nested record component has a
+! user-defined default mapper. The generated outer mapper is still needed as a
+! carrier for the nested component mapper, but it must not emit maps for
+! allocatable components.
+
+program main
+  implicit none
+
+  type :: inner(k)
+    integer, kind :: k
+    integer(k), pointer :: p(:)
+  end type
+
+  !$omp declare mapper(default: inner(4) :: v) map(tofrom: v%p)
+
+  type :: outer
+    integer, allocatable :: unused(:)
+    type(inner(4)) :: child
+  end type
+
+contains
+  subroutine run(x)
+    type(outer) :: x
+    !$omp target map(tofrom: x)
+      x%child%p(1) = 42
+    !$omp end target
+  end subroutine
+end program
+
+! CHECK-DAG: omp.declare_mapper @[[OUTER_MAPPER:.*outer.*_omp_default_mapper]]
+! CHECK-DAG: omp.declare_mapper @[[INNER_MAPPER:.*inner.*_omp_default_mapper]]
+! CHECK-DAG: fir.coordinate_of %{{.*}}, child
+! CHECK-DAG: omp.map.info {{.*}}mapper(@[[INNER_MAPPER]])
+! CHECK-DAG: omp.map.info {{.*}}members(%{{.*}} : [1]
+! CHECK: omp.map.info {{.*}}mapper(@[[OUTER_MAPPER]]) name("x")
+! CHECK: omp.target
diff --git 
a/flang/test/Lower/OpenMP/implicit-default-mapper-multiple-nested-default-mappers.f90
 
b/flang/test/Lower/OpenMP/implicit-default-mapper-multiple-nested-default-mappers.f90
new file mode 100644
index 00000000000000..2252462ca70852
--- /dev/null
+++ 
b/flang/test/Lower/OpenMP/implicit-default-mapper-multiple-nested-default-mappers.f90
@@ -0,0 +1,109 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck 
%s --check-prefixes=CHECK,ON
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %s -o - | FileCheck %s 
--check-prefixes=CHECK,OFF
+
+! Check that generated default mapper carriers are emitted for multi-level
+! derived type hierarchies when nested components have user-defined default
+! mappers. This must work both with and without
+! -fno-implicit-default-mapper-allocatable-members.
+!
+! The compiler-generated top_t mapper should attach the user-defined middle_t
+! default mapper to top%mid, and the user-defined middle_t default mapper 
should
+! attach the user-defined leaf_t default mapper to middle%leaf.
+!
+! Also check a top-level allocatable component in a generated carrier mapper:
+! default/on emits the allocatable member map, while the -fno flag suppresses
+! only that allocatable member and still emits the nested default mapper 
carrier.
+
+program main
+  implicit none
+
+  type :: leaf_t(k)
+    integer, kind :: k
+    integer(k), pointer :: p(:)
+  end type
+
+  !$omp declare mapper(default: leaf_t(4) :: v) map(tofrom: v%p)
+
+  type :: middle_t
+    integer :: payload(8)
+    type(leaf_t(4)) :: leaf
+  end type
+
+  !$omp declare mapper(default: middle_t :: v) map(tofrom: v%leaf)
+
+  type :: top_t
+    integer :: scalar
+    type(middle_t) :: mid
+  end type
+
+  type(top_t) :: x
+
+  !$omp target map(tofrom: x)
+    x%mid%leaf%p(1) = 42
+  !$omp end target
+end program
+
+subroutine top_allocatable_component
+  implicit none
+
+  type :: leaf_alloc_t(k)
+    integer, kind :: k
+    integer(k), pointer :: p(:)
+  end type
+
+  !$omp declare mapper(default: leaf_alloc_t(4) :: v) map(tofrom: v%p)
+
+  type :: middle_alloc_t
+    integer :: payload(8)
+    type(leaf_alloc_t(4)) :: leaf
+  end type
+
+  !$omp declare mapper(default: middle_alloc_t :: v) map(tofrom: v%leaf)
+
+  type :: top_alloc_t
+    integer, allocatable :: alloc_field(:)
+    type(middle_alloc_t) :: mid
+  end type
+
+  type(top_alloc_t) :: x
+
+  !$omp target map(tofrom: x)
+    x%mid%leaf%p(1) = 42
+  !$omp end target
+end subroutine
+
+! The allocatable variant's generated middle mapper carries the default leaf
+! mapper, and the generated top mapper carries the default middle mapper.
+! CHECK: omp.declare_mapper @{{.*middle_alloc_t_omp_default_mapper}}
+! CHECK: omp.map.info {{.*}}mapper(@{{.*leaf_alloc_t.*_omp_default_mapper}})
+! CHECK: omp.declare_mapper @{{.*top_alloc_t_omp_default_mapper}}
+
+! Default/on maps the top-level allocatable member inside the generated mapper.
+! ON: fir.field_index alloc_field
+! ON: omp.map.info {{.*}}map_clauses(implicit, tofrom, ref_ptee)
+! ON: fir.field_index mid
+! ON: omp.map.info {{.*}}mapper(@{{.*middle_alloc_t_omp_default_mapper}})
+! ON: omp.declare_mapper.info
+
+! With -fno-implicit-default-mapper-allocatable-members, the generated carrier
+! mapper omits the allocatable member map but still attaches the nested default
+! mapper to mid.
+! OFF-NOT: fir.field_index alloc_field
+! OFF: fir.field_index mid
+! OFF: omp.map.info {{.*}}mapper(@{{.*middle_alloc_t_omp_default_mapper}})
+! OFF: omp.declare_mapper.info
+
+! The user-defined middle_alloc_t mapper also carries the leaf_alloc_t mapper.
+! CHECK: omp.declare_mapper @{{.*middle_alloc_t_omp_default_mapper}}
+! CHECK: omp.map.info {{.*}}mapper(@{{.*leaf_alloc_t.*_omp_default_mapper}})
+
+! The non-allocatable variant's generated middle mapper carries the default 
leaf
+! mapper, and the generated top mapper carries the default middle mapper.
+! CHECK: omp.declare_mapper @{{.*middle_t_omp_default_mapper}}
+! CHECK: omp.map.info {{.*}}mapper(@{{.*leaf_t.*_omp_default_mapper}})
+! CHECK: omp.declare_mapper @{{.*top_t_omp_default_mapper}}
+! CHECK: omp.map.info {{.*}}mapper(@{{.*middle_t_omp_default_mapper}})
+
+! The target maps use the generated top-level carrier mappers.
+! CHECK-DAG: omp.map.info {{.*}}mapper(@{{.*top_t_omp_default_mapper}}) 
name("x")
+! CHECK-DAG: omp.map.info {{.*}}mapper(@{{.*top_alloc_t_omp_default_mapper}}) 
name("x")
diff --git 
a/flang/test/Lower/OpenMP/implicit-default-mapper-nested-default-mapper-carrier.f90
 
b/flang/test/Lower/OpenMP/implicit-default-mapper-nested-default-mapper-carrier.f90
new file mode 100644
index 00000000000000..fd1c9894134fb7
--- /dev/null
+++ 
b/flang/test/Lower/OpenMP/implicit-default-mapper-nested-default-mapper-carrier.f90
@@ -0,0 +1,37 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck 
%s
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 
-fno-implicit-default-mapper-allocatable-members %s -o - | FileCheck %s
+
+! Check that an implicit default mapper is generated for an outer record even
+! when it has no allocatable components, if a nested record component has a
+! user-defined default mapper. The generated outer mapper is needed as a 
carrier
+! to attach the nested component mapper.
+
+program main
+  implicit none
+
+  type :: inner(k)
+    integer, kind :: k
+    integer(k), pointer :: p(:)
+  end type
+
+  !$omp declare mapper(default: inner(4) :: v) map(tofrom: v%p)
+
+  type :: outer
+    integer :: some_arr(10)
+    type(inner(4)) :: child
+  end type
+
+  type(outer) :: x
+
+  !$omp target map(tofrom: x)
+    x%child%p(1) = 42
+  !$omp end target
+end program
+
+! CHECK-DAG: omp.declare_mapper @[[OUTER_MAPPER:.*outer.*_omp_default_mapper]]
+! CHECK-DAG: omp.declare_mapper @[[INNER_MAPPER:.*inner.*_omp_default_mapper]]
+! CHECK-DAG: fir.coordinate_of %{{.*}}, child
+! CHECK-DAG: omp.map.info {{.*}}mapper(@[[INNER_MAPPER]])
+! CHECK-DAG: omp.map.info {{.*}}members(%{{.*}} : [1]
+! CHECK: omp.map.info {{.*}}mapper(@[[OUTER_MAPPER]]) name("x")
+! CHECK: omp.target

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to