diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -263,3 +263,69 @@ This Fortran 2008 feature might as well be viewed like an extension; no other compiler that we've tested can handle it yet. + +## Behavior in cases where the standard is ambiguous or indefinite + +* When an inner procedure of a subprogram uses the value or an attribute + of an undeclared name in a specification expression and that name does + not appear in the host, it is not clear in the standard whether that + name is an implicitly typed local variable of the inner procedure or a + host association with an implicitly typed local variable of the host. + For example: +``` +module module + contains + subroutine host(j) + ! Although "m" never appears in the specification or executable + ! parts of this subroutine, both of its contained subroutines + ! might be accessing it via host association. + integer, intent(in out) :: j + call inner1(j) + call inner2(j) + contains + subroutine inner1(n) + integer(kind(m)), intent(in) :: n + m = n + 1 + end subroutine + subroutine inner2(n) + integer(kind(m)), intent(out) :: n + n = m + 2 + end subroutine + end subroutine +end module + +program demo + use module + integer :: k + k = 0 + call host(k) + print *, k, " should be 3" +end + +``` + + Other Fortran compilers disagree in their interpretations of this example; + some seem to treat the references to `m` as if they were host associations + to an implicitly typed variable (and print `3`), while others seem to + treat them as references to implicitly typed local variabless, and + load uninitialized values. + + In f18, we chose to emit an error message for this case since the standard + is unclear, the usage is not portable, and the issue can be easily resolved + by adding a declaration. + +* In subclause 7.5.6.2 of Fortran 2018 the standard defines a partial ordering + of the final subroutine calls for finalizable objects, their non-parent + components, and then their parent components. + (The object is finalized, then the non-parent components of each element, + and then the parent component.) + Some have argued that the standard permits an implementation + to finalize the parent component before finalizing an allocatable component in + the context of deallocation, and the next revision of the language may codify + this option. + In the interest of avoiding needless confusion, this compiler implements what + we believe to be the least surprising order of finalization. + Specifically: all non-parent components are finalized before + the parent, allocatable or not; + all finalization takes place before any deallocation; + and no object or subobject will be finalized more than once. diff --git a/flang/runtime/derived.cpp b/flang/runtime/derived.cpp --- a/flang/runtime/derived.cpp +++ b/flang/runtime/derived.cpp @@ -208,8 +208,9 @@ } // The order of finalization follows Fortran 2018 7.5.6.2, with -// elementwise deallocation of non-parent components (and their consequent -// finalizations) taking place before parent component finalization. +// elementwise finalization of non-parent components taking place +// before parent component finalization, and with all finalization +// preceding any deallocation. void Destroy(const Descriptor &descriptor, bool finalize, const typeInfo::DerivedType &derived) { if (derived.noDestructionNeeded() || !descriptor.IsAllocated()) {