Skip to content

Commit 996c0fb

Browse files
committed
[flang] Avoid cycles during instantiation of derived types
Derived-type-spec (such as `type(t)`) typically cause the instantiation of a class which is also used to define the offsets of its data components and the size of the class. Fortran derived types are always "completely" defined (i.e., no incomplete / opaque derived types exist on which we can build a pointer to them like in C/C++) so they can have their offsets always computed. However, we must be careful not to instantiate a derived type while it is being defined. This can happen due to cycles introduced by forward references, such as the one below. ```lang=fortran type t1 type(t2), pointer :: b ! (A) end type t1 type :: t2 ! (B) type(t1), pointer :: a ! (C) end type t2 ! (D) ``` At `(A)`, flang determines that this is a forward declaration so no instantiation happens. At `(B)`, flang determines `t2` is not a forward declaration anymore, because we are defining it. At `(C)`, flang chooses to instantiate `t1`. Instantiation of `t1` finds the field `b` at `(A)`. Now `t2` is not a forward declaration anymore, so it can be instantiated. But at this point the field `a` has not been added to `t2`, so we compute the size of an empty class. Because this computation is done just once, we end emitting a wrong derived type descriptor with a `sizeinbytes` field set to 0. Because these kind of cycles can only happen via forward referenced derived types specifiers, the idea here is to avoid instantiating the derived type being defined (i.e. `t2`) until `(D)`. Keeping the attribute "is forward reference" set until `(D)` avoids that. Fixes #64973 Differential Revision: https://reviews.llvm.org/D159117
1 parent 1778d68 commit 996c0fb

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5189,7 +5189,6 @@ bool DeclarationVisitor::Pre(const parser::DerivedTypeDef &x) {
51895189
CHECK(scope.symbol());
51905190
CHECK(scope.symbol()->scope() == &scope);
51915191
auto &details{scope.symbol()->get<DerivedTypeDetails>()};
5192-
details.set_isForwardReferenced(false);
51935192
std::set<SourceName> paramNames;
51945193
for (auto &paramName : std::get<std::list<parser::Name>>(stmt.statement.t)) {
51955194
details.add_paramName(paramName.source);
@@ -5242,6 +5241,7 @@ bool DeclarationVisitor::Pre(const parser::DerivedTypeDef &x) {
52425241
}
52435242
Walk(std::get<std::optional<parser::TypeBoundProcedurePart>>(x.t));
52445243
Walk(std::get<parser::Statement<parser::EndTypeStmt>>(x.t));
5244+
details.set_isForwardReferenced(false);
52455245
derivedTypeInfo_ = {};
52465246
PopScope();
52475247
return false;
@@ -5257,7 +5257,13 @@ void DeclarationVisitor::Post(const parser::DerivedTypeStmt &x) {
52575257
auto *extendsName{derivedTypeInfo_.extends};
52585258
std::optional<DerivedTypeSpec> extendsType{
52595259
ResolveExtendsType(name, extendsName)};
5260-
auto &symbol{MakeSymbol(name, GetAttrs(), DerivedTypeDetails{})};
5260+
DerivedTypeDetails derivedTypeDetails;
5261+
if (Symbol *typeSymbol{FindInScope(currScope(), name)}; typeSymbol &&
5262+
typeSymbol->has<DerivedTypeDetails>() &&
5263+
typeSymbol->get<DerivedTypeDetails>().isForwardReferenced()) {
5264+
derivedTypeDetails.set_isForwardReferenced(true);
5265+
}
5266+
auto &symbol{MakeSymbol(name, GetAttrs(), std::move(derivedTypeDetails))};
52615267
symbol.ReplaceName(name.source);
52625268
derivedTypeInfo_.type = &symbol;
52635269
PushScope(Scope::Kind::DerivedType, &symbol);

flang/test/Semantics/typeinfo05.f90

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
!RUN: bbc --dump-symbols %s | FileCheck %s
2+
!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s
3+
! Ensure that cycles via POINTERs do not instantiate incomplete derived
4+
! types that would lead to types whose sizeinbytes=0
5+
program main
6+
implicit none
7+
type t1
8+
type(t2), pointer :: b
9+
end type t1
10+
!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)
11+
type :: t2
12+
type(t1) :: a
13+
end type t2
14+
! 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)
15+
end program main
16+

flang/test/Semantics/typeinfo06.f90

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
!RUN: bbc --dump-symbols %s | FileCheck %s
2+
!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s
3+
! Ensure that cycles via ALLOCATABLEs do not instantiate incomplete derived
4+
! types that would lead to types whose sizeinbytes=0
5+
program main
6+
implicit none
7+
type t1
8+
type(t2), allocatable :: b
9+
end type t1
10+
!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)
11+
type :: t2
12+
type(t1) :: a
13+
end type t2
14+
! 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)
15+
end program main
16+

0 commit comments

Comments
 (0)