[flang-commits] [flang] [flang] Deallocate components of local variables at the end of the scope. (PR #68064)

via flang-commits flang-commits at lists.llvm.org
Mon Oct 2 19:46:10 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

<details>
<summary>Changes</summary>

Call Destroy runtime for local variables of derived types with
allocatable components.


---
Full diff: https://github.com/llvm/llvm-project/pull/68064.diff


4 Files Affected:

- (modified) flang/include/flang/Semantics/tools.h (+2) 
- (modified) flang/lib/Lower/ConvertVariable.cpp (+20) 
- (modified) flang/lib/Semantics/tools.cpp (+5) 
- (added) flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90 (+111) 


``````````diff
diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index ab48ef422801a44..0b5c3dde2e72082 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -180,6 +180,8 @@ const Symbol *HasImpureFinal(const Symbol &);
 // Is this type finalizable or does it contain any polymorphic allocatable
 // ultimate components?
 bool MayRequireFinalization(const DerivedTypeSpec &derived);
+// Does this type have an allocatable direct component?
+bool HasAllocatableDirectComponent(const DerivedTypeSpec &derived);
 
 bool IsInBlankCommon(const Symbol &);
 inline bool IsAssumedSizeArray(const Symbol &symbol) {
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 58d754668000ef3..df0431229e83e05 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -96,6 +96,17 @@ static bool hasFinalization(const Fortran::semantics::Symbol &sym) {
   return false;
 }
 
+// Does this variable have an allocatable direct component?
+static bool
+hasAllocatableDirectComponent(const Fortran::semantics::Symbol &sym) {
+  if (sym.has<Fortran::semantics::ObjectEntityDetails>())
+    if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
+      if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
+              declTypeSpec->AsDerived())
+        return Fortran::semantics::HasAllocatableDirectComponent(
+            *derivedTypeSpec);
+  return false;
+}
 //===----------------------------------------------------------------===//
 // Global variables instantiation (not for alias and common)
 //===----------------------------------------------------------------===//
@@ -674,6 +685,15 @@ needDeallocationOrFinalization(const Fortran::lower::pft::Variable &var) {
       return VariableCleanUp::Deallocate;
     if (hasFinalization(sym))
       return VariableCleanUp::Finalize;
+    // hasFinalization() check above handled all cases that require
+    // finalization, but we also have to deallocate all allocatable
+    // components of local variables (since they are also local variables
+    // according to F18 5.4.3.2.2, p. 2, note 1).
+    // Here, the variable itself is not allocatable. If it has an allocatable
+    // component the Destroy runtime does the job. Use the Finalize clean-up,
+    // though there will be no finalization in runtime.
+    if (hasAllocatableDirectComponent(sym))
+      return VariableCleanUp::Finalize;
   }
   return std::nullopt;
 }
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index 25ffcb68eaf87a2..7d6ab2c83cc5952 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -841,6 +841,11 @@ bool MayRequireFinalization(const DerivedTypeSpec &derived) {
       FindPolymorphicAllocatableUltimateComponent(derived);
 }
 
+bool HasAllocatableDirectComponent(const DerivedTypeSpec &derived) {
+  DirectComponentIterator directs{derived};
+  return std::any_of(directs.begin(), directs.end(), IsAllocatable);
+}
+
 bool IsAssumedLengthCharacter(const Symbol &symbol) {
   if (const DeclTypeSpec * type{symbol.GetType()}) {
     return type->category() == DeclTypeSpec::Character &&
diff --git a/flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90 b/flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90
new file mode 100644
index 000000000000000..b63026b1e3f103d
--- /dev/null
+++ b/flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90
@@ -0,0 +1,111 @@
+! Test automatic deallocation of allocatable components
+! of local variables as described in Fortran 2018 standard
+! 9.7.3.2 point 2. and 3.
+! The allocatable components of local variables are local variables
+! themselves due to 5.4.3.2.2 p. 2, note 1.
+! RUN: bbc -emit-hlfir -o - -I nowhere %s | FileCheck %s
+
+module types
+  type t1
+     real, allocatable :: x
+  end type t1
+  type t2
+     type(t1) :: x
+  end type t2
+  type, extends(t1) :: t3
+  end type t3
+  type, extends(t3) :: t4
+  end type t4
+  type, extends(t2) :: t5
+  end type t5
+end module types
+
+subroutine test1()
+  use types
+  type(t1) :: x1
+end subroutine test1
+! CHECK-LABEL:   func.func @_QPtest1() {
+! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+
+subroutine test1b()
+  use types
+  block
+    type(t1) :: x1
+  end block
+end subroutine test1b
+! CHECK-LABEL:   func.func @_QPtest1b() {
+! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+
+subroutine test2()
+  use types
+  type(t2) :: x2
+end subroutine test2
+! CHECK-LABEL:   func.func @_QPtest2() {
+! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt2{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>
+
+subroutine test2b()
+  use types
+  block
+    type(t2) :: x2
+  end block
+end subroutine test2b
+! CHECK-LABEL:   func.func @_QPtest2b() {
+! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt2{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>
+
+subroutine test3()
+  use types
+  type(t3) :: x3
+end subroutine test3
+! CHECK-LABEL:   func.func @_QPtest3() {
+! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt3{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+
+subroutine test3b()
+  use types
+  block
+    type(t3) :: x3
+  end block
+end subroutine test3b
+! CHECK-LABEL:   func.func @_QPtest3b() {
+! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt3{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+
+subroutine test4()
+  use types
+  type(t4) :: x4
+end subroutine test4
+! CHECK-LABEL:   func.func @_QPtest4() {
+! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt4{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+
+subroutine test4b()
+  use types
+  block
+    type(t4) :: x4
+  end block
+end subroutine test4b
+! CHECK-LABEL:   func.func @_QPtest4b() {
+! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt4{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+
+subroutine test5()
+  use types
+  type(t5) :: x5
+end subroutine test5
+! CHECK-LABEL:   func.func @_QPtest5() {
+! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt5{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>
+
+subroutine test5b()
+  use types
+  block
+    type(t5) :: x5
+  end block
+end subroutine test5b
+! CHECK-LABEL:   func.func @_QPtest5b() {
+! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt5{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>

``````````

</details>


https://github.com/llvm/llvm-project/pull/68064


More information about the flang-commits mailing list