[flang] Assign sizes & offsets before instantiating some component types (#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 https://github.com/llvm/llvm-project/issues/178786.
This commit is contained in:
parent
6577aa54e8
commit
33cef35bfb
2 changed files with 99 additions and 8 deletions
|
|
@ -296,7 +296,8 @@ private:
|
|||
template <typename A> A Fold(A &&expr) {
|
||||
return evaluate::Fold(foldingContext(), std::move(expr));
|
||||
}
|
||||
void InstantiateComponent(const Symbol &);
|
||||
Symbol *BeginComponentInstantiation(const Symbol &);
|
||||
void CompleteComponentInstantiation(Symbol &);
|
||||
const DeclTypeSpec *InstantiateType(const Symbol &);
|
||||
const DeclTypeSpec &InstantiateIntrinsicType(
|
||||
SourceName, const DeclTypeSpec &);
|
||||
|
|
@ -319,12 +320,16 @@ static int PlumbPDTInstantiationDepth(const Scope *scope) {
|
|||
static void InstantiateNonPDTScope(Scope &typeScope, Scope &containingScope) {
|
||||
auto &context{containingScope.context()};
|
||||
auto &foldingContext{context.foldingContext()};
|
||||
std::set<DerivedTypeSpec *> deferred;
|
||||
for (auto &pair : typeScope) {
|
||||
Symbol &symbol{*pair.second};
|
||||
if (DeclTypeSpec * type{symbol.GetType()}) {
|
||||
if (DerivedTypeSpec * derived{type->AsDerived()}) {
|
||||
if (!(derived->IsForwardReferenced() &&
|
||||
IsAllocatableOrPointer(symbol))) {
|
||||
if (IsAllocatableOrPointer(symbol)) {
|
||||
if (!derived->IsForwardReferenced()) {
|
||||
deferred.insert(derived);
|
||||
}
|
||||
} else {
|
||||
derived->Instantiate(containingScope);
|
||||
}
|
||||
}
|
||||
|
|
@ -340,6 +345,9 @@ static void InstantiateNonPDTScope(Scope &typeScope, Scope &containingScope) {
|
|||
}
|
||||
}
|
||||
ComputeOffsets(context, typeScope);
|
||||
for (DerivedTypeSpec *derived : deferred) {
|
||||
derived->Instantiate(containingScope);
|
||||
}
|
||||
}
|
||||
|
||||
void DerivedTypeSpec::Instantiate(Scope &containingScope) {
|
||||
|
|
@ -441,10 +449,16 @@ void InstantiateHelper::InstantiateComponents(const Scope &fromScope) {
|
|||
// Instantiate symbols in declaration order; this ensures that
|
||||
// parent components and type parameters of ancestor types exist
|
||||
// by the time that they're needed.
|
||||
std::vector<Symbol *> newSymbols;
|
||||
for (SymbolRef ref : fromScope.GetSymbols()) {
|
||||
InstantiateComponent(*ref);
|
||||
if (Symbol * newSymbol{BeginComponentInstantiation(*ref)}) {
|
||||
newSymbols.emplace_back(newSymbol);
|
||||
}
|
||||
}
|
||||
ComputeOffsets(context(), scope_);
|
||||
for (Symbol *symbol : newSymbols) {
|
||||
CompleteComponentInstantiation(*symbol);
|
||||
}
|
||||
}
|
||||
|
||||
// Walks a parsed expression to prepare it for (re)analysis;
|
||||
|
|
@ -472,7 +486,8 @@ private:
|
|||
Scope &scope_;
|
||||
};
|
||||
|
||||
void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
|
||||
Symbol *InstantiateHelper::BeginComponentInstantiation(
|
||||
const Symbol &oldSymbol) {
|
||||
auto pair{scope_.try_emplace(
|
||||
oldSymbol.name(), oldSymbol.attrs(), common::Clone(oldSymbol.details()))};
|
||||
Symbol &newSymbol{*pair.first->second};
|
||||
|
|
@ -480,12 +495,14 @@ void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
|
|||
// Symbol was already present in the scope, which can only happen
|
||||
// in the case of type parameters.
|
||||
CHECK(oldSymbol.has<TypeParamDetails>());
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
newSymbol.flags() = oldSymbol.flags();
|
||||
if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) {
|
||||
if (const DeclTypeSpec * newType{InstantiateType(newSymbol)}) {
|
||||
details->ReplaceType(*newType);
|
||||
if (!IsAllocatableOrPointer(newSymbol)) {
|
||||
if (const DeclTypeSpec *newType{InstantiateType(newSymbol)}) {
|
||||
details->ReplaceType(*newType);
|
||||
}
|
||||
}
|
||||
for (ShapeSpec &dim : details->shape()) {
|
||||
if (dim.lbound().isExplicit()) {
|
||||
|
|
@ -533,6 +550,17 @@ void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return &newSymbol;
|
||||
}
|
||||
|
||||
void InstantiateHelper::CompleteComponentInstantiation(Symbol &newSymbol) {
|
||||
if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) {
|
||||
if (IsAllocatableOrPointer(newSymbol)) {
|
||||
if (const DeclTypeSpec *newType{InstantiateType(newSymbol)}) {
|
||||
details->ReplaceType(*newType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) {
|
||||
|
|
|
|||
63
flang/test/Semantics/bug178786.f90
Normal file
63
flang/test/Semantics/bug178786.f90
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
!RUN: %flang_fc1 -fdebug-dump-symbols %s 2>&1 | FileCheck %s
|
||||
!CHECK: DerivedType scope: b size=4048 alignment=8 instantiation of b sourceRange=62 bytes
|
||||
!CHECK: DerivedType scope: e size=4080 alignment=8 instantiation of e sourceRange=48 bytes
|
||||
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
|
||||
!CHECK: DerivedType scope: size=4080 alignment=8 instantiation of e(k=4_4) sourceRange=0 bytes
|
||||
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
|
||||
!CHECK: DerivedType scope: size=4080 alignment=8 instantiation of e(k=4_4) sourceRange=0 bytes
|
||||
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
|
||||
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
|
||||
!CHECK: DerivedType scope: size=4080 alignment=8 instantiation of e(k=4_4) sourceRange=0 bytes
|
||||
!CHECK: DerivedType scope: size=4048 alignment=8 instantiation of b(k=4_4) sourceRange=0 bytes
|
||||
|
||||
module noPDTs
|
||||
type :: b
|
||||
integer::d1
|
||||
type (e),allocatable::n
|
||||
integer::dd1(1000)
|
||||
end type
|
||||
type,extends(b) :: e
|
||||
integer::d2
|
||||
character(:),allocatable::c
|
||||
end type
|
||||
contains
|
||||
subroutine alloc(d)
|
||||
class (b),allocatable :: d
|
||||
allocate(e::d)
|
||||
end subroutine alloc
|
||||
subroutine s1
|
||||
class (b),allocatable :: v
|
||||
call alloc(v)
|
||||
deallocate(v)
|
||||
end
|
||||
end
|
||||
|
||||
module PDTs
|
||||
type :: b(k)
|
||||
integer, kind :: k
|
||||
integer(k)::d1
|
||||
type(e(k)),allocatable::n
|
||||
integer::dd1(1000)
|
||||
end type
|
||||
type,extends(b) :: e
|
||||
integer::d2
|
||||
character(:),allocatable::c
|
||||
end type
|
||||
contains
|
||||
subroutine alloc(d)
|
||||
class(b(kind(0))),allocatable :: d
|
||||
allocate(e(kind(0))::d)
|
||||
end subroutine alloc
|
||||
subroutine s2
|
||||
class(b(kind(0))),allocatable :: v
|
||||
call alloc(v)
|
||||
deallocate(v)
|
||||
end
|
||||
end
|
||||
|
||||
use noPDTS, only: s1
|
||||
use PDTS, only: s2
|
||||
call s1
|
||||
call s2
|
||||
print *, 'ok'
|
||||
end
|
||||
Loading…
Reference in a new issue