[flang-commits] [flang] [flang] Assign sizes & offsets before instantiating some component types (PR #178927)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Fri Jan 30 09:41:38 PST 2026
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/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.
>From ebfd2764b721536695b74448a91bf0a71a451ecd Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Fri, 30 Jan 2026 09:31:29 -0800
Subject: [PATCH] [flang] Assign sizes & offsets before instantiating some
component types
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.
---
flang/lib/Semantics/type.cpp | 44 +++++++++++++++++----
flang/test/Semantics/bug178786.f90 | 63 ++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+), 8 deletions(-)
create mode 100644 flang/test/Semantics/bug178786.f90
diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index 038a402e54f96..5e711134bf778 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -296,7 +296,8 @@ class InstantiateHelper {
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::list<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 @@ class ResetHelper {
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) {
diff --git a/flang/test/Semantics/bug178786.f90 b/flang/test/Semantics/bug178786.f90
new file mode 100644
index 0000000000000..930b886a29987
--- /dev/null
+++ b/flang/test/Semantics/bug178786.f90
@@ -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
More information about the flang-commits
mailing list