diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index baecfd7c48fd06..697bd131c04c7a 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -706,6 +706,21 @@ end `INDEX` include an optional `BACK=` argument, but it doesn't actually work. +* Allocatable components of array and structure constructors are deallocated + after use without calling final subroutines. + The standard does not specify when and how deallocation of array and structure + constructors allocatable components should happen. All compilers free the + memory after use, but the behavior when the allocatable component is a derived + type with finalization differ, especially when dealing with nested array and + structure constructors expressions. Some compilers call final routine for the + allocatable components of each constructor sub-expressions, some call it only + for the allocatable component of the top level constructor, and some only + deallocate the memory. Deallocating only the memory offers the most + flexibility when lowering such expressions, and it is not clear finalization + is desirable in such context (Fortran interop 1.6.2 in F2018 standards require + array and structure constructors not to be finalized, so it also makes sense + not to finalize their allocatable components when releasing their storage). + ## De Facto Standard Features * `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index 68ecaa19d2d5d1..731c5072c45c58 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -1844,6 +1844,16 @@ class HlfirBuilder { builder.genIfThen(loc, isAlloc).genThen(genAssign).end(); } + if (fir::isRecordWithAllocatableMember(recTy)) { + // Deallocate allocatable components without calling final subroutines. + // The Fortran 2018 section 9.7.3.2 about deallocation is not ruling + // about the fate of allocatable components of structure constructors, + // and there is no behavior consensus in other compilers. + fir::FirOpBuilder *bldr = &builder; + getStmtCtx().attachCleanup([=]() { + fir::runtime::genDerivedTypeDestroyWithoutFinalization(*bldr, loc, box); + }); + } return varOp; } diff --git a/flang/test/Lower/HLFIR/structure-constructor.f90 b/flang/test/Lower/HLFIR/structure-constructor.f90 index ff0c27f274f32a..d02427d2ff671a 100644 --- a/flang/test/Lower/HLFIR/structure-constructor.f90 +++ b/flang/test/Lower/HLFIR/structure-constructor.f90 @@ -161,6 +161,8 @@ end subroutine test4 ! CHECK: hlfir.assign %[[VAL_26]] to %[[VAL_20]] realloc keep_lhs_len temporary_lhs : !fir.box>>>, !fir.ref>>>> ! CHECK: } ! CHECK: hlfir.assign %[[VAL_12]]#0 to %[[VAL_3]]#0 : !fir.ref>>>}>>, !fir.ref>>>}>> +! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_13]] : (!fir.box>>>}>>) -> !fir.box +! CHECK: fir.call @_FortranADestroyWithoutFinalization(%[[VAL_27]] ! CHECK: return ! CHECK: } @@ -201,6 +203,8 @@ end subroutine test5 ! CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_18]] realloc temporary_lhs : !fir.box>>>}>>>>, !fir.ref>>>}>>>>> ! CHECK: } ! CHECK: hlfir.assign %[[VAL_11]]#0 to %[[VAL_3]]#0 : !fir.ref>>>}>>>>}>>, !fir.ref>>>}>>>>}>> +! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_12]] : (!fir.box>>>}>>>>}>>) -> !fir.box +! CHECK: fir.call @_FortranADestroyWithoutFinalization(%[[VAL_24]] ! CHECK: return ! CHECK: } @@ -291,6 +295,10 @@ end subroutine test6 ! CHECK: %[[VAL_70:.*]] = hlfir.as_expr %[[VAL_48]]#0 move %[[VAL_69]] : (!fir.heap}>>>, i1) -> !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>> ! CHECK: hlfir.assign %[[VAL_70]] to %[[VAL_44]] temporary_lhs : !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref}>>> ! CHECK: hlfir.assign %[[VAL_20]]#0 to %[[VAL_12]]#0 : !fir.ref>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>> +! CHECK: %[[VAL_71:.*]] = fir.convert %[[VAL_21]] : (!fir.box>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box +! CHECK: fir.call @_FortranADestroyWithoutFinalization(%[[VAL_71]] +! CHECK: %[[VAL_72:.*]] = fir.convert %[[VAL_29]] : (!fir.box>>>}>>>>}>>) -> !fir.box +! CHECK: fir.call @_FortranADestroyWithoutFinalization(%[[VAL_72]] ! CHECK: return ! CHECK: } @@ -375,6 +383,8 @@ end subroutine test8 ! CHECK: hlfir.assign %[[VAL_29]] to %[[VAL_22]] realloc keep_lhs_len temporary_lhs : !fir.heap>, !fir.ref>>> ! CHECK: } ! CHECK: hlfir.assign %[[VAL_14]]#0 to %[[VAL_2]]#0 : !fir.ref>>}>>, !fir.ref>>}>> +! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_15]] : (!fir.box>>}>>) -> !fir.box +! CHECK: fir.call @_FortranADestroyWithoutFinalization(%[[VAL_30]] ! CHECK: return ! CHECK: } @@ -410,6 +420,8 @@ end subroutine test9 ! CHECK: %[[VAL_20:.*]] = hlfir.designate %[[VAL_12]]#0{"c"} typeparams %[[VAL_19]] {fortran_attrs = #fir.var_attrs} : (!fir.ref>>}>>, index) -> !fir.ref>>> ! CHECK: hlfir.assign %[[VAL_11]]#0 to %[[VAL_20]] realloc keep_lhs_len temporary_lhs : !fir.ref>, !fir.ref>>> ! CHECK: hlfir.assign %[[VAL_12]]#0 to %[[VAL_2]]#0 : !fir.ref>>}>>, !fir.ref>>}>> +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_13]] : (!fir.box>>}>>) -> !fir.box +! CHECK: fir.call @_FortranADestroyWithoutFinalization(%[[VAL_21]] ! CHECK: return ! CHECK: }