Skip to content

Commit 33cef35

Browse files
authored
[flang] Assign sizes & offsets before instantiating some component types (llvm#178927)
Semantics is instantiating derived types too soon is some cases, leading to incorrect sizes and component offsets in cases of valid forward references to derived types -- these appear in the declarations of allocatable and pointer components. The incorrect size led to a runtime crash in the linked bug report after an insufficient allocation. Since those components are indirect, their sizes in the derived type instantiation can be known without having to recursive instantiate the components' types. Then, after laying out the derived type instantiation, the compiler can then ensure that the components' types are instantiated. Fixes llvm#178786.
1 parent 6577aa5 commit 33cef35

2 files changed

Lines changed: 99 additions & 8 deletions

File tree

flang/lib/Semantics/type.cpp

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ class InstantiateHelper {
296296
template <typename A> A Fold(A &&expr) {
297297
return evaluate::Fold(foldingContext(), std::move(expr));
298298
}
299-
void InstantiateComponent(const Symbol &);
299+
Symbol *BeginComponentInstantiation(const Symbol &);
300+
void CompleteComponentInstantiation(Symbol &);
300301
const DeclTypeSpec *InstantiateType(const Symbol &);
301302
const DeclTypeSpec &InstantiateIntrinsicType(
302303
SourceName, const DeclTypeSpec &);
@@ -319,12 +320,16 @@ static int PlumbPDTInstantiationDepth(const Scope *scope) {
319320
static void InstantiateNonPDTScope(Scope &typeScope, Scope &containingScope) {
320321
auto &context{containingScope.context()};
321322
auto &foldingContext{context.foldingContext()};
323+
std::set<DerivedTypeSpec *> deferred;
322324
for (auto &pair : typeScope) {
323325
Symbol &symbol{*pair.second};
324326
if (DeclTypeSpec * type{symbol.GetType()}) {
325327
if (DerivedTypeSpec * derived{type->AsDerived()}) {
326-
if (!(derived->IsForwardReferenced() &&
327-
IsAllocatableOrPointer(symbol))) {
328+
if (IsAllocatableOrPointer(symbol)) {
329+
if (!derived->IsForwardReferenced()) {
330+
deferred.insert(derived);
331+
}
332+
} else {
328333
derived->Instantiate(containingScope);
329334
}
330335
}
@@ -340,6 +345,9 @@ static void InstantiateNonPDTScope(Scope &typeScope, Scope &containingScope) {
340345
}
341346
}
342347
ComputeOffsets(context, typeScope);
348+
for (DerivedTypeSpec *derived : deferred) {
349+
derived->Instantiate(containingScope);
350+
}
343351
}
344352

345353
void DerivedTypeSpec::Instantiate(Scope &containingScope) {
@@ -441,10 +449,16 @@ void InstantiateHelper::InstantiateComponents(const Scope &fromScope) {
441449
// Instantiate symbols in declaration order; this ensures that
442450
// parent components and type parameters of ancestor types exist
443451
// by the time that they're needed.
452+
std::vector<Symbol *> newSymbols;
444453
for (SymbolRef ref : fromScope.GetSymbols()) {
445-
InstantiateComponent(*ref);
454+
if (Symbol * newSymbol{BeginComponentInstantiation(*ref)}) {
455+
newSymbols.emplace_back(newSymbol);
456+
}
446457
}
447458
ComputeOffsets(context(), scope_);
459+
for (Symbol *symbol : newSymbols) {
460+
CompleteComponentInstantiation(*symbol);
461+
}
448462
}
449463

450464
// Walks a parsed expression to prepare it for (re)analysis;
@@ -472,20 +486,23 @@ class ResetHelper {
472486
Scope &scope_;
473487
};
474488

475-
void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
489+
Symbol *InstantiateHelper::BeginComponentInstantiation(
490+
const Symbol &oldSymbol) {
476491
auto pair{scope_.try_emplace(
477492
oldSymbol.name(), oldSymbol.attrs(), common::Clone(oldSymbol.details()))};
478493
Symbol &newSymbol{*pair.first->second};
479494
if (!pair.second) {
480495
// Symbol was already present in the scope, which can only happen
481496
// in the case of type parameters.
482497
CHECK(oldSymbol.has<TypeParamDetails>());
483-
return;
498+
return nullptr;
484499
}
485500
newSymbol.flags() = oldSymbol.flags();
486501
if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) {
487-
if (const DeclTypeSpec * newType{InstantiateType(newSymbol)}) {
488-
details->ReplaceType(*newType);
502+
if (!IsAllocatableOrPointer(newSymbol)) {
503+
if (const DeclTypeSpec *newType{InstantiateType(newSymbol)}) {
504+
details->ReplaceType(*newType);
505+
}
489506
}
490507
for (ShapeSpec &dim : details->shape()) {
491508
if (dim.lbound().isExplicit()) {
@@ -533,6 +550,17 @@ void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
533550
}
534551
}
535552
}
553+
return &newSymbol;
554+
}
555+
556+
void InstantiateHelper::CompleteComponentInstantiation(Symbol &newSymbol) {
557+
if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) {
558+
if (IsAllocatableOrPointer(newSymbol)) {
559+
if (const DeclTypeSpec *newType{InstantiateType(newSymbol)}) {
560+
details->ReplaceType(*newType);
561+
}
562+
}
563+
}
536564
}
537565

538566
const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) {

flang/test/Semantics/bug178786.f90

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
!RUN: %flang_fc1 -fdebug-dump-symbols %s 2>&1 | FileCheck %s
2+
!CHECK: DerivedType scope: b size=4048 alignment=8 instantiation of b sourceRange=62 bytes
3+
!CHECK: DerivedType scope: e size=4080 alignment=8 instantiation of e sourceRange=48 bytes
4+
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
5+
!CHECK: DerivedType scope: size=4080 alignment=8 instantiation of e(k=4_4) sourceRange=0 bytes
6+
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
7+
!CHECK: DerivedType scope: size=4080 alignment=8 instantiation of e(k=4_4) sourceRange=0 bytes
8+
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
9+
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
10+
!CHECK: DerivedType scope: size=4080 alignment=8 instantiation of e(k=4_4) sourceRange=0 bytes
11+
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
12+
13+
module noPDTs
14+
type :: b
15+
integer::d1
16+
type (e),allocatable::n
17+
integer::dd1(1000)
18+
end type
19+
type,extends(b) :: e
20+
integer::d2
21+
character(:),allocatable::c
22+
end type
23+
contains
24+
subroutine alloc(d)
25+
class (b),allocatable :: d
26+
allocate(e::d)
27+
end subroutine alloc
28+
subroutine s1
29+
class (b),allocatable :: v
30+
call alloc(v)
31+
deallocate(v)
32+
end
33+
end
34+
35+
module PDTs
36+
type :: b(k)
37+
integer, kind :: k
38+
integer(k)::d1
39+
type(e(k)),allocatable::n
40+
integer::dd1(1000)
41+
end type
42+
type,extends(b) :: e
43+
integer::d2
44+
character(:),allocatable::c
45+
end type
46+
contains
47+
subroutine alloc(d)
48+
class(b(kind(0))),allocatable :: d
49+
allocate(e(kind(0))::d)
50+
end subroutine alloc
51+
subroutine s2
52+
class(b(kind(0))),allocatable :: v
53+
call alloc(v)
54+
deallocate(v)
55+
end
56+
end
57+
58+
use noPDTS, only: s1
59+
use PDTS, only: s2
60+
call s1
61+
call s2
62+
print *, 'ok'
63+
end

0 commit comments

Comments
 (0)