diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 46a59b38ae6ab..895ae2451125d 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -714,7 +714,10 @@ needDummyIntentoutFinalization(const Fortran::lower::pft::Variable &var) { return true; // Intent(out) dummies must be finalized at runtime if their type has a // finalization. - return hasFinalization(sym); + // Allocatable components of INTENT(OUT) dummies must be deallocated (9.7.3.2 + // p6). Calling finalization runtime for this works even if the components + // have no final procedures. + return hasFinalization(sym) || hasAllocatableDirectComponent(sym); } /// Call default initialization runtime routine to initialize \p var. @@ -747,6 +750,9 @@ static void finalizeAtRuntime(Fortran::lower::AbstractConverter &converter, // is deallocated; any allocated allocatable object that is a subobject of an // actual argument corresponding to an INTENT(OUT) dummy argument is // deallocated. +// Note that allocatable components of non-ALLOCATABLE INTENT(OUT) dummy +// arguments are dealt with needDummyIntentoutFinalization (finalization runtime +// is called to reach the intended component deallocation effect). static void deallocateIntentOut(Fortran::lower::AbstractConverter &converter, const Fortran::lower::pft::Variable &var, Fortran::lower::SymMap &symMap) { diff --git a/flang/test/Lower/HLFIR/intentout-allocatable-components.f90 b/flang/test/Lower/HLFIR/intentout-allocatable-components.f90 new file mode 100644 index 0000000000000..932fafd322a3e --- /dev/null +++ b/flang/test/Lower/HLFIR/intentout-allocatable-components.f90 @@ -0,0 +1,32 @@ +! Test that allocatable components of non pointer/non allocatable INTENT(OUT) +! dummy arguments are deallocated. +! RUN: bbc -emit-hlfir -polymorphic-type %s -o - -I nowhere | FileCheck %s + +subroutine test_intentout_component_deallocate(a) + type :: t + integer, allocatable :: x + end type + type(t), intent(out) :: a +end subroutine +! CHECK-LABEL: func.func @_QPtest_intentout_component_deallocate( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>}>> +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_intentout_component_deallocateEa"} +! CHECK: %[[VAL_2:.*]] = fir.embox %[[VAL_1]]#1 : (!fir.ref>}>>) -> !fir.box>}>> +! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.box>}>>) -> !fir.box +! CHECK: %[[VAL_4:.*]] = fir.call @_FortranADestroy(%[[VAL_3]]) fastmath : (!fir.box) -> none + +subroutine test_intentout_optional_component_deallocate(a) + type :: t + integer, allocatable :: x + end type + type(t), optional, intent(out) :: a +end subroutine +! CHECK-LABEL: func.func @_QPtest_intentout_optional_component_deallocate( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>}>> +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_intentout_optional_component_deallocateEa"} +! CHECK: %[[VAL_2:.*]] = fir.is_present %[[VAL_1]]#1 : (!fir.ref>}>>) -> i1 +! CHECK: fir.if %[[VAL_2]] { +! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_1]]#1 : (!fir.ref>}>>) -> !fir.box>}>> +! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.box>}>>) -> !fir.box +! CHECK: %[[VAL_5:.*]] = fir.call @_FortranADestroy(%[[VAL_4]]) fastmath : (!fir.box) -> none +! CHECK: }