Index: flang/lib/Semantics/resolve-names.cpp =================================================================== --- flang/lib/Semantics/resolve-names.cpp +++ flang/lib/Semantics/resolve-names.cpp @@ -1089,6 +1089,9 @@ bool sequence{false}; // is a sequence type const Symbol *type{nullptr}; // derived type being defined bool isStructure{false}; // is a DEC STRUCTURE + std::vector> + delayedInstantiations; // We may have to delay instantiations of derived + // types to avoid cycles. } derivedTypeInfo_; // In a ProcedureDeclarationStmt or ProcComponentDefStmt, this is // the interface name, if any. @@ -5139,9 +5142,20 @@ // Direct recursive use of a type in the definition of one of its // components: defer instantiation } else { - auto restorer{ - GetFoldingContext().messages().SetLocation(currStmtSource().value())}; - derived.Instantiate(currScope()); + if (currScope().IsDerivedType() && + GetAttrs().HasAny({Attr::POINTER, Attr::ALLOCATABLE})) { + // We risk ourselves to instantiate via a cycle of forward references + // an incomplete class. Delay what we wanted to instantiate and + // do that at the end of the derived-type-def. + // This works because initializers of these data components are + // not allowed (ALLOCATABLE) or they are very limited (POINTER). + derivedTypeInfo_.delayedInstantiations.emplace_back( + currStmtSource().value(), &currScope(), &derived); + } else { + auto restorer{GetFoldingContext().messages().SetLocation( + currStmtSource().value())}; + derived.Instantiate(currScope()); + } } SetDeclTypeSpec(type); } @@ -5229,6 +5243,12 @@ } Walk(std::get>(x.t)); Walk(std::get>(x.t)); + // Instantiate delayed types now that the type has been fully checked. + for (auto [source, scope, derivedTypeSpec] : + derivedTypeInfo_.delayedInstantiations) { + auto restorer{GetFoldingContext().messages().SetLocation(source)}; + derivedTypeSpec->Instantiate(*scope); + } derivedTypeInfo_ = {}; PopScope(); return false; Index: flang/test/Semantics/typeinfo05.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/typeinfo05.f90 @@ -0,0 +1,16 @@ +!RUN: bbc --dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s +! Ensure that cycles via POINTERs do not instantiate incomplete derived +! types that would lead to types whose sizeinbytes=0 +program main + implicit none + type t1 + type(t2), pointer :: b + end type t1 +!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) + type :: t2 + type(t1), pointer :: a + end type t2 +! CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1) +end program main + Index: flang/test/Semantics/typeinfo06.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/typeinfo06.f90 @@ -0,0 +1,16 @@ +!RUN: bbc --dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s +! Ensure that cycles via ALLOCATABLEs do not instantiate incomplete derived +! types that would lead to types whose sizeinbytes=0 +program main + implicit none + type t1 + type(t2), allocatable :: b + end type t1 +!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1) + type :: t2 + type(t1), allocatable :: a + end type t2 +! CHECK: .dt.t2, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t2,sizeinbytes=40_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1) +end program main +