[flang-commits] [flang] [flang] Assign sizes & offsets before instantiating some component types (PR #178927)
via flang-commits
flang-commits at lists.llvm.org
Fri Jan 30 09:42:08 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Peter Klausler (klausler)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/178927.diff
2 Files Affected:
- (modified) flang/lib/Semantics/type.cpp (+36-8)
- (added) flang/test/Semantics/bug178786.f90 (+63)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/178927
More information about the flang-commits
mailing list