[flang-commits] [flang] [Flang][OpenMP][Sema] Warn on local descriptors in target enter data (PR #204839)

Akash Banerjee via flang-commits flang-commits at lists.llvm.org
Fri Jun 19 07:41:14 PDT 2026


https://github.com/TIFitis created https://github.com/llvm/llvm-project/pull/204839

This reworks the reverted warning from llvm/llvm-project#201060 after llvm/llvm-project#203324.

The original diagnostic used the default-on `-Wopenmp-usage` bucket, so projects building with `-Werror` could fail just by mapping these descriptors. This version puts the check behind a dedicated opt-in warning, `-Wopenmp-target-enter-data-local-descriptor`, while keeping default `-Werror` builds quiet.

What changed:
- Warn when `TARGET ENTER DATA` maps an assumed-shape/assumed-rank dummy or an unsaved local allocatable/pointer descriptor without a matching `TARGET EXIT DATA` in the same subprogram scope.
- Keep the OpenMP 6.1+ wording that suggests `ref_ptee`.
- Track enter/exit data pairs per subprogram scope so internal subprograms do not clear or satisfy their host procedure's mappings.
- Avoid warning for saved/module descriptors, dummy allocatable/pointer descriptors, explicit-shape/assumed-size dummies, `ref_*` map modifiers, or matching exit data.

Validation:
- `ninja -C build flang bbc FlangCommonTests`
- `build/tools/flang/unittests/Common/FlangCommonTests --gtest_filter=FortranFeaturesTest.CamelCaseToLowerCaseHyphenated`
- `build/bin/llvm-lit -sv flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor.f90 flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor-omp61.f90`
- `ninja -C build check-flang-semantics-openmp`


>From 013c3558521bb08c1b4b6970299527869444aedc Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Fri, 19 Jun 2026 15:34:46 +0100
Subject: [PATCH] [Flang][OpenMP][Sema] Warn on local descriptors in target
 enter data

---
 flang/include/flang/Semantics/openmp-utils.h  |   4 +
 .../include/flang/Support/Fortran-features.h  |   3 +-
 flang/lib/Semantics/check-omp-structure.cpp   |  64 +++++++++
 flang/lib/Semantics/check-omp-structure.h     |   9 ++
 flang/lib/Semantics/openmp-utils.cpp          |  19 +++
 ...arget-enter-data-temp-descriptor-omp61.f90 | 101 ++++++++++++++
 .../target-enter-data-temp-descriptor.f90     | 125 ++++++++++++++++++
 .../unittests/Common/FortranFeaturesTest.cpp  |   3 +
 8 files changed, 327 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor-omp61.f90
 create mode 100644 flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor.f90

diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index e0358eafe487c..fdbfa9292b11a 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -119,6 +119,10 @@ const Symbol *GetHostSymbol(const Symbol &sym);
 bool IsMapEnteringType(parser::OmpMapType::Value type);
 bool IsMapExitingType(parser::OmpMapType::Value type);
 
+// Returns true if mapping the symbol may map a local descriptor whose lifetime
+// is tied to the current procedure activation.
+bool HasTemporaryStackDescriptor(const Symbol &symbol);
+
 MaybeExpr GetEvaluateExpr(const parser::Expr &parserExpr);
 template <typename T> MaybeExpr GetEvaluateExpr(const T &inp) {
   return GetEvaluateExpr(parser::UnwrapRef<parser::Expr>(inp));
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index ebc6f495e59ba..0bcac2993eda6 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -74,7 +74,8 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
     Bounds, Preprocessing, Scanning, OpenAccUsage, ProcPointerCompatibility,
     VoidMold, KnownBadImplicitInterface, EmptyCase, CaseOverflow, CUDAUsage,
     IgnoreTKRUsage, ExternalInterfaceMismatch, DefinedOperatorArgs, Final,
-    ZeroDoStep, UnusedForallIndex, OpenMPUsage, DataLength, IgnoredDirective,
+    ZeroDoStep, UnusedForallIndex, OpenMPUsage,
+    OpenMPTargetEnterDataLocalDescriptor, DataLength, IgnoredDirective,
     HomonymousSpecific, HomonymousResult, IgnoredIntrinsicFunctionType,
     PreviousScalarUse, RedeclaredInaccessibleComponent, ImplicitShared,
     IndexVarRedefinition, IncompatibleImplicitInterfaces,
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 7c531ae0046ae..ca3f6f80fff0b 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -140,27 +140,58 @@ void OmpStructureChecker::Leave(const parser::Submodule &x) {
 void OmpStructureChecker::Enter(const parser::SubroutineStmt &x) {
   const Symbol *sym{std::get<parser::Name>(x.t).symbol};
   scopeStack_.push_back(sym->scope());
+  tempDescriptorMappings_.emplace_back();
+}
+
+void OmpStructureChecker::CheckTempDescriptorMappings() {
+  if (tempDescriptorMappings_.empty()) {
+    return;
+  }
+
+  unsigned version{context_.langOptions().OpenMPVersion};
+  TempDescriptorMappings &mappings{tempDescriptorMappings_.back()};
+  for (const auto &[symbol, source] : mappings.enterMaps) {
+    if (mappings.exitMaps.find(symbol) == mappings.exitMaps.end()) {
+      if (version >= 61) {
+        context_.Warn(
+            common::UsageWarning::OpenMPTargetEnterDataLocalDescriptor, source,
+            "The map of '%s' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference. To avoid mapping the descriptor utilize OpenMP's ref_ptee reference modifier to map just the data"_warn_en_US,
+            symbol->name());
+      } else {
+        context_.Warn(
+            common::UsageWarning::OpenMPTargetEnterDataLocalDescriptor, source,
+            "The map of '%s' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference"_warn_en_US,
+            symbol->name());
+      }
+    }
+  }
+  tempDescriptorMappings_.pop_back();
 }
 
 void OmpStructureChecker::Enter(const parser::EndSubroutineStmt &x) {
+  CheckTempDescriptorMappings();
   scopeStack_.pop_back();
 }
 
 void OmpStructureChecker::Enter(const parser::FunctionStmt &x) {
   const Symbol *sym{std::get<parser::Name>(x.t).symbol};
   scopeStack_.push_back(sym->scope());
+  tempDescriptorMappings_.emplace_back();
 }
 
 void OmpStructureChecker::Enter(const parser::EndFunctionStmt &x) {
+  CheckTempDescriptorMappings();
   scopeStack_.pop_back();
 }
 
 void OmpStructureChecker::Enter(const parser::MpSubprogramStmt &x) {
   const Symbol *sym{x.v.symbol};
   scopeStack_.push_back(sym->scope());
+  tempDescriptorMappings_.emplace_back();
 }
 
 void OmpStructureChecker::Enter(const parser::EndMpSubprogramStmt &x) {
+  CheckTempDescriptorMappings();
   scopeStack_.pop_back();
 }
 
@@ -4676,6 +4707,39 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Map &x) {
       }
     }
   }
+
+  // If we are an enter or exit map, iterate over the maps and add them to
+  // containers that track if the symbol has been referenced in both an
+  // enter/exit map in the current scope, if it falls into the category of
+  // having a temporary stack descriptor. If we have reference modifiers, we
+  // ignore the warning and trust that the user knows what they are doing
+  // already, as they are aware the type comes with a descriptor and pointer
+  // combination.
+  //
+  // We will utilize this information to emit a warning later if the necessary
+  // conditions are met, where we have an enter map without a corresponding exit
+  // in the current scope.
+  bool hasRefModifier{
+      OmpGetUniqueModifier<parser::OmpRefModifier>(modifiers) != nullptr};
+  if (!hasRefModifier && !tempDescriptorMappings_.empty() &&
+      (llvm::is_contained(leafs, Directive::OMPD_target_enter_data) ||
+          llvm::is_contained(leafs, Directive::OMPD_target_exit_data))) {
+    TempDescriptorMappings &mappings{tempDescriptorMappings_.back()};
+    for (const parser::OmpObject &object : objects.v) {
+      if (const Symbol *sym{GetObjectSymbol(object, /*ultimate=*/true)}) {
+        if (HasTemporaryStackDescriptor(*sym)) {
+          auto maybeSource{GetObjectSource(object)};
+          parser::CharBlock source{
+              maybeSource.value_or(GetContext().clauseSource)};
+          if (llvm::is_contained(leafs, Directive::OMPD_target_enter_data)) {
+            mappings.enterMaps.emplace(sym, source);
+          } else {
+            mappings.exitMaps.insert(sym);
+          }
+        }
+      }
+    }
+  }
 }
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Schedule &x) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 9fca5ff0f5fca..05406e29e2002 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -392,6 +392,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
       const parser::OmpClause &initClause);
   void CheckAllowedRequiresClause(llvm::omp::Clause clause);
   void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
+  void CheckTempDescriptorMappings();
 
   void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
   void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
@@ -414,6 +415,14 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
   int allocateDirectiveLevel_{0};
   parser::CharBlock visitedAtomicSource_;
 
+  struct TempDescriptorMappings {
+    SymbolSourceMap enterMaps;
+    std::set<const Symbol *> exitMaps;
+  };
+  // Track descriptor mappings per subprogram scope so internal subprograms do
+  // not affect their host's TARGET ENTER/EXIT DATA pairing.
+  std::vector<TempDescriptorMappings> tempDescriptorMappings_;
+
   // Stack of nested DO loops and OpenMP constructs.
   // This is used to verify DO loop nest for DOACROSS, and branches into
   // and out of OpenMP constructs.
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index b02ef81176a63..5715c7aa27ae3 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -312,6 +312,25 @@ bool IsMapExitingType(parser::OmpMapType::Value type) {
   }
 }
 
+bool HasTemporaryStackDescriptor(const Symbol &symbol) {
+  const Symbol &ultimate(symbol.GetUltimate());
+  bool isDummy = IsDummy(ultimate);
+
+  if (IsAllocatableOrPointer(ultimate)) {
+    return !isDummy && !IsSaved(ultimate);
+  }
+
+  if (!isDummy) {
+    return false;
+  }
+
+  if (const auto *obj = ultimate.detailsIf<ObjectEntityDetails>()) {
+    return obj->IsAssumedShape() || obj->IsAssumedRank();
+  }
+
+  return false;
+}
+
 static MaybeExpr GetEvaluateExprFromTyped(const parser::TypedExpr &typedExpr) {
   // ForwardOwningPointer           typedExpr
   // `- GenericExprWrapper          ^.get()
diff --git a/flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor-omp61.f90 b/flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor-omp61.f90
new file mode 100644
index 0000000000000..091284d46168c
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor-omp61.f90
@@ -0,0 +1,101 @@
+! RUN: %flang -fsyntax-only -fopenmp -fopenmp-version=61 -Wopenmp-target-enter-data-local-descriptor -Wno-experimental-option %s 2>&1 | FileCheck %s --check-prefix=EMIT61
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=61 -Wopenmp-target-enter-data-local-descriptor -Werror -Wno-experimental-option
+
+! EMIT61: warning: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference. To avoid mapping the descriptor utilize OpenMP's ref_ptee reference modifier to map just the data [-Wopenmp-target-enter-data-local-descriptor]
+! EMIT61-NOT: Semantic errors in
+
+! Check for OpenMP 6.1+ specific warning that includes ref_ptee suggestion
+! when mapping variables with temporary stack descriptors on TARGET ENTER DATA
+! without a corresponding TARGET EXIT DATA.
+
+subroutine test_assumed_shape_warning(arr)
+  integer, intent(inout), dimension(:,:) :: arr(:)
+  !WARNING: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference. To avoid mapping the descriptor utilize OpenMP's ref_ptee reference modifier to map just the data [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_assumed_rank_warning(arr)
+  integer, intent(inout) :: arr(..)
+  !WARNING: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference. To avoid mapping the descriptor utilize OpenMP's ref_ptee reference modifier to map just the data [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_local_allocatable_warning()
+  integer, allocatable :: local_arr(:)
+  allocate(local_arr(100))
+  !WARNING: The map of 'local_arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference. To avoid mapping the descriptor utilize OpenMP's ref_ptee reference modifier to map just the data [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: local_arr)
+  deallocate(local_arr)
+end subroutine
+
+subroutine test_local_pointer_warning()
+  integer, pointer :: local_ptr(:)
+  allocate(local_ptr(100))
+  !WARNING: The map of 'local_ptr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference. To avoid mapping the descriptor utilize OpenMP's ref_ptee reference modifier to map just the data [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: local_ptr)
+  deallocate(local_ptr)
+end subroutine
+
+module test_module
+contains
+  subroutine test_module_procedure_warning(arr)
+    integer, intent(inout) :: arr(:)
+    !WARNING: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference. To avoid mapping the descriptor utilize OpenMP's ref_ptee reference modifier to map just the data [-Wopenmp-target-enter-data-local-descriptor]
+    !$omp target enter data map(to: arr)
+  end subroutine
+
+  subroutine test_module_procedure_with_exit(arr)
+    integer, intent(inout) :: arr(:)
+    !$omp target enter data map(to: arr)
+    !$omp target exit data map(from: arr)
+  end subroutine
+end module
+
+! Test cases where warnings should not be emitted, the test_errors.py script
+! should fail if we emit errors for these that are not checked, so no need to
+! verify with an explicit check.
+
+subroutine test_ref_ptee_no_warning(arr)
+  integer, intent(inout) :: arr(:)
+  !$omp target enter data map(ref_ptee, to: arr)
+end subroutine
+
+subroutine test_ref_ptr_no_warning(arr)
+  integer, intent(inout) :: arr(:)
+  !$omp target enter data map(ref_ptr, to: arr)
+end subroutine
+
+subroutine test_ref_ptr_ptee_no_warning(arr)
+  integer, intent(inout) :: arr(:)
+  !$omp target enter data map(ref_ptr_ptee, to: arr)
+end subroutine
+
+subroutine test_with_exit_data(arr)
+  integer, intent(inout) :: arr(:)
+  !$omp target enter data map(to: arr)
+  !$omp target exit data map(from: arr)
+end subroutine
+
+subroutine test_explicit_shape_no_warning(arr, n)
+  integer, intent(in) :: n
+  integer, intent(inout) :: arr(n)
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_local_allocatable_with_exit()
+  integer, allocatable :: local_arr(:)
+  allocate(local_arr(100))
+  !$omp target enter data map(to: local_arr)
+  !$omp target exit data map(from: local_arr)
+  deallocate(local_arr)
+end subroutine
+
+subroutine test_allocatable_dummy_no_warning(arr)
+  integer, allocatable, intent(inout) :: arr(:)
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_pointer_dummy_no_warning(ptr)
+  integer, pointer, intent(inout) :: ptr(:)
+  !$omp target enter data map(to: ptr)
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor.f90 b/flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor.f90
new file mode 100644
index 0000000000000..3a06eb8d26329
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/target-enter-data-temp-descriptor.f90
@@ -0,0 +1,125 @@
+! RUN: %flang -fsyntax-only -fopenmp -fopenmp-version=52 -Werror -Wno-experimental-option %s 2>&1 | FileCheck --allow-empty %s --check-prefix=NOWARN
+! RUN: %flang -fsyntax-only -fopenmp -fopenmp-version=52 -Wopenmp-target-enter-data-local-descriptor -Wno-experimental-option %s 2>&1 | FileCheck %s --check-prefix=EMIT52
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52 -Wopenmp-target-enter-data-local-descriptor -Werror -Wno-experimental-option
+
+! NOWARN-NOT: warning:
+! NOWARN-NOT: Semantic errors in
+! EMIT52: warning: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+! EMIT52-NOT: Semantic errors in
+
+! Check for warning when mapping variables with temporary stack descriptors
+! (assumed-shape, assumed-rank, local allocatables, local pointers) on
+! TARGET ENTER DATA without a corresponding TARGET EXIT DATA in the same scope.
+
+subroutine test_assumed_shape_warning(arr)
+  integer, intent(inout) :: arr(:)
+  !WARNING: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_assumed_shape_2d_warning(arr)
+  integer, intent(inout) :: arr(:,:)
+  !WARNING: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_assumed_rank_warning(arr)
+  integer, intent(inout) :: arr(..)
+  !WARNING: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_local_pointer_warning()
+  integer, pointer :: local_ptr(:)
+  allocate(local_ptr(100))
+  !WARNING: The map of 'local_ptr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: local_ptr)
+  deallocate(local_ptr)
+end subroutine
+
+subroutine test_local_allocatable_warning()
+  integer, allocatable :: local_arr(:)
+  allocate(local_arr(100))
+  !WARNING: The map of 'local_arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: local_arr)
+  deallocate(local_arr)
+end subroutine
+
+module test_module
+contains
+  subroutine test_module_procedure_warning(arr)
+    integer, intent(inout) :: arr(:)
+    !WARNING: The map of 'arr' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+    !$omp target enter data map(to: arr)
+  end subroutine
+
+  subroutine test_module_procedure_with_exit(arr)
+    integer, intent(inout) :: arr(:)
+    !$omp target enter data map(to: arr)
+    !$omp target exit data map(from: arr)
+  end subroutine
+end module
+
+subroutine test_internal_scope_warning(outer)
+  integer, intent(inout) :: outer(:)
+  !WARNING: The map of 'outer' may include a descriptor that is created locally. Mapping this descriptor without an appropriate TARGET EXIT DATA in the same scope may result in the device retaining an invalid descriptor reference [-Wopenmp-target-enter-data-local-descriptor]
+  !$omp target enter data map(to: outer)
+contains
+  subroutine inner(inner_arr)
+    integer, intent(inout) :: inner_arr(:)
+    !$omp target enter data map(to: inner_arr)
+    !$omp target exit data map(from: inner_arr)
+  end subroutine
+end subroutine
+
+! Test cases where warnings should not be emitted, the test_errors.py script
+! should fail if we emit errors for these that are not checked, so no need to
+! verify with an explicit check.
+
+subroutine test_pointer_dummy_no_warning(ptr)
+  integer, pointer, intent(inout) :: ptr(:)
+  !$omp target enter data map(to: ptr)
+end subroutine
+
+subroutine test_allocatable_dummy_no_warning(arr)
+  integer, allocatable, intent(inout) :: arr(:)
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_with_exit_data(arr)
+  integer, intent(inout) :: arr(:)
+  !$omp target enter data map(to: arr)
+  !$omp target exit data map(from: arr)
+end subroutine
+
+subroutine test_explicit_shape_no_warning(arr, n)
+  integer, intent(in) :: n
+  integer, intent(inout) :: arr(n)
+  !$omp target enter data map(to: arr)
+end subroutine
+
+subroutine test_assumed_size_no_warning(arr)
+  integer, intent(inout) :: arr(*)
+  !$omp target enter data map(to: arr(1:10))
+end subroutine
+
+subroutine test_local_allocatable_with_exit()
+  integer, allocatable :: local_arr(:)
+  allocate(local_arr(100))
+  !$omp target enter data map(to: local_arr)
+  !$omp target exit data map(from: local_arr)
+  deallocate(local_arr)
+end subroutine
+
+subroutine test_saved_local_allocatable_no_warning()
+  integer, allocatable, save :: local_arr(:)
+  !$omp target enter data map(to: local_arr)
+end subroutine
+
+module test_saved_module
+  integer, allocatable :: saved_arr(:)
+contains
+  subroutine test_module_allocatable_no_warning()
+    !$omp target enter data map(to: saved_arr)
+  end subroutine
+end module
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index dfd88cb8abecd..b77fd6439f66d 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -490,6 +490,9 @@ TEST(FortranFeaturesTest, CamelCaseToLowerCaseHyphenated) {
   EXPECT_EQ(
       CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::OpenMPUsage)),
       "openmp-usage");
+  EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+                UsageWarning::OpenMPTargetEnterDataLocalDescriptor)),
+      "openmp-target-enter-data-local-descriptor");
   EXPECT_EQ(
       CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::DataLength)),
       "data-length");



More information about the flang-commits mailing list