[flang-commits] [flang] [flang][lowering] Implement component-wise initialization for derived types (PR #187465)

via flang-commits flang-commits at lists.llvm.org
Fri Apr 3 07:09:02 PDT 2026


================
@@ -812,6 +813,149 @@ mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) {
   return Fortran::lower::hasDefaultInitialization(sym);
 }
 
+/// Determines whether a derived type component requires non-trivial
+/// initialization. A component requires non-trivial initialization if it is an
+/// allocatable or pointer data component, or if it is a nested derived type
+/// that contains such components.
+static bool RequiresNonTrivialComponentInitialization(
+    const Fortran::semantics::Symbol &sym) {
+  const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
+  if (!declTy || !declTy->AsDerived())
+    return false;
+  const Fortran::semantics::DerivedTypeSpec &derivedSpec = *declTy->AsDerived();
+  const Fortran::semantics::Scope *scope = derivedSpec.GetScope();
+  assert(scope && "derived type has no scope");
+  const auto &typeDetails =
+      derivedSpec.typeSymbol().get<Fortran::semantics::DerivedTypeDetails>();
+
+  for (const auto &compName : typeDetails.componentNames()) {
+    auto iter = scope->find(compName);
+    assert(iter != scope->cend() && "component symbol not found in scope");
+    const Fortran::semantics::Symbol &compSym = iter->second.get();
+    const auto *objDetails =
+        compSym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
+    // If data component is an allocatable/pointer,
+    // or a nested derived type that requires initialization,
+    // return true.
+    if (objDetails && (Fortran::semantics::IsAllocatableOrPointer(compSym) ||
+                       RequiresNonTrivialComponentInitialization(compSym))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Performs component-wise initialization for \p derivedSpec,
+/// selectively generating IR only for components that require it.
+static void genDerivedTypeComponentInit(
+    Fortran::lower::AbstractConverter &converter, mlir::Location loc,
+    const Fortran::semantics::DerivedTypeSpec &derivedSpec,
+    mlir::Value baseAddr, fir::RecordType recTy) {
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  const Fortran::semantics::Scope *scope = derivedSpec.GetScope();
+  assert(scope && "derived type has no scope");
+  const auto &typeDetails =
+      derivedSpec.typeSymbol().get<Fortran::semantics::DerivedTypeDetails>();
+
+  for (const auto &compName : typeDetails.componentNames()) {
+    auto scopeIter = scope->find(compName);
+    assert(scopeIter != scope->cend() &&
+           "component name must exist in its scope");
+    const Fortran::semantics::Symbol &compSym = scopeIter->second.get();
+    // Only process data components; procedure pointers are ignored.
+    const auto *objDetails =
+        compSym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
+    if (!objDetails)
+      continue;
+
+    bool isPtrOrAlloc = Fortran::semantics::IsAllocatableOrPointer(compSym);
+    const Fortran::semantics::DeclTypeSpec *declTy = compSym.GetType();
+    bool isNestedDerived = declTy && declTy->AsDerived();
+    // Targets are pointer or allocatable components, or nested derived types
+    // containing them.
+    bool isTargetComponent =
+        isPtrOrAlloc ||
+        (isNestedDerived && RequiresNonTrivialComponentInitialization(compSym));
----------------
jeanPerier wrote:

Here you can replace `RequiresNonTrivialComponentInitialization` by `Fortran::lower::hasDefaultInitialization(comp)`, given the previous check this will be equivalent and will avoid having you defining the new RequiresNonTrivialComponentInitialization all together.

Also, the way this is done, there is a quadratic cost with the depth of the pointer/allocatable component given (`RequiresNonTrivialComponentInitialization`/`hasDefaultInitialization` has a cost at least linear with the depth of the pointer/alloc componenent and is called each time the recursion is descending into a subcomponent.).

I would suggest completely restructuring `genDerivedTypeComponentInit` to use the `UltimateComponentIterator` defined [here](https://github.com/llvm/llvm-project/blob/fd65b3ef7737ee06445088d5c716fc20a1776e2e/flang/include/flang/Semantics/tools.h#L514), to detect the POINTER/ALLOCTABLE components using `GetComponentPath` to generate the fir.coordinate_of (you can store the results of the intermediate  fir.coordinate_of into a small map using the symbols as keys to avoid regenerating them if the components have already been addressed).

This will have a cost linear with the derived type tree.

https://github.com/llvm/llvm-project/pull/187465


More information about the flang-commits mailing list