[flang-commits] [flang] [flang][hlfir] Make the parent type the first component (PR #69348)

via flang-commits flang-commits at lists.llvm.org
Fri Oct 20 02:13:26 PDT 2023


https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/69348

>From 1422677a11fb430c8b9e9dfd255d6a2c1102b2a5 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Tue, 17 Oct 2023 03:22:26 -0700
Subject: [PATCH 1/3] [flang][hlfir] Make parent type the first component

Type extension is currently handled in FIR by inlining the parents
components as the first member of the record type.

This is not correct from a memory layout point of view since the
storage size of the parent type may be bigger than the sum of the
size of its component (due to alignment requirement). To avoid
making FIR types target dependent and fix this issue, make the parent
component a single component with the parent type at the beginning of
the record type.

This also simplifies addressing since parent component is now a "normal"
component that can be designated with hlfir.designate.

StructureComponent lowering however is a bit more complex since the
symbols in the structure component may refer to subcomponents of parent
types.
---
 flang/include/flang/Lower/ConvertType.h       |  30 +++
 flang/include/flang/Semantics/tools.h         |   2 +-
 flang/include/flang/Semantics/type.h          |   2 +
 flang/lib/Lower/ConvertConstant.cpp           | 210 ++++++++++++------
 flang/lib/Lower/ConvertExprToHLFIR.cpp        | 132 +++++------
 flang/lib/Lower/ConvertType.cpp               |  90 ++++++--
 flang/lib/Lower/ConvertVariable.cpp           | 155 ++++++++-----
 flang/lib/Semantics/type.cpp                  |   4 +
 .../calls-constant-expr-arg-polymorphic.f90   |  10 +-
 .../local-end-of-scope-component-dealloc.f90  |  12 +-
 .../test/Lower/HLFIR/parent-component-ref.f90 |  39 ++--
 flang/test/Lower/HLFIR/private-components.f90 |   4 +-
 .../Lower/HLFIR/structure-constructor.f90     |  37 ++-
 .../Lower/HLFIR/type-bound-call-mismatch.f90  |   4 +-
 flang/test/Lower/HLFIR/type-info.f90          |   8 +-
 15 files changed, 452 insertions(+), 287 deletions(-)

diff --git a/flang/include/flang/Lower/ConvertType.h b/flang/include/flang/Lower/ConvertType.h
index f86cc0023579c43..61cbc7d7aa303cc 100644
--- a/flang/include/flang/Lower/ConvertType.h
+++ b/flang/include/flang/Lower/ConvertType.h
@@ -48,6 +48,8 @@ struct SomeType;
 namespace semantics {
 class Symbol;
 class DerivedTypeSpec;
+class DerivedTypeDetails;
+class Scope;
 } // namespace semantics
 
 namespace lower {
@@ -97,6 +99,34 @@ class TypeBuilder {
 using namespace evaluate;
 FOR_EACH_SPECIFIC_TYPE(extern template class TypeBuilder, )
 
+/// A helper class to reverse iterate through the component names of a derived
+/// type, including the parent component and the component of the parents. This
+/// is useful to deal with StructureConstructor lowering.
+class ComponentReverseIterator {
+public:
+  ComponentReverseIterator(const Fortran::semantics::DerivedTypeSpec &derived) {
+    setCurrentType(derived);
+  }
+  /// Does the current type has a component with \name (does not look-up the
+  /// components of the parent if any). If there is a match, the iterator
+  /// is advanced to the search result.
+  bool lookup(const Fortran::parser::CharBlock &name) {
+    componentIt = std::find(componentIt, componentItEnd, name);
+    return componentIt != componentItEnd;
+  };
+
+  /// Advance iterator to the last components of the current type parent.
+  const Fortran::semantics::DerivedTypeSpec &advanceToParentType();
+
+private:
+  void setCurrentType(const Fortran::semantics::DerivedTypeSpec &derived);
+  const Fortran::semantics::DerivedTypeSpec *currentParentType = nullptr;
+  const Fortran::semantics::DerivedTypeDetails *currentTypeDetails = nullptr;
+  using name_iterator =
+      std::list<Fortran::parser::CharBlock>::const_reverse_iterator;
+  name_iterator componentIt{};
+  name_iterator componentItEnd{};
+};
 } // namespace lower
 } // namespace Fortran
 
diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 0b5c3dde2e72082..e3deb2da1be04ab 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -509,7 +509,7 @@ template <ComponentKind componentKind> class ComponentIterator {
       explicit ComponentPathNode(const DerivedTypeSpec &derived)
           : derived_{derived} {
         if constexpr (componentKind == ComponentKind::Scope) {
-          const Scope &scope{DEREF(derived.scope())};
+          const Scope &scope{DEREF(derived.GetScope())};
           nameIterator_ = scope.cbegin();
           nameEnd_ = scope.cend();
         } else {
diff --git a/flang/include/flang/Semantics/type.h b/flang/include/flang/Semantics/type.h
index 5228c15066f6f39..8965d29d8889dad 100644
--- a/flang/include/flang/Semantics/type.h
+++ b/flang/include/flang/Semantics/type.h
@@ -261,6 +261,8 @@ class DerivedTypeSpec {
   const SourceName &name() const { return name_; }
   const Symbol &typeSymbol() const { return typeSymbol_; }
   const Scope *scope() const { return scope_; }
+  // Return scope_ if it is set, or the typeSymbol_ scope otherwise.
+  const Scope *GetScope() const;
   void set_scope(const Scope &);
   void ReplaceScope(const Scope &);
   const RawParameters &rawParameters() const { return rawParameters_; }
diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp
index 6e7a60e42abfe66..c935c90121941f3 100644
--- a/flang/lib/Lower/ConvertConstant.cpp
+++ b/flang/lib/Lower/ConvertConstant.cpp
@@ -347,6 +347,83 @@ genConstantValue(Fortran::lower::AbstractConverter &converter,
                  mlir::Location loc,
                  const Fortran::lower::SomeExpr &constantExpr);
 
+static mlir::Value genStructureComponentInit(
+    Fortran::lower::AbstractConverter &converter, mlir::Location loc,
+    const Fortran::semantics::Symbol &sym, const Fortran::lower::SomeExpr &expr,
+    mlir::Value res) {
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  fir::RecordType recTy = mlir::cast<fir::RecordType>(res.getType());
+  std::string name = converter.getRecordTypeFieldName(sym);
+  mlir::Type componentTy = recTy.getType(name);
+  auto fieldTy = fir::FieldType::get(recTy.getContext());
+  assert(componentTy && "failed to retrieve component");
+  // FIXME: type parameters must come from the derived-type-spec
+  auto field = builder.create<fir::FieldIndexOp>(
+      loc, fieldTy, name, recTy,
+      /*typeParams=*/mlir::ValueRange{} /*TODO*/);
+
+  if (Fortran::semantics::IsAllocatable(sym))
+    TODO(loc, "allocatable component in structure constructor");
+
+  if (Fortran::semantics::IsPointer(sym)) {
+    mlir::Value initialTarget =
+        Fortran::lower::genInitialDataTarget(converter, loc, componentTy, expr);
+    res = builder.create<fir::InsertValueOp>(
+        loc, recTy, res, initialTarget,
+        builder.getArrayAttr(field.getAttributes()));
+    return res;
+  }
+
+  if (Fortran::lower::isDerivedTypeWithLenParameters(sym))
+    TODO(loc, "component with length parameters in structure constructor");
+
+  // Special handling for scalar c_ptr/c_funptr constants. The array constant
+  // must fall through to genConstantValue() below.
+  if (Fortran::semantics::IsBuiltinCPtr(sym) && sym.Rank() == 0 &&
+      (Fortran::evaluate::GetLastSymbol(expr) ||
+       Fortran::evaluate::IsNullPointer(expr))) {
+    // Builtin c_ptr and c_funptr have special handling because designators
+    // and NULL() are handled as initial values for them as an extension
+    // (otherwise only c_ptr_null/c_funptr_null are allowed and these are
+    // replaced by structure constructors by semantics, so GetLastSymbol
+    // returns nothing).
+
+    // The Ev::Expr is an initializer that is a pointer target (e.g., 'x' or
+    // NULL()) that must be inserted into an intermediate cptr record value's
+    // address field, which ought to be an intptr_t on the target.
+    mlir::Value addr = fir::getBase(
+        Fortran::lower::genExtAddrInInitializer(converter, loc, expr));
+    if (addr.getType().isa<fir::BoxProcType>())
+      addr = builder.create<fir::BoxAddrOp>(loc, addr);
+    assert((fir::isa_ref_type(addr.getType()) ||
+            addr.getType().isa<mlir::FunctionType>()) &&
+           "expect reference type for address field");
+    assert(fir::isa_derived(componentTy) &&
+           "expect C_PTR, C_FUNPTR to be a record");
+    auto cPtrRecTy = componentTy.cast<fir::RecordType>();
+    llvm::StringRef addrFieldName = Fortran::lower::builtin::cptrFieldName;
+    mlir::Type addrFieldTy = cPtrRecTy.getType(addrFieldName);
+    auto addrField = builder.create<fir::FieldIndexOp>(
+        loc, fieldTy, addrFieldName, componentTy,
+        /*typeParams=*/mlir::ValueRange{});
+    mlir::Value castAddr = builder.createConvert(loc, addrFieldTy, addr);
+    auto undef = builder.create<fir::UndefOp>(loc, componentTy);
+    addr = builder.create<fir::InsertValueOp>(
+        loc, componentTy, undef, castAddr,
+        builder.getArrayAttr(addrField.getAttributes()));
+    res = builder.create<fir::InsertValueOp>(
+        loc, recTy, res, addr, builder.getArrayAttr(field.getAttributes()));
+    return res;
+  }
+
+  mlir::Value val = fir::getBase(genConstantValue(converter, loc, expr));
+  assert(!fir::isa_ref_type(val.getType()) && "expecting a constant value");
+  mlir::Value castVal = builder.createConvert(loc, componentTy, val);
+  res = builder.create<fir::InsertValueOp>(
+      loc, recTy, res, castVal, builder.getArrayAttr(field.getAttributes()));
+  return res;
+}
+
 // Generate a StructureConstructor inlined (returns raw fir.type<T> value,
 // not the address of a global constant).
 static mlir::Value genInlinedStructureCtorLitImpl(
@@ -354,84 +431,75 @@ static mlir::Value genInlinedStructureCtorLitImpl(
     const Fortran::evaluate::StructureConstructor &ctor, mlir::Type type) {
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   auto recTy = type.cast<fir::RecordType>();
-  auto fieldTy = fir::FieldType::get(type.getContext());
-  mlir::Value res = builder.create<fir::UndefOp>(loc, recTy);
-
-  for (const auto &[sym, expr] : ctor.values()) {
-    // Parent components need more work because they do not appear in the
-    // fir.rec type.
-    if (sym->test(Fortran::semantics::Symbol::Flag::ParentComp))
-      TODO(loc, "parent component in structure constructor");
-
-    std::string name = converter.getRecordTypeFieldName(sym);
-    mlir::Type componentTy = recTy.getType(name);
-    assert(componentTy && "failed to retrieve component");
-    // FIXME: type parameters must come from the derived-type-spec
-    auto field = builder.create<fir::FieldIndexOp>(
-        loc, fieldTy, name, type,
-        /*typeParams=*/mlir::ValueRange{} /*TODO*/);
 
-    if (Fortran::semantics::IsAllocatable(sym))
-      TODO(loc, "allocatable component in structure constructor");
-
-    if (Fortran::semantics::IsPointer(sym)) {
-      mlir::Value initialTarget = Fortran::lower::genInitialDataTarget(
-          converter, loc, componentTy, expr.value());
-      res = builder.create<fir::InsertValueOp>(
-          loc, recTy, res, initialTarget,
-          builder.getArrayAttr(field.getAttributes()));
-      continue;
+  if (!converter.getLoweringOptions().getLowerToHighLevelFIR()) {
+    mlir::Value res = builder.create<fir::UndefOp>(loc, recTy);
+    for (const auto &[sym, expr] : ctor.values()) {
+      // Parent components need more work because they do not appear in the
+      // fir.rec type.
+      if (sym->test(Fortran::semantics::Symbol::Flag::ParentComp))
+        TODO(loc, "parent component in structure constructor");
+      res = genStructureComponentInit(converter, loc, sym, expr.value(), res);
     }
+    return res;
+  }
 
-    if (Fortran::lower::isDerivedTypeWithLenParameters(sym))
-      TODO(loc, "component with length parameters in structure constructor");
-
-    // Special handling for scalar c_ptr/c_funptr constants. The array constant
-    // must fall through to genConstantValue() below.
-    if (Fortran::semantics::IsBuiltinCPtr(sym) && sym->Rank() == 0 &&
-        (Fortran::evaluate::GetLastSymbol(expr.value()) ||
-         Fortran::evaluate::IsNullPointer(expr.value()))) {
-      // Builtin c_ptr and c_funptr have special handling because designators
-      // and NULL() are handled as initial values for them as an extension
-      // (otherwise only c_ptr_null/c_funptr_null are allowed and these are
-      // replaced by structure constructors by semantics, so GetLastSymbol
-      // returns nothing).
-
-      // The Ev::Expr is an initializer that is a pointer target (e.g., 'x' or
-      // NULL()) that must be inserted into an intermediate cptr record value's
-      // address field, which ought to be an intptr_t on the target.
-      mlir::Value addr = fir::getBase(Fortran::lower::genExtAddrInInitializer(
-          converter, loc, expr.value()));
-      if (addr.getType().isa<fir::BoxProcType>())
-        addr = builder.create<fir::BoxAddrOp>(loc, addr);
-      assert((fir::isa_ref_type(addr.getType()) ||
-              addr.getType().isa<mlir::FunctionType>()) &&
-             "expect reference type for address field");
-      assert(fir::isa_derived(componentTy) &&
-             "expect C_PTR, C_FUNPTR to be a record");
-      auto cPtrRecTy = componentTy.cast<fir::RecordType>();
-      llvm::StringRef addrFieldName = Fortran::lower::builtin::cptrFieldName;
-      mlir::Type addrFieldTy = cPtrRecTy.getType(addrFieldName);
-      auto addrField = builder.create<fir::FieldIndexOp>(
-          loc, fieldTy, addrFieldName, componentTy,
-          /*typeParams=*/mlir::ValueRange{});
-      mlir::Value castAddr = builder.createConvert(loc, addrFieldTy, addr);
-      auto undef = builder.create<fir::UndefOp>(loc, componentTy);
-      addr = builder.create<fir::InsertValueOp>(
-          loc, componentTy, undef, castAddr,
-          builder.getArrayAttr(addrField.getAttributes()));
+  auto fieldTy = fir::FieldType::get(recTy.getContext());
+  mlir::Value res{};
+  // When the first structure component values belong to some parent type PT
+  // and the next values belong to a type extension ET, a new undef for ET must
+  // be created and the previous PT value inserted into it. There may
+  // be empty parent types in between ET and PT, hence the list and while loop.
+  auto insertParentValueIntoExtension = [&](mlir::Type typeExtension) {
+    assert(res && "res must be set");
+    llvm::SmallVector<mlir::Type> parentTypes = {typeExtension};
+    while (true) {
+      fir::RecordType last = mlir::cast<fir::RecordType>(parentTypes.back());
+      mlir::Type next =
+          last.getType(0); // parent components are first in HLFIR.
+      if (next != res.getType())
+        parentTypes.push_back(next);
+      else
+        break;
+    }
+    for (mlir::Type parentType : llvm::reverse(parentTypes)) {
+      auto undef = builder.create<fir::UndefOp>(loc, parentType);
+      fir::RecordType parentRecTy = mlir::cast<fir::RecordType>(parentType);
+      auto field = builder.create<fir::FieldIndexOp>(
+          loc, fieldTy, parentRecTy.getTypeList()[0].first, parentType,
+          /*typeParams=*/mlir::ValueRange{} /*TODO*/);
       res = builder.create<fir::InsertValueOp>(
-          loc, recTy, res, addr, builder.getArrayAttr(field.getAttributes()));
-      continue;
+          loc, recTy, undef, res, builder.getArrayAttr(field.getAttributes()));
     }
+  };
 
-    mlir::Value val =
-        fir::getBase(genConstantValue(converter, loc, expr.value()));
-    assert(!fir::isa_ref_type(val.getType()) && "expecting a constant value");
-    mlir::Value castVal = builder.createConvert(loc, componentTy, val);
-    res = builder.create<fir::InsertValueOp>(
-        loc, recTy, res, castVal, builder.getArrayAttr(field.getAttributes()));
+  const Fortran::semantics::DerivedTypeSpec *curentType = nullptr;
+  for (const auto &[sym, expr] : ctor.values()) {
+    // This TODO is not needed here anymore, but should be removed in a separate
+    // patch.
+    if (sym->test(Fortran::semantics::Symbol::Flag::ParentComp))
+      TODO(loc, "parent component in structure constructor");
+    const Fortran::semantics::DerivedTypeSpec *componentParentType =
+        sym->owner().derivedTypeSpec();
+    assert(componentParentType && "failed to retrieve component parent type");
+    if (!res) {
+      mlir::Type parentType = converter.genType(*componentParentType);
+      curentType = componentParentType;
+      res = builder.create<fir::UndefOp>(loc, parentType);
+    } else if (*componentParentType != *curentType) {
+      mlir::Type parentType = converter.genType(*componentParentType);
+      insertParentValueIntoExtension(parentType);
+      curentType = componentParentType;
+    }
+    res = genStructureComponentInit(converter, loc, sym, expr.value(), res);
   }
+
+  if (!res) // structure constructor for empty type.
+    return builder.create<fir::UndefOp>(loc, recTy);
+
+  // The last component may belong to a parent type.
+  if (res.getType() != recTy)
+    insertParentValueIntoExtension(recTy);
   return res;
 }
 
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 236a3639d8dc2e8..4cf29c9aecbf577 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -303,63 +303,19 @@ class HlfirDesignatorBuilder {
   }
 
   fir::FortranVariableOpInterface
-  gen(const Fortran::evaluate::Component &component,
-      bool skipParentComponent = false) {
+  gen(const Fortran::evaluate::Component &component) {
     if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol()))
       return genWholeAllocatableOrPointerComponent(component);
-    if (component.GetLastSymbol().test(
-            Fortran::semantics::Symbol::Flag::ParentComp)) {
-      if (skipParentComponent)
-        // Inner parent components can be skipped: x%parent_comp%i is equivalent
-        // to "x%i" in FIR (all the parent components are part of the FIR type
-        // of "x").
-        return genDataRefAndSkipParentComponents(component.base());
-      // This is a leaf "x%parent_comp" or "x(subscripts)%parent_comp" and
-      // cannot be skipped: the designator must be lowered to the parent type.
-      // This cannot be represented with an hlfir.designate since "parent_comp"
-      // name is meaningless in the fir.record type of "x". Instead, an
-      // hlfir.parent_comp is generated.
-      fir::FirOpBuilder &builder = getBuilder();
-      hlfir::Entity base = genDataRefAndSkipParentComponents(component.base());
-      base = derefPointersAndAllocatables(loc, builder, base);
-      mlir::Value shape;
-      if (base.isArray())
-        shape = hlfir::genShape(loc, builder, base);
-      const Fortran::semantics::DeclTypeSpec *declTypeSpec =
-          component.GetLastSymbol().GetType();
-      assert(declTypeSpec && declTypeSpec->AsDerived() &&
-             "parent component symbols must have a derived type");
-      mlir::Type componentType = Fortran::lower::translateDerivedTypeToFIRType(
-          getConverter(), *declTypeSpec->AsDerived());
-      mlir::Type resultType =
-          changeElementType(base.getElementOrSequenceType(), componentType);
-      // Note that the result is monomorphic even if the base is polymorphic:
-      // the dynamic type of the parent component reference is the parent type.
-      // If the base is an array, it is however most likely not contiguous.
-      if (base.isArray() || fir::isRecordWithTypeParameters(componentType))
-        resultType = fir::BoxType::get(resultType);
-      else
-        resultType = fir::ReferenceType::get(resultType);
-      if (fir::isRecordWithTypeParameters(componentType))
-        TODO(loc, "parent component reference with a parametrized parent type");
-      auto parentComp = builder.create<hlfir::ParentComponentOp>(
-          loc, resultType, base, shape, /*typeParams=*/mlir::ValueRange{});
-      return mlir::cast<fir::FortranVariableOpInterface>(
-          parentComp.getOperation());
-    }
     PartInfo partInfo;
     mlir::Type resultType = visit(component, partInfo);
     return genDesignate(resultType, partInfo, component);
   }
 
   fir::FortranVariableOpInterface
-  genDataRefAndSkipParentComponents(const Fortran::evaluate::DataRef &dataRef) {
-    return std::visit(Fortran::common::visitors{
-                          [&](const Fortran::evaluate::Component &component) {
-                            return gen(component, /*skipParentComponent=*/true);
-                          },
-                          [&](const auto &x) { return gen(x); }},
-                      dataRef.u);
+  gen(const Fortran::evaluate::DataRef &dataRef) {
+    return std::visit(
+        Fortran::common::visitors{[&](const auto &x) { return gen(x); }},
+        dataRef.u);
   }
 
   fir::FortranVariableOpInterface
@@ -725,7 +681,7 @@ class HlfirDesignatorBuilder {
     // coarray-ref, or another component, this creates another hlfir.designate
     // for it.  hlfir.designate is not meant to represent more than one
     // part-ref.
-    partInfo.base = genDataRefAndSkipParentComponents(component.base());
+    partInfo.base = gen(component.base());
     // If the base is an allocatable/pointer, dereference it here since the
     // component ref designates its target.
     partInfo.base =
@@ -739,9 +695,6 @@ class HlfirDesignatorBuilder {
     // Lower the information about the component (type, length parameters and
     // shape).
     const Fortran::semantics::Symbol &componentSym = component.GetLastSymbol();
-    assert(
-        !componentSym.test(Fortran::semantics::Symbol::Flag::ParentComp) &&
-        "parent components are skipped and must not reach visitComponentImpl");
     partInfo.componentName = converter.getRecordTypeFieldName(componentSym);
     auto recordType =
         hlfir::getFortranElementType(baseType).cast<fir::RecordType>();
@@ -1697,7 +1650,7 @@ class HlfirBuilder {
   // Construct an entity holding the value specified by the
   // StructureConstructor. The initialization of the temporary entity
   // is done component by component with the help of HLFIR operations
-  // ParentComponentOp, DesignateOp and AssignOp.
+  // DesignateOp and AssignOp.
   hlfir::EntityWithAttributes
   gen(const Fortran::evaluate::StructureConstructor &ctor) {
     mlir::Location loc = getLoc();
@@ -1720,35 +1673,58 @@ class HlfirBuilder {
     mlir::Value box = builder.createBox(loc, fir::ExtendedValue{varOp});
     fir::runtime::genDerivedTypeInitialize(builder, loc, box);
 
+    // StructureConstructor values may relate to name of components in parent
+    // types. These components cannot be addressed directly, the parent
+    // components must be addressed first. The loop below creates all the
+    // required chains of hlfir.designate to address the parent components so
+    // that the StructureConstructor can later be lowered by addressing these
+    // parent components if needed. Note: the front-end orders the components in
+    // structure constructors. The code below relies on the component to appear
+    // in order.
+    using ValueAndParent = std::tuple<const Fortran::lower::SomeExpr &,
+                                      const Fortran::semantics::Symbol &,
+                                      hlfir::EntityWithAttributes>;
+    llvm::SmallVector<ValueAndParent> valuesAndParents;
+    Fortran::lower::ComponentReverseIterator compIterator(
+        ctor.result().derivedTypeSpec());
+    hlfir::EntityWithAttributes currentParent = varOp;
+    for (const auto &value : llvm::reverse(ctor.values())) {
+      const Fortran::semantics::Symbol &compSym = *value.first;
+      while (!compIterator.lookup(compSym.name())) {
+        const auto &parentType = compIterator.advanceToParentType();
+        llvm::StringRef parentName = toStringRef(parentType.name());
+        auto baseRecTy = mlir::cast<fir::RecordType>(
+            hlfir::getFortranElementType(currentParent.getType()));
+        auto parentCompType = baseRecTy.getType(parentName);
+        assert(parentCompType && "failed to retrieve parent component type");
+        mlir::Type designatorType = builder.getRefType(parentCompType);
+        mlir::Value newParent = builder.create<hlfir::DesignateOp>(
+            loc, designatorType, currentParent, parentName,
+            /*compShape=*/mlir::Value{}, hlfir::DesignateOp::Subscripts{},
+            /*substring=*/mlir::ValueRange{},
+            /*complexPart=*/std::nullopt,
+            /*shape=*/mlir::Value{}, /*typeParams=*/mlir::ValueRange{},
+            fir::FortranVariableFlagsAttr{});
+        currentParent = hlfir::EntityWithAttributes{newParent};
+      }
+      valuesAndParents.emplace_back(
+          ValueAndParent{value.second.value(), compSym, currentParent});
+    }
+
     HlfirDesignatorBuilder designatorBuilder(loc, converter, symMap, stmtCtx);
-    for (const auto &value : ctor.values()) {
-      const Fortran::semantics::Symbol &sym = *value.first;
-      const Fortran::lower::SomeExpr &expr = value.second.value();
+    for (const auto &iter : llvm::reverse(valuesAndParents)) {
+      auto &sym = std::get<const Fortran::semantics::Symbol &>(iter);
+      auto &expr = std::get<const Fortran::lower::SomeExpr &>(iter);
+      auto &baseOp = std::get<hlfir::EntityWithAttributes>(iter);
       std::string name = converter.getRecordTypeFieldName(sym);
-      if (sym.test(Fortran::semantics::Symbol::Flag::ParentComp)) {
-        const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType();
-        assert(declTypeSpec && declTypeSpec->AsDerived() &&
-               "parent component symbol must have a derived type");
-        mlir::Type compType = Fortran::lower::translateDerivedTypeToFIRType(
-            converter, *declTypeSpec->AsDerived());
-        if (fir::isRecordWithTypeParameters(compType))
-          TODO(loc,
-               "parent component reference with a parameterized parent type");
-        mlir::Type resultType = builder.getRefType(compType);
-        auto lhs = builder.create<hlfir::ParentComponentOp>(
-            loc, resultType, varOp, /*shape=*/nullptr,
-            /*typeparams=*/mlir::ValueRange{});
-        auto rhs = gen(expr);
-        builder.create<hlfir::AssignOp>(loc, rhs, lhs, /*realloc=*/false,
-                                        /*keep_lhs_length_if_realloc=*/false,
-                                        /*temporary_lhs=*/true);
-        continue;
-      }
 
       // Generate DesignateOp for the component.
       // The designator's result type is just a reference to the component type,
       // because the whole component is being designated.
-      auto compType = recTy.getType(name);
+      auto baseRecTy = mlir::cast<fir::RecordType>(
+          hlfir::getFortranElementType(baseOp.getType()));
+      auto compType = baseRecTy.getType(name);
+      assert(compType && "failed to retrieve component type");
       mlir::Value compShape =
           designatorBuilder.genComponentShape(sym, compType);
       mlir::Type designatorType = builder.getRefType(compType);
@@ -1771,7 +1747,7 @@ class HlfirBuilder {
 
       // Get the component designator.
       auto lhs = builder.create<hlfir::DesignateOp>(
-          loc, designatorType, varOp, name, compShape,
+          loc, designatorType, baseOp, name, compShape,
           hlfir::DesignateOp::Subscripts{},
           /*substring=*/mlir::ValueRange{},
           /*complexPart=*/std::nullopt,
diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp
index 22b83efe8678bb0..1ed3b602621b449 100644
--- a/flang/lib/Lower/ConvertType.cpp
+++ b/flang/lib/Lower/ConvertType.cpp
@@ -376,31 +376,56 @@ struct TypeBuilderImpl {
       return genVectorType(tySpec);
     }
 
+    const Fortran::semantics::Scope &derivedScope = DEREF(tySpec.GetScope());
+
     auto rec = fir::RecordType::get(context, converter.mangleName(tySpec));
     // Maintain the stack of types for recursive references.
     derivedTypeInConstruction.emplace_back(typeSymbol, rec);
 
     // Gather the record type fields.
     // (1) The data components.
-    for (const auto &component :
-         Fortran::semantics::OrderedComponentIterator(tySpec)) {
-      // Lowering is assuming non deferred component lower bounds are always 1.
-      // Catch any situations where this is not true for now.
-      if (!converter.getLoweringOptions().getLowerToHighLevelFIR() &&
-          componentHasNonDefaultLowerBounds(component))
-        TODO(converter.genLocation(component.name()),
-             "derived type components with non default lower bounds");
-      if (IsProcedure(component))
-        TODO(converter.genLocation(component.name()), "procedure components");
-      mlir::Type ty = genSymbolType(component);
-      // Do not add the parent component (component of the parents are
-      // added and should be sufficient, the parent component would
-      // duplicate the fields). Note that genSymbolType must be called above on
-      // it so that the dispatch table for the parent type still gets emitted
-      // as needed.
-      if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
-        continue;
-      cs.emplace_back(converter.getRecordTypeFieldName(component), ty);
+    if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
+      // In HLFIR the parent component is the first fir.type component.
+      for (const auto &componentName :
+           typeSymbol.get<Fortran::semantics::DerivedTypeDetails>()
+               .componentNames()) {
+        auto scopeIter = derivedScope.find(componentName);
+        assert(scopeIter != derivedScope.cend() &&
+               "failed to find derived type component symbol");
+        const Fortran::semantics::Symbol &component = scopeIter->second.get();
+        if (IsProcedure(component))
+          TODO(converter.genLocation(component.name()), "procedure components");
+        mlir::Type ty = genSymbolType(component);
+        cs.emplace_back(converter.getRecordTypeFieldName(component), ty);
+      }
+    } else {
+      for (const auto &component :
+           Fortran::semantics::OrderedComponentIterator(tySpec)) {
+        // In the lowering to FIR the parent component does not appear in the
+        // fir.type and its components are inlined at the beginning of the
+        // fir.type<>.
+        // FIXME: this strategy leads to bugs because padding should be inserted
+        // after the component of the parents so that the next components do not
+        // end-up in the parent storage if the sum of the parent's component
+        // storage size is not a multiple of the parent type storage alignment.
+
+        // Lowering is assuming non deferred component lower bounds are
+        // always 1. Catch any situations where this is not true for now.
+        if (componentHasNonDefaultLowerBounds(component))
+          TODO(converter.genLocation(component.name()),
+               "derived type components with non default lower bounds");
+        if (IsProcedure(component))
+          TODO(converter.genLocation(component.name()), "procedure components");
+        mlir::Type ty = genSymbolType(component);
+        // Do not add the parent component (component of the parents are
+        // added and should be sufficient, the parent component would
+        // duplicate the fields). Note that genSymbolType must be called above
+        // on it so that the dispatch table for the parent type still gets
+        // emitted as needed.
+        if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
+          continue;
+        cs.emplace_back(converter.getRecordTypeFieldName(component), ty);
+      }
     }
 
     mlir::Location loc = converter.genLocation(typeSymbol.name());
@@ -427,11 +452,9 @@ struct TypeBuilderImpl {
     LLVM_DEBUG(llvm::dbgs() << "derived type: " << rec << '\n');
 
     // Generate the type descriptor object if any
-    if (const Fortran::semantics::Scope *derivedScope =
-            tySpec.scope() ? tySpec.scope() : tySpec.typeSymbol().scope())
-      if (const Fortran::semantics::Symbol *typeInfoSym =
-              derivedScope->runtimeDerivedTypeDescription())
-        converter.registerTypeInfo(loc, *typeInfoSym, tySpec, rec);
+    if (const Fortran::semantics::Symbol *typeInfoSym =
+            derivedScope.runtimeDerivedTypeDescription())
+      converter.registerTypeInfo(loc, *typeInfoSym, tySpec, rec);
     return rec;
   }
 
@@ -596,6 +619,25 @@ mlir::Type Fortran::lower::TypeBuilder<T>::genType(
   return TypeBuilderImpl{converter}.genExprType(funcRef);
 }
 
+const Fortran::semantics::DerivedTypeSpec &
+Fortran::lower::ComponentReverseIterator::advanceToParentType() {
+  const Fortran::semantics::Scope *scope = currentParentType->GetScope();
+  auto parentComp =
+      DEREF(scope).find(currentTypeDetails->GetParentComponentName().value());
+  assert(parentComp != scope->cend() && "failed to get parent component");
+  setCurrentType(parentComp->second->GetType()->derivedTypeSpec());
+  return *currentParentType;
+}
+
+void Fortran::lower::ComponentReverseIterator::setCurrentType(
+    const Fortran::semantics::DerivedTypeSpec &derived) {
+  currentParentType = &derived;
+  currentTypeDetails = &currentParentType->typeSymbol()
+                            .get<Fortran::semantics::DerivedTypeDetails>();
+  componentIt = currentTypeDetails->componentNames().crbegin();
+  componentItEnd = currentTypeDetails->componentNames().crend();
+}
+
 using namespace Fortran::evaluate;
 using namespace Fortran::common;
 FOR_EACH_SPECIFIC_TYPE(template class Fortran::lower::TypeBuilder, )
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 895ae2451125d63..57fb9fc432de2ff 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -309,6 +309,74 @@ mlir::Value Fortran::lower::genInitialDataTarget(
                                       /*slice=*/mlir::Value{});
 }
 
+/// Generate default initial value for a derived type object \p sym with mlir
+/// type \p symTy.
+static mlir::Value genDefaultInitializerValue(
+    Fortran::lower::AbstractConverter &converter, mlir::Location loc,
+    const Fortran::semantics::Symbol &sym, mlir::Type symTy,
+    Fortran::lower::StatementContext &stmtCtx);
+
+/// Generate the initial value of a derived component \p component and insert
+/// it into the derived type initial value \p insertInto of type \p recTy.
+/// Return the new derived type initial value after the insertion.
+static mlir::Value genComponentDefaultInit(
+    Fortran::lower::AbstractConverter &converter, mlir::Location loc,
+    const Fortran::semantics::Symbol &component, fir::RecordType recTy,
+    mlir::Value insertInto, Fortran::lower::StatementContext &stmtCtx) {
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  std::string name = converter.getRecordTypeFieldName(component);
+  mlir::Type componentTy = recTy.getType(name);
+  assert(componentTy && "component not found in type");
+  mlir::Value componentValue;
+  if (const auto *object{
+          component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) {
+    if (const auto &init = object->init()) {
+      // Component has explicit initialization.
+      if (Fortran::semantics::IsPointer(component))
+        // Initial data target.
+        componentValue =
+            genInitialDataTarget(converter, loc, componentTy, *init);
+      else
+        // Initial value.
+        componentValue = fir::getBase(
+            genInitializerExprValue(converter, loc, *init, stmtCtx));
+    } else if (Fortran::semantics::IsAllocatableOrPointer(component)) {
+      // Pointer or allocatable without initialization.
+      // Create deallocated/disassociated value.
+      // From a standard point of view, pointer without initialization do not
+      // need to be disassociated, but for sanity and simplicity, do it in
+      // global constructor since this has no runtime cost.
+      componentValue = fir::factory::createUnallocatedBox(
+          builder, loc, componentTy, std::nullopt);
+    } else if (hasDefaultInitialization(component)) {
+      // Component type has default initialization.
+      componentValue = genDefaultInitializerValue(converter, loc, component,
+                                                  componentTy, stmtCtx);
+    } else {
+      // Component has no initial value. Set its bits to zero by extension
+      // to match what is expected because other compilers are doing it.
+      componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
+    }
+  } else if (const auto *proc{
+                 component
+                     .detailsIf<Fortran::semantics::ProcEntityDetails>()}) {
+    if (proc->init().has_value())
+      TODO(loc, "procedure pointer component default initialization");
+    else
+      componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
+  }
+  assert(componentValue && "must have been computed");
+  componentValue = builder.createConvert(loc, componentTy, componentValue);
+  auto fieldTy = fir::FieldType::get(recTy.getContext());
+  // FIXME: type parameters must come from the derived-type-spec
+  auto field = builder.create<fir::FieldIndexOp>(
+      loc, fieldTy, name, recTy,
+      /*typeParams=*/mlir::ValueRange{} /*TODO*/);
+  return builder.create<fir::InsertValueOp>(
+      loc, recTy, insertInto, componentValue,
+      builder.getArrayAttr(field.getAttributes()));
+}
+
 static mlir::Value genDefaultInitializerValue(
     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
     const Fortran::semantics::Symbol &sym, mlir::Type symTy,
@@ -323,67 +391,40 @@ static mlir::Value genDefaultInitializerValue(
   // Build a scalar default value of the symbol type, looping through the
   // components to build each component initial value.
   auto recTy = scalarType.cast<fir::RecordType>();
-  auto fieldTy = fir::FieldType::get(scalarType.getContext());
   mlir::Value initialValue = builder.create<fir::UndefOp>(loc, scalarType);
   const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
   assert(declTy && "var with default initialization must have a type");
-  Fortran::semantics::OrderedComponentIterator components(
-      declTy->derivedTypeSpec());
-  for (const auto &component : components) {
-    // Skip parent components, the sub-components of parent types are part of
-    // components and will be looped through right after.
-    if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
-      continue;
-    mlir::Value componentValue;
-    std::string name = converter.getRecordTypeFieldName(component);
-    mlir::Type componentTy = recTy.getType(name);
-    assert(componentTy && "component not found in type");
-    if (const auto *object{
-            component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) {
-      if (const auto &init = object->init()) {
-        // Component has explicit initialization.
-        if (Fortran::semantics::IsPointer(component))
-          // Initial data target.
-          componentValue =
-              genInitialDataTarget(converter, loc, componentTy, *init);
-        else
-          // Initial value.
-          componentValue = fir::getBase(
-              genInitializerExprValue(converter, loc, *init, stmtCtx));
-      } else if (Fortran::semantics::IsAllocatableOrPointer(component)) {
-        // Pointer or allocatable without initialization.
-        // Create deallocated/disassociated value.
-        // From a standard point of view, pointer without initialization do not
-        // need to be disassociated, but for sanity and simplicity, do it in
-        // global constructor since this has no runtime cost.
-        componentValue = fir::factory::createUnallocatedBox(
-            builder, loc, componentTy, std::nullopt);
-      } else if (hasDefaultInitialization(component)) {
-        // Component type has default initialization.
-        componentValue = genDefaultInitializerValue(converter, loc, component,
-                                                    componentTy, stmtCtx);
-      } else {
-        // Component has no initial value. Set its bits to zero by extension
-        // to match what is expected because other compilers are doing it.
-        componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
-      }
-    } else if (const auto *proc{
-                   component
-                       .detailsIf<Fortran::semantics::ProcEntityDetails>()}) {
-      if (proc->init().has_value())
-        TODO(loc, "procedure pointer component default initialization");
-      else
-        componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
+
+  if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
+    // In HLFIR, the parent type is the first component, while in FIR there is
+    // not parent component in the fir.type and the component of the parent are
+    // "inlined" at the beginning of the fir.type.
+    const Fortran::semantics::Symbol &typeSymbol =
+        declTy->derivedTypeSpec().typeSymbol();
+    const Fortran::semantics::Scope *derivedScope =
+        declTy->derivedTypeSpec().GetScope();
+    assert(derivedScope && "failed to retrieve derived type scope");
+    for (const auto &componentName :
+         typeSymbol.get<Fortran::semantics::DerivedTypeDetails>()
+             .componentNames()) {
+      auto scopeIter = derivedScope->find(componentName);
+      assert(scopeIter != derivedScope->cend() &&
+             "failed to find derived type component symbol");
+      const Fortran::semantics::Symbol &component = scopeIter->second.get();
+      initialValue = genComponentDefaultInit(converter, loc, component, recTy,
+                                             initialValue, stmtCtx);
+    }
+  } else {
+    Fortran::semantics::OrderedComponentIterator components(
+        declTy->derivedTypeSpec());
+    for (const auto &component : components) {
+      // Skip parent components, the sub-components of parent types are part of
+      // components and will be looped through right after.
+      if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
+        continue;
+      initialValue = genComponentDefaultInit(converter, loc, component, recTy,
+                                             initialValue, stmtCtx);
     }
-    assert(componentValue && "must have been computed");
-    componentValue = builder.createConvert(loc, componentTy, componentValue);
-    // FIXME: type parameters must come from the derived-type-spec
-    auto field = builder.create<fir::FieldIndexOp>(
-        loc, fieldTy, name, scalarType,
-        /*typeParams=*/mlir::ValueRange{} /*TODO*/);
-    initialValue = builder.create<fir::InsertValueOp>(
-        loc, recTy, initialValue, componentValue,
-        builder.getArrayAttr(field.getAttributes()));
   }
 
   if (sequenceType) {
diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index a72c2e8ea23c613..e812283fc6f1902 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -37,6 +37,10 @@ void DerivedTypeSpec::ReplaceScope(const Scope &scope) {
   scope_ = &scope;
 }
 
+const Scope *DerivedTypeSpec::GetScope() const {
+  return scope_ ? scope_ : typeSymbol_.scope();
+}
+
 void DerivedTypeSpec::AddRawParamValue(
     const parser::Keyword *keyword, ParamValue &&value) {
   CHECK(parameters_.empty());
diff --git a/flang/test/Lower/HLFIR/calls-constant-expr-arg-polymorphic.f90 b/flang/test/Lower/HLFIR/calls-constant-expr-arg-polymorphic.f90
index e1de5f765349fb7..04d1354596de321 100644
--- a/flang/test/Lower/HLFIR/calls-constant-expr-arg-polymorphic.f90
+++ b/flang/test/Lower/HLFIR/calls-constant-expr-arg-polymorphic.f90
@@ -21,9 +21,9 @@ subroutine foo(x)
 end
 ! CHECK-LABEL:   func.func @_QQmain() {
 ! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}(%[[VAL_2:.*]]) {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQro.1x_QFTt2.0"}
-! CHECK:           %[[VAL_4:.*]] = hlfir.as_expr %[[VAL_3]]#0 : (!fir.ref<!fir.array<1x!fir.type<_QFTt2{i:i32,j:i32}>>>) -> !hlfir.expr<1x!fir.type<_QFTt2{i:i32,j:i32}>>
-! CHECK:           %[[VAL_5:.*]]:3 = hlfir.associate %[[VAL_4]](%[[VAL_2]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<1x!fir.type<_QFTt2{i:i32,j:i32}>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1x!fir.type<_QFTt2{i:i32,j:i32}>>>, !fir.ref<!fir.array<1x!fir.type<_QFTt2{i:i32,j:i32}>>>, i1)
-! CHECK:           %[[VAL_6:.*]] = fir.embox %[[VAL_5]]#0(%[[VAL_2]]) : (!fir.ref<!fir.array<1x!fir.type<_QFTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<1x!fir.type<_QFTt2{i:i32,j:i32}>>>
-! CHECK:           %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.box<!fir.array<1x!fir.type<_QFTt2{i:i32,j:i32}>>>) -> !fir.class<!fir.array<?x!fir.type<_QFTt1{i:i32}>>>
+! CHECK:           %[[VAL_4:.*]] = hlfir.as_expr %[[VAL_3]]#0 : (!fir.ref<!fir.array<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>>) -> !hlfir.expr<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>
+! CHECK:           %[[VAL_5:.*]]:3 = hlfir.associate %[[VAL_4]](%[[VAL_2]]) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>>, !fir.ref<!fir.array<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>>, i1)
+! CHECK:           %[[VAL_6:.*]] = fir.embox %[[VAL_5]]#0(%[[VAL_2]]) : (!fir.ref<!fir.array<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>>
+! CHECK:           %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.box<!fir.array<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>>) -> !fir.class<!fir.array<?x!fir.type<_QFTt1{i:i32}>>>
 ! CHECK:           fir.call @_QPfoo(%[[VAL_7]]) {{.*}}: (!fir.class<!fir.array<?x!fir.type<_QFTt1{i:i32}>>>) -> ()
-! CHECK:           hlfir.end_associate %[[VAL_5]]#1, %[[VAL_5]]#2 : !fir.ref<!fir.array<1x!fir.type<_QFTt2{i:i32,j:i32}>>>, i1
+! CHECK:           hlfir.end_associate %[[VAL_5]]#1, %[[VAL_5]]#2 : !fir.ref<!fir.array<1x!fir.type<_QFTt2{t1:!fir.type<_QFTt1{i:i32}>,j:i32}>>>, i1
diff --git a/flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90 b/flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90
index b63026b1e3f103d..06884138d28c344 100644
--- a/flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90
+++ b/flang/test/Lower/HLFIR/local-end-of-scope-component-dealloc.f90
@@ -62,7 +62,7 @@ subroutine test3()
 end subroutine test3
 ! CHECK-LABEL:   func.func @_QPtest3() {
 ! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
-! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt3{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt3{t1:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>
 
 subroutine test3b()
   use types
@@ -72,7 +72,7 @@ subroutine test3b()
 end subroutine test3b
 ! CHECK-LABEL:   func.func @_QPtest3b() {
 ! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
-! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt3{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt3{t1:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>
 
 subroutine test4()
   use types
@@ -80,7 +80,7 @@ subroutine test4()
 end subroutine test4
 ! CHECK-LABEL:   func.func @_QPtest4() {
 ! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
-! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt4{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt4{t3:!fir.type<_QMtypesTt3{t1:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>}>>) -> !fir.box<none>
 
 subroutine test4b()
   use types
@@ -90,7 +90,7 @@ subroutine test4b()
 end subroutine test4b
 ! CHECK-LABEL:   func.func @_QPtest4b() {
 ! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
-! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt4{x:!fir.box<!fir.heap<f32>>}>>) -> !fir.box<none>
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt4{t3:!fir.type<_QMtypesTt3{t1:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>}>>) -> !fir.box<none>
 
 subroutine test5()
   use types
@@ -98,7 +98,7 @@ subroutine test5()
 end subroutine test5
 ! CHECK-LABEL:   func.func @_QPtest5() {
 ! CHECK-DAG:       %[[VAL_10:.*]] = fir.call @_FortranADestroy(%[[VAL_9:.*]]) fastmath<contract> : (!fir.box<none>) -> none
-! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt5{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>
+! CHECK-DAG:       %[[VAL_9]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt5{t2:!fir.type<_QMtypesTt2{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>}>>) -> !fir.box<none>
 
 subroutine test5b()
   use types
@@ -108,4 +108,4 @@ subroutine test5b()
 end subroutine test5b
 ! CHECK-LABEL:   func.func @_QPtest5b() {
 ! CHECK-DAG:       %[[VAL_11:.*]] = fir.call @_FortranADestroy(%[[VAL_10:.*]]) fastmath<contract> : (!fir.box<none>) -> none
-! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt5{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>>) -> !fir.box<none>
+! CHECK-DAG:       %[[VAL_10]] = fir.convert %{{.*}} : (!fir.box<!fir.type<_QMtypesTt5{t2:!fir.type<_QMtypesTt2{x:!fir.type<_QMtypesTt1{x:!fir.box<!fir.heap<f32>>}>}>}>>) -> !fir.box<none>
diff --git a/flang/test/Lower/HLFIR/parent-component-ref.f90 b/flang/test/Lower/HLFIR/parent-component-ref.f90
index ceba56e730ccbf0..b08d8f450e6d714 100644
--- a/flang/test/Lower/HLFIR/parent-component-ref.f90
+++ b/flang/test/Lower/HLFIR/parent-component-ref.f90
@@ -23,28 +23,30 @@ subroutine takes_int_array(x)
 end interface
 end module
 
-subroutine test_ignored_inner_parent_comp(x)
+subroutine test_inner_parent_comp(x)
  use pc_types
  type(t2) :: x
  call takes_int(x%t%i)
 end subroutine
-! CHECK-LABEL: func.func @_QPtest_ignored_inner_parent_comp(
+! CHECK-LABEL: func.func @_QPtest_inner_parent_comp(
 ! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
-! CHECK:  %[[VAL_2:.*]] = hlfir.designate %[[VAL_1]]#0{"i"}   : (!fir.ref<!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>) -> !fir.ref<i32>
-! CHECK:  fir.call @_QPtakes_int(%[[VAL_2]])
+! CHECK:  %[[VAL_2:.*]] = hlfir.designate %[[VAL_1]]#0{"t"}   : (!fir.ref<!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>) -> !fir.ref<!fir.type<_QMpc_typesTt{i:i32}>>
+! CHECK:  %[[VAL_3:.*]] = hlfir.designate %[[VAL_2]]{"i"}   : (!fir.ref<!fir.type<_QMpc_typesTt{i:i32}>>) -> !fir.ref<i32>
+! CHECK:  fir.call @_QPtakes_int(%[[VAL_3]])
 
-subroutine test_ignored_inner_parent_comp_2(x)
+subroutine test_inner_parent_comp_2(x)
  use pc_types
  type(t2) :: x(:)
  call takes_int_array(x%t%i)
 end subroutine
-! CHECK-LABEL: func.func @_QPtest_ignored_inner_parent_comp_2(
+! CHECK-LABEL: func.func @_QPtest_inner_parent_comp_2(
 ! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
 ! CHECK:  %[[VAL_2:.*]] = arith.constant 0 : index
-! CHECK:  %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_1]]#0, %[[VAL_2]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_1]]#0, %[[VAL_2]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>, index) -> (index, index, index)
 ! CHECK:  %[[VAL_4:.*]] = fir.shape %[[VAL_3]]#1 : (index) -> !fir.shape<1>
-! CHECK:  %[[VAL_5:.*]] = hlfir.designate %[[VAL_1]]#0{"i"}   shape %[[VAL_4]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
-! CHECK:  fir.call @_QPtakes_int_array(%[[VAL_5]])
+! CHECK:  %[[VAL_5:.*]] = hlfir.designate %[[VAL_1]]#0{"t"}   shape %[[VAL_4]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  %[[VAL_6:.*]] = hlfir.designate %[[VAL_5]]{"i"}   shape %[[VAL_4]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
+! CHECK:  fir.call @_QPtakes_int_array(%[[VAL_6]])
 
 subroutine test_leaf_parent_ref(x)
  use pc_types
@@ -53,7 +55,7 @@ subroutine test_leaf_parent_ref(x)
 end subroutine
 ! CHECK-LABEL: func.func @_QPtest_leaf_parent_ref(
 ! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
-! CHECK:  %[[VAL_2:.*]] = hlfir.parent_comp %[[VAL_1]]#0 : (!fir.ref<!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>) -> !fir.ref<!fir.type<_QMpc_typesTt{i:i32}>>
+! CHECK:  %[[VAL_2:.*]] = hlfir.designate %[[VAL_1]]#0{"t"}   : (!fir.ref<!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>) -> !fir.ref<!fir.type<_QMpc_typesTt{i:i32}>>
 ! CHECK:  fir.call @_QPtakes_parent(%[[VAL_2]])
 
 subroutine test_leaf_parent_ref_array(x)
@@ -63,12 +65,12 @@ subroutine test_leaf_parent_ref_array(x)
 ! CHECK:  %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Ex"
  call takes_t_type_array(x%t)
 ! CHECK:  %[[VAL_5:.*]] = arith.constant 0 : index
-! CHECK:  %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_4]]#0, %[[VAL_5]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_4]]#0, %[[VAL_5]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>, index) -> (index, index, index)
 ! CHECK:  %[[VAL_7:.*]] = fir.shape %[[VAL_6]]#1 : (index) -> !fir.shape<1>
-! CHECK:  %[[VAL_8:.*]] = hlfir.parent_comp %[[VAL_4]]#0 shape %[[VAL_7]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  %[[VAL_8:.*]] = hlfir.designate %[[VAL_4]]#0{"t"}   shape %[[VAL_7]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
 ! CHECK:  fir.call @_QPtakes_t_type_array(%[[VAL_8]])
  call takes_t_class_array(x%t)
-! CHECK:  %[[VAL_12:.*]] = hlfir.parent_comp %[[VAL_4]]#0 shape %{{.*}} : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  %[[VAL_12:.*]] = hlfir.designate %[[VAL_4]]#0{"t"}   shape %{{.*}} : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
 ! CHECK:  %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>) -> !fir.class<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
 ! CHECK:  fir.call @_QPtakes_t_class_array(%[[VAL_13]])
 end subroutine
@@ -80,8 +82,8 @@ subroutine test_parent_section_leaf_array(x)
 end subroutine
 ! CHECK-LABEL: func.func @_QPtest_parent_section_leaf_array(
 ! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
-! CHECK:  %[[VAL_7:.*]] = hlfir.designate %[[VAL_1]]#0 ({{.*}})  shape %[[VAL_6:.*]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, index, index, index, !fir.shape<1>) -> !fir.class<!fir.array<10x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>
-! CHECK:  %[[VAL_8:.*]] = hlfir.parent_comp %[[VAL_7]] shape %[[VAL_6]] : (!fir.class<!fir.array<10x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<10x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  %[[VAL_7:.*]] = hlfir.designate %[[VAL_1]]#0 ({{.*}})  shape %[[VAL_6:.*]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>, index, index, index, !fir.shape<1>) -> !fir.class<!fir.array<10x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>
+! CHECK:  %[[VAL_8:.*]] = hlfir.designate %[[VAL_7]]{"t"}   shape %[[VAL_6]] : (!fir.class<!fir.array<10x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<10x!fir.type<_QMpc_typesTt{i:i32}>>>
 ! CHECK:  %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.box<!fir.array<10x!fir.type<_QMpc_typesTt{i:i32}>>>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
 ! CHECK:  fir.call @_QPtakes_t_type_array(%[[VAL_9]])
 
@@ -92,8 +94,9 @@ subroutine test_pointer_leaf_parent_ref_array(x)
 end subroutine
 ! CHECK-LABEL: func.func @_QPtest_pointer_leaf_parent_ref_array(
 ! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
-! CHECK:  %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>>>
+! CHECK:  %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>>>
 ! CHECK:  %[[VAL_3:.*]] = arith.constant 0 : index
-! CHECK:  %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>>, index) -> (index, index, index)
 ! CHECK:  %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
-! CHECK:  %[[VAL_6:.*]] = hlfir.parent_comp %[[VAL_2]] shape %[[VAL_5]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  %[[VAL_6:.*]] = hlfir.designate %[[VAL_2]]{"t"}   shape %[[VAL_5]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{t:!fir.type<_QMpc_typesTt{i:i32}>,j:i32}>>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  fir.call @_QPtakes_t_type_array(%[[VAL_6]])
diff --git a/flang/test/Lower/HLFIR/private-components.f90 b/flang/test/Lower/HLFIR/private-components.f90
index bf231c52f5203b7..23c1c7402c9036d 100644
--- a/flang/test/Lower/HLFIR/private-components.f90
+++ b/flang/test/Lower/HLFIR/private-components.f90
@@ -11,7 +11,7 @@ module name_clash
 end module
 
 !CHECK-LABEL: func.func @_QPuser_clash(
-!CHECK-SAME: !fir.ref<!fir.type<_QFuser_clashTt2{_QMname_clashTt.i:i32,i:i32}>>
+!CHECK-SAME: !fir.ref<!fir.type<_QFuser_clashTt2{t:!fir.type<_QMname_clashTt{_QMname_clashTt.i:i32}>,i:i32}>>
 !CHECK-SAME: !fir.ref<!fir.type<_QMname_clashTt{_QMname_clashTt.i:i32}>>
 subroutine user_clash(a, at)
   use name_clash
@@ -26,7 +26,7 @@ subroutine user_clash(a, at)
 end subroutine
 
 ! CHECK-LABEL: func.func @_QPclash_with_intrinsic_module(
-! CHECK-SAME: !fir.ref<!fir.type<_QFclash_with_intrinsic_moduleTmy_class{_QMieee_arithmeticTieee_class_type.which:i8,which:i8}>>
+! CHECK-SAME: !fir.ref<!fir.type<_QFclash_with_intrinsic_moduleTmy_class{ieee_class_type:!fir.type<_QMieee_arithmeticTieee_class_type{_QMieee_arithmeticTieee_class_type.which:i8}>,which:i8}>>
 subroutine clash_with_intrinsic_module(a)
  use ieee_arithmetic
  type, extends(ieee_class_type) :: my_class
diff --git a/flang/test/Lower/HLFIR/structure-constructor.f90 b/flang/test/Lower/HLFIR/structure-constructor.f90
index 797f801ad642408..8bf140abaa5640f 100644
--- a/flang/test/Lower/HLFIR/structure-constructor.f90
+++ b/flang/test/Lower/HLFIR/structure-constructor.f90
@@ -41,9 +41,9 @@ end subroutine test1
 ! CHECK:           %[[VAL_2:.*]] = fir.alloca !fir.type<_QMtypesTt1{c:!fir.char<1,4>}> {bindc_name = "res", uniq_name = "_QFtest1Eres"}
 ! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFtest1Eres"} : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>) -> (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>)
 ! CHECK:           %[[VAL_4:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
-! CHECK:           %[[VAL_6:.*]] = fir.convert %[[VAL_4]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,4>>
-! CHECK:           %[[VAL_5:.*]] = arith.constant 4 : index
-! CHECK:           %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_5]] {uniq_name = "_QFtest1Ex"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>)
+! CHECK:           %[[VAL_5:.*]] = fir.convert %[[VAL_4]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,4>>
+! CHECK:           %[[VAL_6:.*]] = arith.constant 4 : index
+! CHECK:           %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_6]] {uniq_name = "_QFtest1Ex"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>)
 ! CHECK:           %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>) -> (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>)
 ! CHECK:           %[[VAL_9:.*]] = fir.embox %[[VAL_8]]#0 : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>) -> !fir.box<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>
 ! CHECK:           %[[VAL_10:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,{{[0-9]*}}>>
@@ -218,28 +218,28 @@ end subroutine test6
 ! CHECK:           %[[VAL_3:.*]] = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"}
 ! CHECK:           %[[VAL_4:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>> {bindc_name = ".tmp.arrayctor"}
 ! CHECK:           %[[VAL_5:.*]] = fir.alloca !fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>
-! CHECK:           %[[VAL_6:.*]] = fir.alloca !fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>
+! CHECK:           %[[VAL_6:.*]] = fir.alloca !fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>
 ! CHECK:           %[[VAL_7:.*]]:2 = fir.unboxchar %[[VAL_1]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
-! CHECK:           %[[VAL_9:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,4>>
-! CHECK:           %[[VAL_8:.*]] = arith.constant 4 : index
-! CHECK:           %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] typeparams %[[VAL_8]] {uniq_name = "_QFtest6Ec"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>)
-! CHECK:           %[[VAL_11:.*]] = fir.alloca !fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}> {bindc_name = "res", uniq_name = "_QFtest6Eres"}
-! CHECK:           %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFtest6Eres"} : (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>)
-! CHECK:           %[[VAL_13:.*]] = fir.embox %[[VAL_12]]#1 : (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>
+! CHECK:           %[[VAL_8:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,4>>
+! CHECK:           %[[VAL_9:.*]] = arith.constant 4 : index
+! CHECK:           %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_8]] typeparams %[[VAL_9]] {uniq_name = "_QFtest6Ec"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>)
+! CHECK:           %[[VAL_11:.*]] = fir.alloca !fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}> {bindc_name = "res", uniq_name = "_QFtest6Eres"}
+! CHECK:           %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFtest6Eres"} : (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>)
+! CHECK:           %[[VAL_13:.*]] = fir.embox %[[VAL_12]]#1 : (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>
 ! CHECK:           %[[VAL_14:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,{{[0-9]*}}>>
 ! CHECK:           %[[VAL_15:.*]] = arith.constant {{[0-9]*}} : i32
-! CHECK:           %[[VAL_16:.*]] = fir.convert %[[VAL_13]] : (!fir.box<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<none>
+! CHECK:           %[[VAL_16:.*]] = fir.convert %[[VAL_13]] : (!fir.box<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<none>
 ! CHECK:           %[[VAL_17:.*]] = fir.convert %[[VAL_14]] : (!fir.ref<!fir.char<1,{{[0-9]*}}>>) -> !fir.ref<i8>
 ! CHECK:           %[[VAL_18:.*]] = fir.call @_FortranAInitialize(%[[VAL_16]], %[[VAL_17]], %[[VAL_15]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
 ! CHECK:           %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest6Ex"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>)
-! CHECK:           %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>)
-! CHECK:           %[[VAL_21:.*]] = fir.embox %[[VAL_20]]#0 : (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>
+! CHECK:           %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>)
+! CHECK:           %[[VAL_21:.*]] = fir.embox %[[VAL_20]]#0 : (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>
 ! CHECK:           %[[VAL_22:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,{{[0-9]*}}>>
 ! CHECK:           %[[VAL_23:.*]] = arith.constant {{[0-9]*}} : i32
-! CHECK:           %[[VAL_24:.*]] = fir.convert %[[VAL_21]] : (!fir.box<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<none>
+! CHECK:           %[[VAL_24:.*]] = fir.convert %[[VAL_21]] : (!fir.box<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.box<none>
 ! CHECK:           %[[VAL_25:.*]] = fir.convert %[[VAL_22]] : (!fir.ref<!fir.char<1,{{[0-9]*}}>>) -> !fir.ref<i8>
 ! CHECK:           %[[VAL_26:.*]] = fir.call @_FortranAInitialize(%[[VAL_24]], %[[VAL_25]], %[[VAL_23]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
-! CHECK:           %[[VAL_27:.*]] = hlfir.parent_comp %[[VAL_20]]#0 : (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>
+! CHECK:           %[[VAL_27:.*]] = hlfir.designate %[[VAL_20]]#0{"t5"}   : (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>) -> !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>
 ! CHECK:           %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>) -> (!fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>, !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>)
 ! CHECK:           %[[VAL_29:.*]] = fir.embox %[[VAL_28]]#0 : (!fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>) -> !fir.box<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>
 ! CHECK:           %[[VAL_30:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,{{[0-9]*}}>>
@@ -260,7 +260,7 @@ end subroutine test6
 ! CHECK:           hlfir.assign %[[VAL_28]]#0 to %[[VAL_27]] temporary_lhs : !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>, !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>
 ! CHECK:           %[[VAL_42:.*]] = arith.constant 1 : index
 ! CHECK:           %[[VAL_43:.*]] = fir.shape %[[VAL_42]] : (index) -> !fir.shape<1>
-! CHECK:           %[[VAL_44:.*]] = hlfir.designate %[[VAL_20]]#0{"t6m"} <%[[VAL_43]]>   shape %[[VAL_43]] : (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.shape<1>, !fir.shape<1>) -> !fir.ref<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>
+! CHECK:           %[[VAL_44:.*]] = hlfir.designate %[[VAL_20]]#0{"t6m"} <%[[VAL_43]]>   shape %[[VAL_43]] : (!fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.shape<1>, !fir.shape<1>) -> !fir.ref<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>
 ! CHECK:           %[[VAL_45:.*]] = arith.constant 1 : index
 ! CHECK:           %[[VAL_46:.*]] = fir.allocmem !fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>> {bindc_name = ".tmp.arrayctor", uniq_name = ""}
 ! CHECK:           %[[VAL_47:.*]] = fir.shape %[[VAL_45]] : (index) -> !fir.shape<1>
@@ -290,8 +290,7 @@ end subroutine test6
 ! CHECK:           %[[VAL_69:.*]] = arith.constant true
 ! CHECK:           %[[VAL_70:.*]] = hlfir.as_expr %[[VAL_48]]#0 move %[[VAL_69]] : (!fir.heap<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>, i1) -> !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>
 ! CHECK:           hlfir.assign %[[VAL_70]] to %[[VAL_44]] temporary_lhs : !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>
-! CHECK:           hlfir.assign %[[VAL_20]]#0 to %[[VAL_12]]#0 : !fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>
-! CHECK:           hlfir.destroy %[[VAL_70]] : !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>
+! CHECK:           hlfir.assign %[[VAL_20]]#0 to %[[VAL_12]]#0 : !fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref<!fir.type<_QMtypesTt6{t5:!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>
 ! CHECK:           return
 ! CHECK:         }
 
@@ -307,7 +306,7 @@ subroutine test7(n)
   x = t7(n)
 end subroutine test7
 ! CHECK-LABEL:   func.func @_QPtest7(
-! CHECK-SAME:      %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "n"}) {
+! CHECK-SAME:                        %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "n"}) {
 ! CHECK:           %[[VAL_1:.*]] = fir.alloca !fir.type<_QMtypesTt7{c1:i32,c2:!fir.box<!fir.heap<!fir.array<?xf32>>>}>
 ! CHECK:           %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest7En"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 ! CHECK:           %[[VAL_3:.*]] = fir.alloca !fir.type<_QMtypesTt7{c1:i32,c2:!fir.box<!fir.heap<!fir.array<?xf32>>>}> {bindc_name = "x", uniq_name = "_QFtest7Ex"}
diff --git a/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90 b/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90
index 866a80a3057a934..6794d11ece42d26 100644
--- a/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90
+++ b/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90
@@ -35,5 +35,5 @@ subroutine test(x)
 end subroutine
 !CHECK-LABEL:  func.func @_QPtest(
 !CHECK:    %[[X:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtestEx"}
-!CHECK:    %[[CAST:.*]] = fir.convert %[[X]]#0 : (!fir.class<!fir.type<_QMdispatch_mismatchTt2{i:i32}>>) -> !fir.class<!fir.type<_QMdispatch_mismatchTt{i:i32}>>
-!CHECK:    fir.dispatch "proc"(%[[X]]#0 : !fir.class<!fir.type<_QMdispatch_mismatchTt2{i:i32}>>) (%[[CAST]] : !fir.class<!fir.type<_QMdispatch_mismatchTt{i:i32}>>) {pass_arg_pos = 0 : i32}
+!CHECK:    %[[CAST:.*]] = fir.convert %[[X]]#0 : (!fir.class<!fir.type<_QMdispatch_mismatchTt2{t:!fir.type<_QMdispatch_mismatchTt{i:i32}>}>>) -> !fir.class<!fir.type<_QMdispatch_mismatchTt{i:i32}>>
+!CHECK:    fir.dispatch "proc"(%[[X]]#0 : !fir.class<!fir.type<_QMdispatch_mismatchTt2{t:!fir.type<_QMdispatch_mismatchTt{i:i32}>}>>) (%[[CAST]] : !fir.class<!fir.type<_QMdispatch_mismatchTt{i:i32}>>) {pass_arg_pos = 0 : i32}
diff --git a/flang/test/Lower/HLFIR/type-info.f90 b/flang/test/Lower/HLFIR/type-info.f90
index e0716fd069020e7..f1792dc0c077701 100644
--- a/flang/test/Lower/HLFIR/type-info.f90
+++ b/flang/test/Lower/HLFIR/type-info.f90
@@ -54,7 +54,7 @@ subroutine needs_final_final(x)
 ! CHECK-DAG:  fir.type_info @_QMtyinfoTneeds_init1 nodestroy nofinal : !fir.type<_QMtyinfoTneeds_init1{i:i32}>
 ! CHECK-DAG:  fir.type_info @_QMtyinfoTneeds_init_and_destroy nofinal : !fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>
 ! CHECK-DAG:  fir.type_info @_QMtyinfoTneeds_all : !fir.type<_QMtyinfoTneeds_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>}>
-! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_final noinit extends !fir.type<_QMtyinfoTneeds_final> : !fir.type<_QMtyinfoTinherits_final>
-! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_init nodestroy nofinal extends !fir.type<_QMtyinfoTneeds_init1{i:i32}> : !fir.type<_QMtyinfoTinherits_init{i:i32}>
-! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_init_and_destroy nofinal extends !fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}> : !fir.type<_QMtyinfoTinherits_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>
-! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_all extends !fir.type<_QMtyinfoTneeds_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>}> : !fir.type<_QMtyinfoTinherits_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>}>
+! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_final noinit extends !fir.type<_QMtyinfoTneeds_final> : !fir.type<_QMtyinfoTinherits_final{needs_final:!fir.type<_QMtyinfoTneeds_final>}>
+! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_init nodestroy nofinal extends !fir.type<_QMtyinfoTneeds_init1{i:i32}> : !fir.type<_QMtyinfoTinherits_init{needs_init1:!fir.type<_QMtyinfoTneeds_init1{i:i32}>}>
+! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_init_and_destroy nofinal extends !fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}> : !fir.type<_QMtyinfoTinherits_init_and_destroy{needs_init_and_destroy:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>}>
+! CHECK-DAG:  fir.type_info @_QMtyinfoTinherits_all extends !fir.type<_QMtyinfoTneeds_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>}> : !fir.type<_QMtyinfoTinherits_all{needs_all:!fir.type<_QMtyinfoTneeds_all{x:!fir.type<_QMtyinfoTneeds_final>,y:!fir.type<_QMtyinfoTneeds_init_and_destroy{x:!fir.box<!fir.heap<i32>>}>}>}>

>From 098ae260c5cbd80510dcf4d932062b9510276e1a Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Tue, 17 Oct 2023 12:13:10 -0700
Subject: [PATCH 2/3] fix typo in cst struct ctor lowering change

---
 flang/lib/Lower/ConvertConstant.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp
index c935c90121941f3..423a14de4b0a9ca 100644
--- a/flang/lib/Lower/ConvertConstant.cpp
+++ b/flang/lib/Lower/ConvertConstant.cpp
@@ -469,7 +469,8 @@ static mlir::Value genInlinedStructureCtorLitImpl(
           loc, fieldTy, parentRecTy.getTypeList()[0].first, parentType,
           /*typeParams=*/mlir::ValueRange{} /*TODO*/);
       res = builder.create<fir::InsertValueOp>(
-          loc, recTy, undef, res, builder.getArrayAttr(field.getAttributes()));
+          loc, parentRecTy, undef, res,
+          builder.getArrayAttr(field.getAttributes()));
     }
   };
 

>From 4e4603c9a37d01cad86aa97c0dee102a63635a83 Mon Sep 17 00:00:00 2001
From: jeanPerier <jean.perier.polytechnique at gmail.com>
Date: Fri, 20 Oct 2023 11:13:18 +0200
Subject: [PATCH 3/3] Fix comment in ConvertType.h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Valentin Clement (バレンタイン クレメン) <clementval at gmail.com>
---
 flang/include/flang/Lower/ConvertType.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang/include/flang/Lower/ConvertType.h b/flang/include/flang/Lower/ConvertType.h
index 61cbc7d7aa303cc..7a3f92649a4e4af 100644
--- a/flang/include/flang/Lower/ConvertType.h
+++ b/flang/include/flang/Lower/ConvertType.h
@@ -108,7 +108,7 @@ class ComponentReverseIterator {
     setCurrentType(derived);
   }
   /// Does the current type has a component with \name (does not look-up the
-  /// components of the parent if any). If there is a match, the iterator
+  /// components of the parent if any)? If there is a match, the iterator
   /// is advanced to the search result.
   bool lookup(const Fortran::parser::CharBlock &name) {
     componentIt = std::find(componentIt, componentItEnd, name);



More information about the flang-commits mailing list