[flang-commits] [flang] [flang] Correct definability checking for INTENT(IN) pointers (PR #74158)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Fri Dec 8 11:15:42 PST 2023


https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/74158

>From 21018e44083cf68d9db96f5f41a077df88f14928 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Fri, 1 Dec 2023 15:29:52 -0800
Subject: [PATCH] [flang] Correct definability checking for INTENT(IN) pointers

An INTENT(IN) attribute on a pointer dummy argument prevents
modification of the pointer itself only, not modification of
any component of its target.  Fix this case without breaking
definability checking for pointer components of non-pointer
INTENT(IN) dummy arguments.
---
 flang/lib/Semantics/definable.cpp    | 23 +++++++++++++++++------
 flang/test/Semantics/definable01.f90 | 15 +++++++++++++++
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/flang/lib/Semantics/definable.cpp b/flang/lib/Semantics/definable.cpp
index d5ffcabc7233ca..b73290109248a0 100644
--- a/flang/lib/Semantics/definable.cpp
+++ b/flang/lib/Semantics/definable.cpp
@@ -89,7 +89,8 @@ static const Symbol &GetRelevantSymbol(const evaluate::DataRef &dataRef,
 
 // Check the leftmost (or only) symbol from a data-ref or expression.
 static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
-    const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
+    const Scope &scope, DefinabilityFlags flags, const Symbol &original,
+    bool isWholeSymbol) {
   const Symbol &ultimate{original.GetUltimate()};
   bool isPointerDefinition{flags.test(DefinabilityFlag::PointerDefinition)};
   bool acceptAllocatable{flags.test(DefinabilityFlag::AcceptAllocatable)};
@@ -104,7 +105,8 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
     } else if (auto dataRef{evaluate::ExtractDataRef(
                    *association->expr(), true, true)}) {
       return WhyNotDefinableBase(at, scope, flags,
-          GetRelevantSymbol(*dataRef, isPointerDefinition, acceptAllocatable));
+          GetRelevantSymbol(*dataRef, isPointerDefinition, acceptAllocatable),
+          isWholeSymbol);
     }
   }
   if (isTargetDefinition) {
@@ -112,7 +114,8 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
     return BlameSymbol(at, "'%s' is not a variable"_en_US, original);
   } else if (IsProtected(ultimate) && IsUseAssociated(original, scope)) {
     return BlameSymbol(at, "'%s' is protected in this scope"_en_US, original);
-  } else if (IsIntentIn(ultimate)) {
+  } else if (IsIntentIn(ultimate) &&
+      (!IsPointer(ultimate) || (isWholeSymbol && isPointerDefinition))) {
     return BlameSymbol(
         at, "'%s' is an INTENT(IN) dummy argument"_en_US, original);
   }
@@ -165,6 +168,12 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
 static std::optional<parser::Message> WhyNotDefinableLast(parser::CharBlock at,
     const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
   const Symbol &ultimate{original.GetUltimate()};
+  if (const auto *association{ultimate.detailsIf<AssocEntityDetails>()}) {
+    if (auto dataRef{
+            evaluate::ExtractDataRef(*association->expr(), true, true)}) {
+      return WhyNotDefinableLast(at, scope, flags, dataRef->GetLastSymbol());
+    }
+  }
   if (flags.test(DefinabilityFlag::PointerDefinition)) {
     if (flags.test(DefinabilityFlag::AcceptAllocatable)) {
       if (!IsAllocatableOrObjectPointer(&ultimate)) {
@@ -216,7 +225,8 @@ static std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
   const Symbol &base{GetRelevantSymbol(dataRef,
       flags.test(DefinabilityFlag::PointerDefinition),
       flags.test(DefinabilityFlag::AcceptAllocatable))};
-  if (auto whyNot{WhyNotDefinableBase(at, scope, flags, base)}) {
+  if (auto whyNot{WhyNotDefinableBase(at, scope, flags, base,
+          std::holds_alternative<evaluate::SymbolRef>(dataRef.u))}) {
     return whyNot;
   } else {
     return WhyNotDefinableLast(at, scope, flags, dataRef.GetLastSymbol());
@@ -231,12 +241,13 @@ static std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
   const Symbol &base{GetRelevantSymbol(dataRef, false, false)};
   DefinabilityFlags baseFlags{flags};
   baseFlags.reset(DefinabilityFlag::PointerDefinition);
-  return WhyNotDefinableBase(at, scope, baseFlags, base);
+  return WhyNotDefinableBase(at, scope, baseFlags, base,
+      std::holds_alternative<evaluate::SymbolRef>(dataRef.u));
 }
 
 std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
     const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
-  if (auto base{WhyNotDefinableBase(at, scope, flags, original)}) {
+  if (auto base{WhyNotDefinableBase(at, scope, flags, original, true)}) {
     return base;
   }
   return WhyNotDefinableLast(at, scope, flags, original);
diff --git a/flang/test/Semantics/definable01.f90 b/flang/test/Semantics/definable01.f90
index fff493fe7a4152..c0f10668fb480e 100644
--- a/flang/test/Semantics/definable01.f90
+++ b/flang/test/Semantics/definable01.f90
@@ -82,4 +82,19 @@ subroutine test3a(op)
   subroutine test3b(pp)
     procedure(sin), pointer, intent(in out) :: pp
   end subroutine
+  subroutine test4(p)
+    type(ptype), pointer, intent(in) :: p
+    p%x = 1.
+    p%ptr = 1. ! ok
+    nullify(p%ptr) ! ok
+    !CHECK: error: 'p' may not appear in NULLIFY
+    !CHECK: because: 'p' is an INTENT(IN) dummy argument
+    nullify(p)
+  end
+  subroutine test5(np)
+    type(ptype), intent(in) :: np
+    !CHECK: error: 'ptr' may not appear in NULLIFY
+    !CHECK: because: 'np' is an INTENT(IN) dummy argument
+    nullify(np%ptr)
+  end
 end module



More information about the flang-commits mailing list