[flang-commits] [flang] [flang] Avoid exponential traversal in deep type extensions (PR #191955)

Sairudra More via flang-commits flang-commits at lists.llvm.org
Mon Apr 13 22:48:36 PDT 2026


https://github.com/Saieiei created https://github.com/llvm/llvm-project/pull/191955

HasDestruction() and IsFinalizable() walked component iterators that already descend into parent scopes, and then also recursed through derived-type components. With deep type extension chains, that caused the same inheritance structure to be traversed repeatedly and compile time to grow exponentially.

Iterate only over the current type scope instead. The scope contains the type's own components plus its parent component, so the existing recursion through derived-type components still handles inheritance without double traversal.

Add a regression test with a deep type extension hierarchy.

>From 7d76963b77e47f5c7da3dd37fab3a193dec0df64 Mon Sep 17 00:00:00 2001
From: Sairudra More <moresair at pe31.hpc.amslabs.hpecorp.net>
Date: Tue, 14 Apr 2026 00:15:54 -0500
Subject: [PATCH] [flang] Avoid exponential traversal in deep type extensions

HasDestruction() and IsFinalizable() walked component iterators that
already descend into parent scopes, and then also recursed through
derived-type components. With deep type extension chains, that caused
the same inheritance structure to be traversed repeatedly and compile
time to grow exponentially.

Iterate only over the current type scope instead. The scope contains
the type's own components plus its parent component, so the existing
recursion through derived-type components still handles inheritance
without double traversal.

Add a regression test with a deep type extension hierarchy.
---
 flang/lib/Semantics/tools.cpp         |  14 +--
 flang/lib/Semantics/type.cpp          |  15 ++--
 flang/test/Semantics/typesstress5.f90 | 125 ++++++++++++++++++++++++++
 3 files changed, 144 insertions(+), 10 deletions(-)
 create mode 100644 flang/test/Semantics/typesstress5.f90

diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index 68307f7504e28..2ff3bb70203af 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -772,7 +772,7 @@ const Symbol *IsFinalizable(const DerivedTypeSpec &derived,
   if (elemental && (!withImpureFinalizer || !IsPureProcedure(*elemental))) {
     return elemental;
   }
-  // Check components (including ancestors)
+  // Check components (including ancestors via parent component recursion)
   std::set<const DerivedTypeSpec *> basis;
   if (inProgress) {
     if (inProgress->find(&derived) != inProgress->end()) {
@@ -783,10 +783,14 @@ const Symbol *IsFinalizable(const DerivedTypeSpec &derived,
   }
   auto iterator{inProgress->insert(&derived).first};
   const Symbol *result{nullptr};
-  for (const Symbol &component : PotentialComponentIterator{derived}) {
-    result = IsFinalizable(component, inProgress, withImpureFinalizer);
-    if (result) {
-      break;
+  // Iterate only the type's own scope to avoid exponential traversal
+  // when combined with recursion through derived-type components.
+  if (const Scope *scope{derived.GetScope()}) {
+    for (const auto &[_, symbolRef] : *scope) {
+      result = IsFinalizable(*symbolRef, inProgress, withImpureFinalizer);
+      if (result) {
+        break;
+      }
     }
   }
   inProgress->erase(iterator);
diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index bb8fddbffd945..efda6bdffe2cf 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -238,11 +238,16 @@ bool DerivedTypeSpec::HasDestruction() const {
   if (!FinalsForDerivedTypeInstantiation(*this).empty()) {
     return true;
   }
-  DirectComponentIterator components{*this};
-  return bool{std::find_if(
-      components.begin(), components.end(), [&](const Symbol &component) {
-        return IsDestructible(component, &typeSymbol());
-      })};
+  const Scope *scope{GetScope()};
+  if (!scope) {
+    return false;
+  }
+  for (const auto &[_, symbolRef] : *scope) {
+    if (IsDestructible(*symbolRef, &typeSymbol())) {
+      return true;
+    }
+  }
+  return false;
 }
 
 ParamValue *DerivedTypeSpec::FindParameter(SourceName target) {
diff --git a/flang/test/Semantics/typesstress5.f90 b/flang/test/Semantics/typesstress5.f90
new file mode 100644
index 0000000000000..cac9722f17006
--- /dev/null
+++ b/flang/test/Semantics/typesstress5.f90
@@ -0,0 +1,125 @@
+! RUN: %flang_fc1 -fsyntax-only %s 2>&1
+! Regression test: deeply nested type extensions with LEN parameters
+! must not cause exponential compile time in HasDestruction().
+
+module m
+  implicit none
+  type :: extend1
+  end type extend1
+  type, extends(extend1) :: extend2(my8int2)
+    integer, len :: my8int2
+    complex :: mycomplex2
+  end type extend2
+  type, extends(extend2) :: extend3(my8int3)
+    integer, len :: my8int3
+    complex :: mycomplex3
+  end type extend3
+  type, extends(extend3) :: extend4(my8int4)
+    integer, len :: my8int4
+    complex :: mycomplex4
+  end type extend4
+  type, extends(extend4) :: extend5(my8int5)
+    integer, len :: my8int5
+    complex :: mycomplex5
+  end type extend5
+  type, extends(extend5) :: extend6(my8int6)
+    integer, len :: my8int6
+    complex :: mycomplex6
+  end type extend6
+  type, extends(extend6) :: extend7(my8int7)
+    integer, len :: my8int7
+    complex :: mycomplex7
+  end type extend7
+  type, extends(extend7) :: extend8(my8int8)
+    integer, len :: my8int8
+    complex :: mycomplex8
+  end type extend8
+  type, extends(extend8) :: extend9(my8int9)
+    integer, len :: my8int9
+    complex :: mycomplex9
+  end type extend9
+  type, extends(extend9) :: extend10(my8int10)
+    integer, len :: my8int10
+    complex :: mycomplex10
+  end type extend10
+  type, extends(extend10) :: extend11(my8int11)
+    integer, len :: my8int11
+    complex :: mycomplex11
+  end type extend11
+  type, extends(extend11) :: extend12(my8int12)
+    integer, len :: my8int12
+    complex :: mycomplex12
+  end type extend12
+  type, extends(extend12) :: extend13(my8int13)
+    integer, len :: my8int13
+    complex :: mycomplex13
+  end type extend13
+  type, extends(extend13) :: extend14(my8int14)
+    integer, len :: my8int14
+    complex :: mycomplex14
+  end type extend14
+  type, extends(extend14) :: extend15(my8int15)
+    integer, len :: my8int15
+    complex :: mycomplex15
+  end type extend15
+  type, extends(extend15) :: extend16(my8int16)
+    integer, len :: my8int16
+    complex :: mycomplex16
+  end type extend16
+  type, extends(extend16) :: extend17(my8int17)
+    integer, len :: my8int17
+    complex :: mycomplex17
+  end type extend17
+  type, extends(extend17) :: extend18(my8int18)
+    integer, len :: my8int18
+    complex :: mycomplex18
+  end type extend18
+  type, extends(extend18) :: extend19(my8int19)
+    integer, len :: my8int19
+    complex :: mycomplex19
+  end type extend19
+  type, extends(extend19) :: extend20(my8int20)
+    integer, len :: my8int20
+    complex :: mycomplex20
+  end type extend20
+  type, extends(extend20) :: extend21(my8int21)
+    integer, len :: my8int21
+    complex :: mycomplex21
+  end type extend21
+  type, extends(extend21) :: extend22(my8int22)
+    integer, len :: my8int22
+    complex :: mycomplex22
+  end type extend22
+  type, extends(extend22) :: extend23(my8int23)
+    integer, len :: my8int23
+    complex :: mycomplex23
+  end type extend23
+  type, extends(extend23) :: extend24(my8int24)
+    integer, len :: my8int24
+    complex :: mycomplex24
+  end type extend24
+  type, extends(extend24) :: extend25(my8int25)
+    integer, len :: my8int25
+    complex :: mycomplex25
+  end type extend25
+  type, extends(extend25) :: extend26(my8int26)
+    integer, len :: my8int26
+    complex :: mycomplex26
+  end type extend26
+  type, extends(extend26) :: extend27(my8int27)
+    integer, len :: my8int27
+    complex :: mycomplex27
+  end type extend27
+  type, extends(extend27) :: extend28(my8int28)
+    integer, len :: my8int28
+    complex :: mycomplex28
+  end type extend28
+  type, extends(extend28) :: extend29(my8int29)
+    integer, len :: my8int29
+    complex :: mycomplex29
+  end type extend29
+  type, extends(extend29) :: extend30(my8int30)
+    integer, len :: my8int30
+    complex :: mycomplex30
+  end type extend30
+end module m



More information about the flang-commits mailing list