[flang-commits] [flang] d60a022 - [flang] Include default component initialization in static initializers

peter klausler via flang-commits flang-commits at lists.llvm.org
Wed Sep 1 09:40:46 PDT 2021


Author: peter klausler
Date: 2021-09-01T09:40:37-07:00
New Revision: d60a02201d96ed5311404991186d827869d7ac8b

URL: https://github.com/llvm/llvm-project/commit/d60a02201d96ed5311404991186d827869d7ac8b
DIFF: https://github.com/llvm/llvm-project/commit/d60a02201d96ed5311404991186d827869d7ac8b.diff

LOG: [flang] Include default component initialization in static initializers

The combined initializers constructed from DATA statements and explicit
static initialization in declarations needs to include derived type
component default initializations, overriding those default values
without complaint with values from explicit DATA statement or declaration
initializations when they overlap.  This also has to work for objects
with storage association due to EQUIVALENCE.  When storage association causes
default component initializations to overlap, emit errors if and only
if the values differ (See Fortran 2018 subclause 19.5.3, esp. paragraph
10).

The f18 front-end has a module that analyzes and converts DATA statements
into equivalent static initializers for objects.  For storage-associated
objects, compiler-generated objects are created that overlay the entire
association and fill it with a combined initializer.  This "data-to-inits"
module already exists, and this patch is essentially extension and
clean-up of its machinery to complete the job.

Also: emit EQUIVALENCE to module files; mark compiler-created symbols
and *don't* emit those to module files; check non-static EQUIVALENCE
sets for conflicting default component initializations, so lowering
doesn't have to check them or emit diagnostics.

Differential Revision: https://reviews.llvm.org/D109022

Added: 
    flang/test/Semantics/data12.f90
    flang/test/Semantics/data13.f90

Modified: 
    flang/include/flang/Evaluate/initial-image.h
    flang/include/flang/Semantics/scope.h
    flang/include/flang/Semantics/symbol.h
    flang/include/flang/Semantics/tools.h
    flang/lib/Evaluate/initial-image.cpp
    flang/lib/Semantics/check-declarations.cpp
    flang/lib/Semantics/compute-offsets.cpp
    flang/lib/Semantics/data-to-inits.cpp
    flang/lib/Semantics/data-to-inits.h
    flang/lib/Semantics/mod-file.cpp
    flang/lib/Semantics/resolve-names.cpp
    flang/lib/Semantics/runtime-type-info.cpp
    flang/lib/Semantics/symbol.cpp
    flang/lib/Semantics/tools.cpp
    flang/lib/Semantics/type.cpp
    flang/test/Semantics/typeinfo01.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/initial-image.h b/flang/include/flang/Evaluate/initial-image.h
index c2cf12e377e05..596b1f77d1790 100644
--- a/flang/include/flang/Evaluate/initial-image.h
+++ b/flang/include/flang/Evaluate/initial-image.h
@@ -30,6 +30,7 @@ class InitialImage {
   };
 
   explicit InitialImage(std::size_t bytes) : data_(bytes) {}
+  InitialImage(InitialImage &&that) = default;
 
   std::size_t size() const { return data_.size(); }
 
@@ -93,19 +94,17 @@ class InitialImage {
 
   void AddPointer(ConstantSubscript, const Expr<SomeType> &);
 
-  void Incorporate(ConstantSubscript, const InitialImage &);
+  void Incorporate(ConstantSubscript toOffset, const InitialImage &from,
+      ConstantSubscript fromOffset, ConstantSubscript bytes);
 
   // Conversions to constant initializers
   std::optional<Expr<SomeType>> AsConstant(FoldingContext &,
       const DynamicType &, const ConstantSubscripts &,
       ConstantSubscript offset = 0) const;
-  std::optional<Expr<SomeType>> AsConstantDataPointer(
-      const DynamicType &, ConstantSubscript offset = 0) const;
-  const ProcedureDesignator &AsConstantProcPointer(
+  std::optional<Expr<SomeType>> AsConstantPointer(
       ConstantSubscript offset = 0) const;
 
   friend class AsConstantHelper;
-  friend class AsConstantDataPointerHelper;
 
 private:
   std::vector<char> data_;

diff  --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h
index f1d5b0c87d48a..6c6ee5956f490 100644
--- a/flang/include/flang/Semantics/scope.h
+++ b/flang/include/flang/Semantics/scope.h
@@ -41,6 +41,8 @@ struct EquivalenceObject {
       std::optional<ConstantSubscript> substringStart, parser::CharBlock source)
       : symbol{symbol}, subscripts{subscripts},
         substringStart{substringStart}, source{source} {}
+  explicit EquivalenceObject(Symbol &symbol)
+      : symbol{symbol}, source{symbol.name()} {}
 
   bool operator==(const EquivalenceObject &) const;
   bool operator<(const EquivalenceObject &) const;

diff  --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 7eb7eb1370180..8810c57853701 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -497,6 +497,7 @@ class Symbol {
       LocalityShared, // named in SHARED locality-spec
       InDataStmt, // initialized in a DATA statement
       InNamelist, // flag is set if the symbol is in Namelist statement
+      CompilerCreated,
       // OpenACC data-sharing attribute
       AccPrivate, AccFirstPrivate, AccShared,
       // OpenACC data-mapping attribute
@@ -779,7 +780,7 @@ struct SymbolAddressCompare {
   }
 };
 
-// Symbol comparison is based on the order of cooked source
+// Symbol comparison is usually based on the order of cooked source
 // stream creation and, when both are from the same cooked source,
 // their positions in that cooked source stream.
 // Don't use this comparator or OrderedSymbolSet to hold
@@ -791,12 +792,17 @@ struct SymbolSourcePositionCompare {
   bool operator()(const MutableSymbolRef &, const MutableSymbolRef &) const;
 };
 
+struct SymbolOffsetCompare {
+  bool operator()(const SymbolRef &, const SymbolRef &) const;
+  bool operator()(const MutableSymbolRef &, const MutableSymbolRef &) const;
+};
+
 using UnorderedSymbolSet = std::set<SymbolRef, SymbolAddressCompare>;
-using OrderedSymbolSet = std::set<SymbolRef, SymbolSourcePositionCompare>;
+using SourceOrderedSymbolSet = std::set<SymbolRef, SymbolSourcePositionCompare>;
 
 template <typename A>
-OrderedSymbolSet OrderBySourcePosition(const A &container) {
-  OrderedSymbolSet result;
+SourceOrderedSymbolSet OrderBySourcePosition(const A &container) {
+  SourceOrderedSymbolSet result;
   for (SymbolRef x : container) {
     result.emplace(x);
   }

diff  --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 1e92275eb6011..d969dc914b037 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -56,6 +56,8 @@ const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &);
 const DeclTypeSpec *FindParentTypeSpec(const Scope &);
 const DeclTypeSpec *FindParentTypeSpec(const Symbol &);
 
+const EquivalenceSet *FindEquivalenceSet(const Symbol &);
+
 enum class Tristate { No, Yes, Maybe };
 inline Tristate ToTristate(bool x) { return x ? Tristate::Yes : Tristate::No; }
 
@@ -105,14 +107,13 @@ bool IsEventTypeOrLockType(const DerivedTypeSpec *);
 bool IsOrContainsEventOrLockComponent(const Symbol &);
 bool CanBeTypeBoundProc(const Symbol *);
 // Does a non-PARAMETER symbol have explicit initialization with =value or
-// =>target in its declaration, or optionally in a DATA statement? (Being
+// =>target in its declaration (but not in a DATA statement)? (Being
 // ALLOCATABLE or having a derived type with default component initialization
 // doesn't count; it must be a variable initialization that implies the SAVE
 // attribute, or a derived type component default value.)
-bool IsStaticallyInitialized(const Symbol &, bool ignoreDATAstatements = false);
+bool HasDeclarationInitializer(const Symbol &);
 // Is the symbol explicitly or implicitly initialized in any way?
-bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false,
-    const Symbol *derivedType = nullptr);
+bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false);
 // Is the symbol a component subject to deallocation or finalization?
 bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr);
 bool HasIntrinsicTypeName(const Symbol &);
@@ -330,6 +331,13 @@ enum class ProcedureDefinitionClass {
 
 ProcedureDefinitionClass ClassifyProcedure(const Symbol &);
 
+// Returns a list of storage associations due to EQUIVALENCE in a
+// scope; each storage association is a list of symbol references
+// in ascending order of scope offset.  Note that the scope may have
+// more EquivalenceSets than this function's result has storage
+// associations; these are closures over equivalences.
+std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &);
+
 // Derived type component iterator that provides a C++ LegacyForwardIterator
 // iterator over the Ordered, Direct, Ultimate or Potential components of a
 // DerivedTypeSpec. These iterators can be used with STL algorithms

diff  --git a/flang/lib/Evaluate/initial-image.cpp b/flang/lib/Evaluate/initial-image.cpp
index 35be2238af1ad..6abca5704fbb6 100644
--- a/flang/lib/Evaluate/initial-image.cpp
+++ b/flang/lib/Evaluate/initial-image.cpp
@@ -54,11 +54,14 @@ void InitialImage::AddPointer(
   pointers_.emplace(offset, pointer);
 }
 
-void InitialImage::Incorporate(
-    ConstantSubscript offset, const InitialImage &that) {
-  CHECK(that.pointers_.empty()); // pointers are not allowed in EQUIVALENCE
-  CHECK(offset + that.size() <= size());
-  std::memcpy(&data_[offset], &that.data_[0], that.size());
+void InitialImage::Incorporate(ConstantSubscript toOffset,
+    const InitialImage &from, ConstantSubscript fromOffset,
+    ConstantSubscript bytes) {
+  CHECK(from.pointers_.empty()); // pointers are not allowed in EQUIVALENCE
+  CHECK(fromOffset >= 0 && bytes >= 0 &&
+      static_cast<std::size_t>(fromOffset + bytes) <= from.size());
+  CHECK(static_cast<std::size_t>(toOffset + bytes) <= size());
+  std::memcpy(&data_[toOffset], &from.data_[fromOffset], bytes);
 }
 
 // Classes used with common::SearchTypes() to (re)construct Constant<> values
@@ -97,26 +100,31 @@ class AsConstantHelper {
       const semantics::DerivedTypeSpec &derived{type_.GetDerivedTypeSpec()};
       for (auto iter : DEREF(derived.scope())) {
         const Symbol &component{*iter.second};
-        bool isPointer{IsPointer(component)};
-        if (component.has<semantics::ObjectEntityDetails>() ||
-            component.has<semantics::ProcEntityDetails>()) {
-          auto componentType{DynamicType::From(component)};
-          CHECK(componentType);
+        bool isProcPtr{IsProcedurePointer(component)};
+        if (isProcPtr || component.has<semantics::ObjectEntityDetails>()) {
           auto at{offset_ + component.offset()};
-          if (isPointer) {
+          if (isProcPtr) {
             for (std::size_t j{0}; j < elements; ++j, at += stride) {
-              Result value{image_.AsConstantDataPointer(*componentType, at)};
-              CHECK(value);
-              typedValue[j].emplace(component, std::move(*value));
+              if (Result value{image_.AsConstantPointer(at)}) {
+                typedValue[j].emplace(component, std::move(*value));
+              }
+            }
+          } else if (IsPointer(component)) {
+            for (std::size_t j{0}; j < elements; ++j, at += stride) {
+              if (Result value{image_.AsConstantPointer(at)}) {
+                typedValue[j].emplace(component, std::move(*value));
+              }
             }
           } else {
+            auto componentType{DynamicType::From(component)};
+            CHECK(componentType.has_value());
             auto componentExtents{GetConstantExtents(context_, component)};
-            CHECK(componentExtents);
+            CHECK(componentExtents.has_value());
             for (std::size_t j{0}; j < elements; ++j, at += stride) {
-              Result value{image_.AsConstant(
-                  context_, *componentType, *componentExtents, at)};
-              CHECK(value);
-              typedValue[j].emplace(component, std::move(*value));
+              if (Result value{image_.AsConstant(
+                      context_, *componentType, *componentExtents, at)}) {
+                typedValue[j].emplace(component, std::move(*value));
+              }
             }
           }
         }
@@ -159,45 +167,11 @@ std::optional<Expr<SomeType>> InitialImage::AsConstant(FoldingContext &context,
       AsConstantHelper{context, type, extents, *this, offset});
 }
 
-class AsConstantDataPointerHelper {
-public:
-  using Result = std::optional<Expr<SomeType>>;
-  using Types = AllTypes;
-  AsConstantDataPointerHelper(const DynamicType &type,
-      const InitialImage &image, ConstantSubscript offset = 0)
-      : type_{type}, image_{image}, offset_{offset} {}
-  template <typename T> Result Test() {
-    if (T::category != type_.category()) {
-      return std::nullopt;
-    }
-    if constexpr (T::category != TypeCategory::Derived) {
-      if (T::kind != type_.kind()) {
-        return std::nullopt;
-      }
-    }
-    auto iter{image_.pointers_.find(offset_)};
-    if (iter == image_.pointers_.end()) {
-      return AsGenericExpr(NullPointer{});
-    }
-    return iter->second;
-  }
-
-private:
-  const DynamicType &type_;
-  const InitialImage &image_;
-  ConstantSubscript offset_;
-};
-
-std::optional<Expr<SomeType>> InitialImage::AsConstantDataPointer(
-    const DynamicType &type, ConstantSubscript offset) const {
-  return common::SearchTypes(AsConstantDataPointerHelper{type, *this, offset});
-}
-
-const ProcedureDesignator &InitialImage::AsConstantProcPointer(
+std::optional<Expr<SomeType>> InitialImage::AsConstantPointer(
     ConstantSubscript offset) const {
-  auto iter{pointers_.find(0)};
-  CHECK(iter != pointers_.end());
-  return DEREF(std::get_if<ProcedureDesignator>(&iter->second.u));
+  auto iter{pointers_.find(offset)};
+  return iter == pointers_.end() ? std::optional<Expr<SomeType>>{}
+                                 : iter->second;
 }
 
 } // namespace Fortran::evaluate

diff  --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 3b6d589ba2973..4468784c06a17 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -526,7 +526,7 @@ void CheckHelper::CheckObjectEntity(
     messages_.Say("OPTIONAL attribute may apply only to a dummy "
                   "argument"_err_en_US); // C849
   }
-  if (IsStaticallyInitialized(symbol, true /* ignore DATA inits */)) { // C808
+  if (HasDeclarationInitializer(symbol)) { // C808; ignore DATA initialization
     CheckPointerInitialization(symbol);
     if (IsAutomatic(symbol)) {
       messages_.Say(

diff  --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp
index 2ceb8f4336a58..a78d3f8418bc7 100644
--- a/flang/lib/Semantics/compute-offsets.cpp
+++ b/flang/lib/Semantics/compute-offsets.cpp
@@ -38,9 +38,9 @@ class ComputeOffsetsHelper {
   };
   struct SymbolAndOffset {
     SymbolAndOffset(Symbol &s, std::size_t off, const EquivalenceObject &obj)
-        : symbol{&s}, offset{off}, object{&obj} {}
+        : symbol{s}, offset{off}, object{&obj} {}
     SymbolAndOffset(const SymbolAndOffset &) = default;
-    Symbol *symbol;
+    MutableSymbolRef symbol;
     std::size_t offset;
     const EquivalenceObject *object;
   };

diff  --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp
index 168dfb8e45586..8fba39f825345 100644
--- a/flang/lib/Semantics/data-to-inits.cpp
+++ b/flang/lib/Semantics/data-to-inits.cpp
@@ -20,6 +20,16 @@
 #include "flang/Evaluate/tools.h"
 #include "flang/Semantics/tools.h"
 
+// The job of generating explicit static initializers for objects that don't
+// have them in order to implement default component initialization is now being
+// done in lowering, so don't do it here in semantics; but the code remains here
+// in case we change our minds.
+static constexpr bool makeDefaultInitializationExplicit{false};
+
+// Whether to delete the original "init()" initializers from storage-associated
+// objects and pointers.
+static constexpr bool removeOriginalInits{false};
+
 namespace Fortran::semantics {
 
 // Steps through a list of values in a DATA statement set; implements
@@ -269,8 +279,10 @@ bool DataInitializationCompiler::InitElement(
     }
   }};
   const auto GetImage{[&]() -> evaluate::InitialImage & {
-    auto &symbolInit{inits_.emplace(&symbol, symbol.size()).first->second};
-    symbolInit.inits.emplace_back(offsetSymbol.offset(), offsetSymbol.size());
+    auto iter{inits_.emplace(&symbol, symbol.size())};
+    auto &symbolInit{iter.first->second};
+    symbolInit.initializedRanges.emplace_back(
+        offsetSymbol.offset(), offsetSymbol.size());
     return symbolInit.image;
   }};
   const auto OutOfRangeError{[&]() {
@@ -393,146 +405,422 @@ void AccumulateDataInitializations(DataInitializations &inits,
   }
 }
 
-static bool CombineSomeEquivalencedInits(
-    DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer) {
-  auto end{inits.end()};
-  for (auto iter{inits.begin()}; iter != end; ++iter) {
-    const Symbol &symbol{*iter->first};
-    Scope &scope{const_cast<Scope &>(symbol.owner())};
-    if (scope.equivalenceSets().empty()) {
-      continue; // no problem to solve here
-    }
-    const auto *commonBlock{FindCommonBlockContaining(symbol)};
-    // Sweep following DATA initializations in search of overlapping
-    // objects, accumulating into a vector; iterate to a fixed point.
-    std::vector<const Symbol *> conflicts;
-    auto minStart{symbol.offset()};
-    auto maxEnd{symbol.offset() + symbol.size()};
-    std::size_t minElementBytes{1};
-    while (true) {
-      auto prevCount{conflicts.size()};
-      conflicts.clear();
-      for (auto scan{iter}; ++scan != end;) {
-        const Symbol &other{*scan->first};
-        const Scope &otherScope{other.owner()};
-        if (&otherScope == &scope &&
-            FindCommonBlockContaining(other) == commonBlock &&
-            maxEnd > other.offset() &&
-            other.offset() + other.size() > minStart) {
-          // "other" conflicts with "symbol" or another conflict
-          conflicts.push_back(&other);
-          minStart = std::min(minStart, other.offset());
-          maxEnd = std::max(maxEnd, other.offset() + other.size());
+// Looks for default derived type component initialization -- but
+// *not* allocatables.
+static const DerivedTypeSpec *HasDefaultInitialization(const Symbol &symbol) {
+  if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
+    if (object->init().has_value()) {
+      return nullptr; // init is explicit, not default
+    } else if (!object->isDummy() && object->type()) {
+      if (const DerivedTypeSpec * derived{object->type()->AsDerived()}) {
+        DirectComponentIterator directs{*derived};
+        if (std::find_if(
+                directs.begin(), directs.end(), [](const Symbol &component) {
+                  return !IsAllocatable(component) &&
+                      HasDeclarationInitializer(component);
+                })) {
+          return derived;
         }
       }
-      if (conflicts.size() == prevCount) {
-        break;
+    }
+  }
+  return nullptr;
+}
+
+// PopulateWithComponentDefaults() adds initializations to an instance
+// of SymbolDataInitialization containing all of the default component
+// initializers
+
+static void PopulateWithComponentDefaults(SymbolDataInitialization &init,
+    std::size_t offset, const DerivedTypeSpec &derived,
+    evaluate::FoldingContext &foldingContext);
+
+static void PopulateWithComponentDefaults(SymbolDataInitialization &init,
+    std::size_t offset, const DerivedTypeSpec &derived,
+    evaluate::FoldingContext &foldingContext, const Symbol &symbol) {
+  if (auto extents{evaluate::GetConstantExtents(foldingContext, symbol)}) {
+    const Scope &scope{derived.scope() ? *derived.scope()
+                                       : DEREF(derived.typeSymbol().scope())};
+    std::size_t stride{scope.size()};
+    if (std::size_t alignment{scope.alignment().value_or(0)}) {
+      stride = ((stride + alignment - 1) / alignment) * alignment;
+    }
+    for (auto elements{evaluate::GetSize(*extents)}; elements-- > 0;
+         offset += stride) {
+      PopulateWithComponentDefaults(init, offset, derived, foldingContext);
+    }
+  }
+}
+
+// F'2018 19.5.3(10) allows storage-associated default component initialization
+// when the values are identical.
+static void PopulateWithComponentDefaults(SymbolDataInitialization &init,
+    std::size_t offset, const DerivedTypeSpec &derived,
+    evaluate::FoldingContext &foldingContext) {
+  const Scope &scope{
+      derived.scope() ? *derived.scope() : DEREF(derived.typeSymbol().scope())};
+  for (const auto &pair : scope) {
+    const Symbol &component{*pair.second};
+    std::size_t componentOffset{offset + component.offset()};
+    if (const auto *object{component.detailsIf<ObjectEntityDetails>()}) {
+      if (!IsAllocatable(component) && !IsAutomatic(component)) {
+        bool initialized{false};
+        if (object->init()) {
+          initialized = true;
+          if (IsPointer(component)) {
+            if (auto extant{init.image.AsConstantPointer(componentOffset)}) {
+              initialized = !(*extant == *object->init());
+            }
+            if (initialized) {
+              init.image.AddPointer(componentOffset, *object->init());
+            }
+          } else { // data, not pointer
+            if (auto dyType{evaluate::DynamicType::From(component)}) {
+              if (auto extents{evaluate::GetConstantExtents(
+                      foldingContext, component)}) {
+                if (auto extant{init.image.AsConstant(
+                        foldingContext, *dyType, *extents, componentOffset)}) {
+                  initialized = !(*extant == *object->init());
+                }
+              }
+            }
+            if (initialized) {
+              init.image.Add(componentOffset, component.size(), *object->init(),
+                  foldingContext);
+            }
+          }
+        } else if (const DeclTypeSpec * type{component.GetType()}) {
+          if (const DerivedTypeSpec * componentDerived{type->AsDerived()}) {
+            PopulateWithComponentDefaults(init, componentOffset,
+                *componentDerived, foldingContext, component);
+          }
+        }
+        if (initialized) {
+          init.initializedRanges.emplace_back(
+              componentOffset, component.size());
+        }
+      }
+    } else if (const auto *proc{component.detailsIf<ProcEntityDetails>()}) {
+      if (proc->init() && *proc->init()) {
+        SomeExpr procPtrInit{evaluate::ProcedureDesignator{**proc->init()}};
+        auto extant{init.image.AsConstantPointer(componentOffset)};
+        if (!extant || !(*extant == procPtrInit)) {
+          init.initializedRanges.emplace_back(
+              componentOffset, component.size());
+          init.image.AddPointer(componentOffset, std::move(procPtrInit));
+        }
       }
     }
-    if (conflicts.empty()) {
-      continue;
-    }
-    // Compute the minimum common granularity
-    if (auto dyType{evaluate::DynamicType::From(symbol)}) {
-      minElementBytes = evaluate::ToInt64(
-          dyType->MeasureSizeInBytes(exprAnalyzer.GetFoldingContext(), true))
-                            .value_or(1);
-    }
-    for (const Symbol *s : conflicts) {
-      if (auto dyType{evaluate::DynamicType::From(*s)}) {
-        minElementBytes = std::min<std::size_t>(minElementBytes,
-            evaluate::ToInt64(dyType->MeasureSizeInBytes(
-                                  exprAnalyzer.GetFoldingContext(), true))
-                .value_or(1));
+  }
+}
+
+static bool CheckForOverlappingInitialization(
+    const std::list<SymbolRef> &symbols,
+    SymbolDataInitialization &initialization,
+    evaluate::ExpressionAnalyzer &exprAnalyzer, const std::string &what) {
+  bool result{true};
+  auto &context{exprAnalyzer.GetFoldingContext()};
+  initialization.initializedRanges.sort();
+  ConstantSubscript next{0};
+  for (const auto &range : initialization.initializedRanges) {
+    if (range.start() < next) {
+      result = false; // error: overlap
+      bool hit{false};
+      for (const Symbol &symbol : symbols) {
+        auto offset{range.start() -
+            static_cast<ConstantSubscript>(
+                symbol.offset() - symbols.front()->offset())};
+        if (offset >= 0) {
+          if (auto badDesignator{evaluate::OffsetToDesignator(
+                  context, symbol, offset, range.size())}) {
+            hit = true;
+            exprAnalyzer.Say(symbol.name(),
+                "%s affect '%s' more than once"_err_en_US, what,
+                badDesignator->AsFortran());
+          }
+        }
+      }
+      CHECK(hit);
+    }
+    next = range.start() + range.size();
+    CHECK(next <= static_cast<ConstantSubscript>(initialization.image.size()));
+  }
+  return result;
+}
+
+static void IncorporateExplicitInitialization(
+    SymbolDataInitialization &combined, DataInitializations &inits,
+    const Symbol &symbol, ConstantSubscript firstOffset,
+    evaluate::FoldingContext &foldingContext) {
+  auto iter{inits.find(&symbol)};
+  const auto offset{symbol.offset() - firstOffset};
+  if (iter != inits.end()) { // DATA statement initialization
+    for (const auto &range : iter->second.initializedRanges) {
+      auto at{offset + range.start()};
+      combined.initializedRanges.emplace_back(at, range.size());
+      combined.image.Incorporate(
+          at, iter->second.image, range.start(), range.size());
+    }
+    if (removeOriginalInits) {
+      inits.erase(iter);
+    }
+  } else { // Declaration initialization
+    Symbol &mutableSymbol{const_cast<Symbol &>(symbol)};
+    if (IsPointer(mutableSymbol)) {
+      if (auto *object{mutableSymbol.detailsIf<ObjectEntityDetails>()}) {
+        if (object->init()) {
+          combined.initializedRanges.emplace_back(offset, mutableSymbol.size());
+          combined.image.AddPointer(offset, *object->init());
+          if (removeOriginalInits) {
+            object->init().reset();
+          }
+        }
+      } else if (auto *proc{mutableSymbol.detailsIf<ProcEntityDetails>()}) {
+        if (proc->init() && *proc->init()) {
+          combined.initializedRanges.emplace_back(offset, mutableSymbol.size());
+          combined.image.AddPointer(
+              offset, SomeExpr{evaluate::ProcedureDesignator{**proc->init()}});
+          if (removeOriginalInits) {
+            proc->init().reset();
+          }
+        }
+      }
+    } else if (auto *object{mutableSymbol.detailsIf<ObjectEntityDetails>()}) {
+      if (!IsNamedConstant(mutableSymbol) && object->init()) {
+        combined.initializedRanges.emplace_back(offset, mutableSymbol.size());
+        combined.image.Add(
+            offset, mutableSymbol.size(), *object->init(), foldingContext);
+        if (removeOriginalInits) {
+          object->init().reset();
+        }
+      }
+    }
+  }
+}
+
+// Finds the size of the smallest element type in a list of
+// storage-associated objects.
+static std::size_t ComputeMinElementBytes(
+    const std::list<SymbolRef> &associated,
+    evaluate::FoldingContext &foldingContext) {
+  std::size_t minElementBytes{1};
+  const Symbol &first{*associated.front()};
+  for (const Symbol &s : associated) {
+    if (auto dyType{evaluate::DynamicType::From(s)}) {
+      auto size{static_cast<std::size_t>(
+          evaluate::ToInt64(dyType->MeasureSizeInBytes(foldingContext, true))
+              .value_or(1))};
+      if (std::size_t alignment{dyType->GetAlignment(foldingContext)}) {
+        size = ((size + alignment - 1) / alignment) * alignment;
+      }
+      if (&s == &first) {
+        minElementBytes = size;
       } else {
-        minElementBytes = 1;
+        minElementBytes = std::min(minElementBytes, size);
       }
+    } else {
+      minElementBytes = 1;
     }
-    CHECK(minElementBytes > 0);
-    CHECK((minElementBytes & (minElementBytes - 1)) == 0);
-    auto bytes{static_cast<common::ConstantSubscript>(maxEnd - minStart)};
-    CHECK(bytes % minElementBytes == 0);
-    const DeclTypeSpec &typeSpec{scope.MakeNumericType(
-        TypeCategory::Integer, KindExpr{minElementBytes})};
-    // Combine "symbol" and "conflicts[]" into a compiler array temp
-    // that overlaps all of them, and merge their initial values into
-    // the temp's initializer.
+  }
+  return minElementBytes;
+}
+
+// Checks for overlapping initialization errors in a list of
+// storage-associated objects.  Default component initializations
+// are allowed to be overridden by explicit initializations.
+// If the objects are static, save the combined initializer as
+// a compiler-created object that covers all of them.
+static bool CombineEquivalencedInitialization(
+    const std::list<SymbolRef> &associated,
+    evaluate::ExpressionAnalyzer &exprAnalyzer, DataInitializations &inits) {
+  // Compute the minimum common granularity and total size
+  const Symbol &first{*associated.front()};
+  std::size_t maxLimit{0};
+  for (const Symbol &s : associated) {
+    CHECK(s.offset() >= first.offset());
+    auto limit{s.offset() + s.size()};
+    if (limit > maxLimit) {
+      maxLimit = limit;
+    }
+  }
+  auto bytes{static_cast<common::ConstantSubscript>(maxLimit - first.offset())};
+  Scope &scope{const_cast<Scope &>(first.owner())};
+  // Combine the initializations of the associated objects.
+  // Apply all default initializations first.
+  SymbolDataInitialization combined{static_cast<std::size_t>(bytes)};
+  auto &foldingContext{exprAnalyzer.GetFoldingContext()};
+  for (const Symbol &s : associated) {
+    if (!IsNamedConstant(s)) {
+      if (const auto *derived{HasDefaultInitialization(s)}) {
+        PopulateWithComponentDefaults(
+            combined, s.offset() - first.offset(), *derived, foldingContext, s);
+      }
+    }
+  }
+  if (!CheckForOverlappingInitialization(associated, combined, exprAnalyzer,
+          "Distinct default component initializations of equivalenced objects"s)) {
+    return false;
+  }
+  // Don't complain about overlap between explicit initializations and
+  // default initializations.
+  combined.initializedRanges.clear();
+  // Now overlay all explicit initializations from DATA statements and
+  // from initializers in declarations.
+  for (const Symbol &symbol : associated) {
+    IncorporateExplicitInitialization(
+        combined, inits, symbol, first.offset(), foldingContext);
+  }
+  if (!CheckForOverlappingInitialization(associated, combined, exprAnalyzer,
+          "Explicit initializations of equivalenced objects"s)) {
+    return false;
+  }
+  // If the items are in static storage, save the final initialization.
+  if (std::find_if(associated.begin(), associated.end(),
+          [](SymbolRef ref) { return IsSaved(*ref); }) != associated.end()) {
+    // Create a compiler array temp that overlaps all the items.
     SourceName name{exprAnalyzer.context().GetTempName(scope)};
     auto emplaced{
         scope.try_emplace(name, Attrs{Attr::SAVE}, ObjectEntityDetails{})};
     CHECK(emplaced.second);
     Symbol &combinedSymbol{*emplaced.first->second};
+    combinedSymbol.set(Symbol::Flag::CompilerCreated);
+    inits.emplace(&combinedSymbol, std::move(combined));
     auto &details{combinedSymbol.get<ObjectEntityDetails>()};
-    combinedSymbol.set_offset(minStart);
+    combinedSymbol.set_offset(first.offset());
     combinedSymbol.set_size(bytes);
+    std::size_t minElementBytes{
+        ComputeMinElementBytes(associated, foldingContext)};
+    if (!evaluate::IsValidKindOfIntrinsicType(
+            TypeCategory::Integer, minElementBytes) ||
+        (bytes % minElementBytes) != 0) {
+      minElementBytes = 1;
+    }
+    const DeclTypeSpec &typeSpec{scope.MakeNumericType(
+        TypeCategory::Integer, KindExpr{minElementBytes})};
     details.set_type(typeSpec);
     ArraySpec arraySpec;
     arraySpec.emplace_back(ShapeSpec::MakeExplicit(Bound{
         bytes / static_cast<common::ConstantSubscript>(minElementBytes)}));
     details.set_shape(arraySpec);
-    if (commonBlock) {
+    if (const auto *commonBlock{FindCommonBlockContaining(first)}) {
       details.set_commonBlock(*commonBlock);
     }
-    // Merge these EQUIVALENCE'd DATA initializations, and remove the
-    // original initializations from the map.
-    auto combinedInit{
-        inits.emplace(&combinedSymbol, static_cast<std::size_t>(bytes))};
-    evaluate::InitialImage &combined{combinedInit.first->second.image};
-    combined.Incorporate(symbol.offset() - minStart, iter->second.image);
-    inits.erase(iter);
-    for (const Symbol *s : conflicts) {
-      auto sIter{inits.find(s)};
-      CHECK(sIter != inits.end());
-      combined.Incorporate(s->offset() - minStart, sIter->second.image);
-      inits.erase(sIter);
-    }
-    return true; // got one
+    // Add an EQUIVALENCE set to the scope so that the new object appears in
+    // the results of GetStorageAssociations().
+    auto &newSet{scope.equivalenceSets().emplace_back()};
+    newSet.emplace_back(combinedSymbol);
+    newSet.emplace_back(const_cast<Symbol &>(first));
+  }
+  return true;
+}
+
+// When a statically-allocated derived type variable has no explicit
+// initialization, but its type has at least one nonallocatable ultimate
+// component with default initialization, make its initialization explicit.
+[[maybe_unused]] static void MakeDefaultInitializationExplicit(
+    const Scope &scope, const std::list<std::list<SymbolRef>> &associations,
+    evaluate::FoldingContext &foldingContext, DataInitializations &inits) {
+  UnorderedSymbolSet equivalenced;
+  for (const std::list<SymbolRef> &association : associations) {
+    for (const Symbol &symbol : association) {
+      equivalenced.emplace(symbol);
+    }
+  }
+  for (const auto &pair : scope) {
+    const Symbol &symbol{*pair.second};
+    if (!symbol.test(Symbol::Flag::InDataStmt) &&
+        !HasDeclarationInitializer(symbol) && IsSaved(symbol) &&
+        equivalenced.find(symbol) == equivalenced.end()) {
+      // Static object, no local storage association, no explicit initialization
+      if (const DerivedTypeSpec * derived{HasDefaultInitialization(symbol)}) {
+        auto newInitIter{inits.emplace(&symbol, symbol.size())};
+        CHECK(newInitIter.second);
+        auto &newInit{newInitIter.first->second};
+        PopulateWithComponentDefaults(
+            newInit, 0, *derived, foldingContext, symbol);
+      }
+    }
   }
-  return false; // no remaining EQUIVALENCE'd DATA initializations
 }
 
-// Converts the initialization image for all the DATA statement appearances of
-// a single symbol into an init() expression in the symbol table entry.
+// Traverses the Scopes to:
+// 1) combine initialization of equivalenced objects, &
+// 2) optionally make initialization explicit for otherwise uninitialized static
+//    objects of derived types with default component initialization
+// Returns false on error.
+static bool ProcessScopes(const Scope &scope,
+    evaluate::ExpressionAnalyzer &exprAnalyzer, DataInitializations &inits) {
+  bool result{true}; // no error
+  switch (scope.kind()) {
+  case Scope::Kind::Global:
+  case Scope::Kind::Module:
+  case Scope::Kind::MainProgram:
+  case Scope::Kind::Subprogram:
+  case Scope::Kind::BlockData:
+  case Scope::Kind::Block: {
+    std::list<std::list<SymbolRef>> associations{GetStorageAssociations(scope)};
+    for (const std::list<SymbolRef> &associated : associations) {
+      if (std::find_if(associated.begin(), associated.end(), [](SymbolRef ref) {
+            return IsInitialized(*ref);
+          }) != associated.end()) {
+        result &=
+            CombineEquivalencedInitialization(associated, exprAnalyzer, inits);
+      }
+    }
+    if constexpr (makeDefaultInitializationExplicit) {
+      MakeDefaultInitializationExplicit(
+          scope, associations, exprAnalyzer.GetFoldingContext(), inits);
+    }
+    for (const Scope &child : scope.children()) {
+      result &= ProcessScopes(child, exprAnalyzer, inits);
+    }
+  } break;
+  default:;
+  }
+  return result;
+}
+
+// Converts the static initialization image for a single symbol with
+// one or more DATA statement appearances.
 void ConstructInitializer(const Symbol &symbol,
     SymbolDataInitialization &initialization,
     evaluate::ExpressionAnalyzer &exprAnalyzer) {
+  std::list<SymbolRef> symbols{symbol};
+  CheckForOverlappingInitialization(
+      symbols, initialization, exprAnalyzer, "DATA statement initializations"s);
   auto &context{exprAnalyzer.GetFoldingContext()};
-  initialization.inits.sort();
-  ConstantSubscript next{0};
-  for (const auto &init : initialization.inits) {
-    if (init.start() < next) {
-      auto badDesignator{evaluate::OffsetToDesignator(
-          context, symbol, init.start(), init.size())};
-      CHECK(badDesignator);
-      exprAnalyzer.Say(symbol.name(),
-          "DATA statement initializations affect '%s' more than once"_err_en_US,
-          badDesignator->AsFortran());
-    }
-    next = init.start() + init.size();
-    CHECK(next <= static_cast<ConstantSubscript>(initialization.image.size()));
-  }
   if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
     CHECK(IsProcedurePointer(symbol));
-    const auto &procDesignator{initialization.image.AsConstantProcPointer()};
-    CHECK(!procDesignator.GetComponent());
     auto &mutableProc{const_cast<ProcEntityDetails &>(*proc)};
-    mutableProc.set_init(DEREF(procDesignator.GetSymbol()));
+    if (MaybeExpr expr{initialization.image.AsConstantPointer()}) {
+      if (const auto *procDesignator{
+              std::get_if<evaluate::ProcedureDesignator>(&expr->u)}) {
+        CHECK(!procDesignator->GetComponent());
+        mutableProc.set_init(DEREF(procDesignator->GetSymbol()));
+      } else {
+        CHECK(evaluate::IsNullPointer(*expr));
+        mutableProc.set_init(nullptr);
+      }
+    } else {
+      mutableProc.set_init(nullptr);
+    }
   } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
-    if (auto symbolType{evaluate::DynamicType::From(symbol)}) {
-      auto &mutableObject{const_cast<ObjectEntityDetails &>(*object)};
-      if (IsPointer(symbol)) {
+    auto &mutableObject{const_cast<ObjectEntityDetails &>(*object)};
+    if (IsPointer(symbol)) {
+      if (auto ptr{initialization.image.AsConstantPointer()}) {
+        mutableObject.set_init(*ptr);
+      } else {
+        mutableObject.set_init(SomeExpr{evaluate::NullPointer{}});
+      }
+    } else if (auto symbolType{evaluate::DynamicType::From(symbol)}) {
+      if (auto extents{evaluate::GetConstantExtents(context, symbol)}) {
         mutableObject.set_init(
-            initialization.image.AsConstantDataPointer(*symbolType));
+            initialization.image.AsConstant(context, *symbolType, *extents));
       } else {
-        if (auto extents{evaluate::GetConstantExtents(context, symbol)}) {
-          mutableObject.set_init(
-              initialization.image.AsConstant(context, *symbolType, *extents));
-        } else {
-          exprAnalyzer.Say(symbol.name(),
-              "internal: unknown shape for '%s' while constructing initializer from DATA"_err_en_US,
-              symbol.name());
-          return;
-        }
+        exprAnalyzer.Say(symbol.name(),
+            "internal: unknown shape for '%s' while constructing initializer from DATA"_err_en_US,
+            symbol.name());
+        return;
       }
     } else {
       exprAnalyzer.Say(symbol.name(),
@@ -552,10 +840,11 @@ void ConstructInitializer(const Symbol &symbol,
 
 void ConvertToInitializers(
     DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer) {
-  while (CombineSomeEquivalencedInits(inits, exprAnalyzer)) {
-  }
-  for (auto &[symbolPtr, initialization] : inits) {
-    ConstructInitializer(*symbolPtr, initialization, exprAnalyzer);
+  if (ProcessScopes(
+          exprAnalyzer.context().globalScope(), exprAnalyzer, inits)) {
+    for (auto &[symbolPtr, initialization] : inits) {
+      ConstructInitializer(*symbolPtr, initialization, exprAnalyzer);
+    }
   }
 }
 } // namespace Fortran::semantics

diff  --git a/flang/lib/Semantics/data-to-inits.h b/flang/lib/Semantics/data-to-inits.h
index 87926fc957c59..fd07396d22099 100644
--- a/flang/lib/Semantics/data-to-inits.h
+++ b/flang/lib/Semantics/data-to-inits.h
@@ -28,8 +28,9 @@ class Symbol;
 struct SymbolDataInitialization {
   using Range = common::Interval<common::ConstantSubscript>;
   explicit SymbolDataInitialization(std::size_t bytes) : image{bytes} {}
+  SymbolDataInitialization(SymbolDataInitialization &&) = default;
   evaluate::InitialImage image;
-  std::list<Range> inits;
+  std::list<Range> initializedRanges;
 };
 
 using DataInitializations = std::map<const Symbol *, SymbolDataInitialization>;

diff  --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 005342007302c..e93e4fbf1935a 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -184,11 +184,25 @@ bool ModFileWriter::PutSymbols(const Scope &scope) {
   std::string buf; // stuff after CONTAINS in derived type
   llvm::raw_string_ostream typeBindings{buf};
   for (const Symbol &symbol : sorted) {
-    PutSymbol(typeBindings, symbol);
+    if (!symbol.test(Symbol::Flag::CompilerCreated)) {
+      PutSymbol(typeBindings, symbol);
+    }
   }
   for (const Symbol &symbol : uses) {
     PutUse(symbol);
   }
+  for (const auto &set : scope.equivalenceSets()) {
+    if (!set.empty() &&
+        !set.front().symbol.test(Symbol::Flag::CompilerCreated)) {
+      char punctuation{'('};
+      decls_ << "equivalence";
+      for (const auto &object : set) {
+        decls_ << punctuation << object.AsFortran();
+        punctuation = ',';
+      }
+      decls_ << ")\n";
+    }
+  }
   if (auto str{typeBindings.str()}; !str.empty()) {
     CHECK(scope.IsDerivedType());
     decls_ << "contains\n" << str;

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 35c29818ae34e..4fbea2962b0a9 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -3757,7 +3757,7 @@ Symbol &DeclarationVisitor::DeclareUnknownEntity(
 
 bool DeclarationVisitor::HasCycle(
     const Symbol &procSymbol, const ProcInterface &interface) {
-  OrderedSymbolSet procsInCycle;
+  SourceOrderedSymbolSet procsInCycle;
   procsInCycle.insert(procSymbol);
   const ProcInterface *thisInterface{&interface};
   bool haveInterface{true};
@@ -5390,7 +5390,7 @@ bool ConstructVisitor::Pre(const parser::DataImpliedDo &x) {
 }
 
 // Sets InDataStmt flag on a variable (or misidentified function) in a DATA
-// statement so that the predicate IsStaticallyInitialized() will be true
+// statement so that the predicate IsInitialized() will be true
 // during semantic analysis before the symbol's initializer is constructed.
 bool ConstructVisitor::Pre(const parser::DataIDoObject &x) {
   std::visit(

diff  --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index 045ced4514eaa..e7879c72060c2 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -264,11 +264,11 @@ static SomeExpr SaveNumericPointerTarget(
     object.set_shape(arraySpec);
     object.set_init(evaluate::AsGenericExpr(evaluate::Constant<T>{
         std::move(x), evaluate::ConstantSubscripts{elements}}));
-    const Symbol &symbol{
-        *scope
-             .try_emplace(
-                 name, Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
-             .first->second};
+    Symbol &symbol{*scope
+                        .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
+                            std::move(object))
+                        .first->second};
+    symbol.set(Symbol::Flag::CompilerCreated);
     return evaluate::AsGenericExpr(
         evaluate::Expr<T>{evaluate::Designator<T>{symbol}});
   }
@@ -301,11 +301,11 @@ static SomeExpr SaveDerivedPointerTarget(Scope &scope, SourceName name,
     object.set_init(
         evaluate::AsGenericExpr(evaluate::Constant<evaluate::SomeDerived>{
             derivedType, std::move(x), std::move(shape)}));
-    const Symbol &symbol{
-        *scope
-             .try_emplace(
-                 name, Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
-             .first->second};
+    Symbol &symbol{*scope
+                        .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
+                            std::move(object))
+                        .first->second};
+    symbol.set(Symbol::Flag::CompilerCreated);
     return evaluate::AsGenericExpr(
         evaluate::Designator<evaluate::SomeDerived>{symbol});
   }
@@ -313,11 +313,12 @@ static SomeExpr SaveDerivedPointerTarget(Scope &scope, SourceName name,
 
 static SomeExpr SaveObjectInit(
     Scope &scope, SourceName name, const ObjectEntityDetails &object) {
-  const Symbol &symbol{*scope
-                            .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
-                                ObjectEntityDetails{object})
-                            .first->second};
+  Symbol &symbol{*scope
+                      .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
+                          ObjectEntityDetails{object})
+                      .first->second};
   CHECK(symbol.get<ObjectEntityDetails>().init().has_value());
+  symbol.set(Symbol::Flag::CompilerCreated);
   return evaluate::AsGenericExpr(
       evaluate::Designator<evaluate::SomeDerived>{symbol});
 }
@@ -615,6 +616,7 @@ Symbol &RuntimeTableBuilder::CreateObject(
       Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))};
   CHECK(pair.second);
   Symbol &result{*pair.first->second};
+  result.set(Symbol::Flag::CompilerCreated);
   return result;
 }
 
@@ -638,11 +640,11 @@ SomeExpr RuntimeTableBuilder::SaveNameAsPointerTarget(
   using Ascii = evaluate::Type<TypeCategory::Character, 1>;
   using AsciiExpr = evaluate::Expr<Ascii>;
   object.set_init(evaluate::AsGenericExpr(AsciiExpr{name}));
-  const Symbol &symbol{
-      *scope
-           .try_emplace(SaveObjectName(".n."s + name),
-               Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
-           .first->second};
+  Symbol &symbol{*scope
+                      .try_emplace(SaveObjectName(".n."s + name),
+                          Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
+                      .first->second};
+  symbol.set(Symbol::Flag::CompilerCreated);
   return evaluate::AsGenericExpr(
       AsciiExpr{evaluate::Designator<Ascii>{symbol}});
 }
@@ -819,6 +821,7 @@ bool RuntimeTableBuilder::InitializeDataPointer(
         ".dp."s + distinctName + "."s + symbol.name().ToString())};
     Symbol &ptrDtSym{
         *scope.try_emplace(ptrDtName, Attrs{}, UnknownDetails{}).first->second};
+    ptrDtSym.set(Symbol::Flag::CompilerCreated);
     Scope &ptrDtScope{scope.MakeScope(Scope::Kind::DerivedType, &ptrDtSym)};
     ignoreScopes_.insert(&ptrDtScope);
     ObjectEntityDetails ptrDtObj;

diff  --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index 8236e96ec1203..60e4572547857 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -676,4 +676,38 @@ bool GenericKind::Is(GenericKind::OtherKind x) const {
   return y && *y == x;
 }
 
+bool SymbolOffsetCompare::operator()(
+    const SymbolRef &x, const SymbolRef &y) const {
+  const Symbol *xCommon{FindCommonBlockContaining(*x)};
+  const Symbol *yCommon{FindCommonBlockContaining(*y)};
+  if (xCommon) {
+    if (yCommon) {
+      const SymbolSourcePositionCompare sourceCmp;
+      if (sourceCmp(*xCommon, *yCommon)) {
+        return true;
+      } else if (sourceCmp(*yCommon, *xCommon)) {
+        return false;
+      } else if (x->offset() == y->offset()) {
+        return x->size() > y->size();
+      } else {
+        return x->offset() < y->offset();
+      }
+    } else {
+      return false;
+    }
+  } else if (yCommon) {
+    return true;
+  } else if (x->offset() == y->offset()) {
+    return x->size() > y->size();
+  } else {
+    return x->offset() < y->offset();
+  }
+  return x->GetSemanticsContext().allCookedSources().Precedes(
+      x->name(), y->name());
+}
+bool SymbolOffsetCompare::operator()(
+    const MutableSymbolRef &x, const MutableSymbolRef &y) const {
+  return (*this)(SymbolRef{*x}, SymbolRef{*y});
+}
+
 } // namespace Fortran::semantics

diff  --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index 7cd6382fea6d9..69d63310ca1bc 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -507,6 +507,18 @@ const DeclTypeSpec *FindParentTypeSpec(const Symbol &symbol) {
   return nullptr;
 }
 
+const EquivalenceSet *FindEquivalenceSet(const Symbol &symbol) {
+  const Symbol &ultimate{symbol.GetUltimate()};
+  for (const EquivalenceSet &set : ultimate.owner().equivalenceSets()) {
+    for (const EquivalenceObject &object : set) {
+      if (object.symbol == ultimate) {
+        return &set;
+      }
+    }
+  }
+  return nullptr;
+}
+
 bool IsExtensibleType(const DerivedTypeSpec *derived) {
   return derived && !IsIsoCType(derived) &&
       !derived->typeSymbol().attrs().test(Attr::BIND_C) &&
@@ -569,34 +581,36 @@ bool CanBeTypeBoundProc(const Symbol *symbol) {
   }
 }
 
-bool IsStaticallyInitialized(const Symbol &symbol, bool ignoreDATAstatements) {
-  if (!ignoreDATAstatements && symbol.test(Symbol::Flag::InDataStmt)) {
-    return true;
-  } else if (IsNamedConstant(symbol)) {
+bool HasDeclarationInitializer(const Symbol &symbol) {
+  if (IsNamedConstant(symbol)) {
     return false;
   } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
     return object->init().has_value();
   } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
     return proc->init().has_value();
+  } else {
+    return false;
   }
-  return false;
 }
 
-bool IsInitialized(const Symbol &symbol, bool ignoreDATAstatements,
-    const Symbol *derivedTypeSymbol) {
-  if (IsStaticallyInitialized(symbol, ignoreDATAstatements) ||
-      IsAllocatable(symbol)) {
+bool IsInitialized(const Symbol &symbol, bool ignoreDataStatements) {
+  if (IsAllocatable(symbol) ||
+      (!ignoreDataStatements && symbol.test(Symbol::Flag::InDataStmt)) ||
+      HasDeclarationInitializer(symbol)) {
     return true;
   } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol) ||
       IsPointer(symbol)) {
     return false;
   } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
     if (!object->isDummy() && object->type()) {
-      const auto *derived{object->type()->AsDerived()};
-      // error recovery: avoid infinite recursion on invalid
-      // recursive usage of a derived type
-      return derived && &derived->typeSymbol() != derivedTypeSymbol &&
-          derived->HasDefaultInitialization();
+      if (const auto *derived{object->type()->AsDerived()}) {
+        DirectComponentIterator directs{*derived};
+        return bool{std::find_if(
+            directs.begin(), directs.end(), [](const Symbol &component) {
+              return IsAllocatable(component) ||
+                  HasDeclarationInitializer(component);
+            })};
+      }
     }
   }
   return false;
@@ -788,6 +802,39 @@ bool IsExternal(const Symbol &symbol) {
   return ClassifyProcedure(symbol) == ProcedureDefinitionClass::External;
 }
 
+// Most scopes have no EQUIVALENCE, and this function is a fast no-op for them.
+std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &scope) {
+  UnorderedSymbolSet distinct;
+  for (const EquivalenceSet &set : scope.equivalenceSets()) {
+    for (const EquivalenceObject &object : set) {
+      distinct.emplace(object.symbol);
+    }
+  }
+  // This set is ordered by ascending offsets, with ties broken by greatest
+  // size.  A multiset is used here because multiple symbols may have the
+  // same offset and size; the symbols in the set, however, are distinct.
+  std::multiset<SymbolRef, SymbolOffsetCompare> associated;
+  for (SymbolRef ref : distinct) {
+    associated.emplace(*ref);
+  }
+  std::list<std::list<SymbolRef>> result;
+  std::size_t limit{0};
+  const Symbol *currentCommon{nullptr};
+  for (const Symbol &symbol : associated) {
+    const Symbol *thisCommon{FindCommonBlockContaining(symbol)};
+    if (result.empty() || symbol.offset() >= limit ||
+        thisCommon != currentCommon) {
+      // Start a new group
+      result.emplace_back(std::list<SymbolRef>{});
+      limit = 0;
+      currentCommon = thisCommon;
+    }
+    result.back().emplace_back(symbol);
+    limit = std::max(limit, symbol.offset() + symbol.size());
+  }
+  return result;
+}
+
 bool IsModuleProcedure(const Symbol &symbol) {
   return ClassifyProcedure(symbol) == ProcedureDefinitionClass::Module;
 }

diff  --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index dc9be0022bb2e..69145b90c4e31 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -179,10 +179,8 @@ bool DerivedTypeSpec::IsForwardReferenced() const {
 
 bool DerivedTypeSpec::HasDefaultInitialization() const {
   DirectComponentIterator components{*this};
-  return bool{std::find_if(
-      components.begin(), components.end(), [&](const Symbol &component) {
-        return IsInitialized(component, false, &typeSymbol());
-      })};
+  return bool{std::find_if(components.begin(), components.end(),
+      [&](const Symbol &component) { return IsInitialized(component); })};
 }
 
 bool DerivedTypeSpec::HasDestruction() const {

diff  --git a/flang/test/Semantics/data12.f90 b/flang/test/Semantics/data12.f90
new file mode 100644
index 0000000000000..0ceba176a8bc0
--- /dev/null
+++ b/flang/test/Semantics/data12.f90
@@ -0,0 +1,35 @@
+! RUN: %S/test_errors.sh %s %t %flang_fc1
+! REQUIRES: shell
+type :: t1
+  sequence
+  integer :: m = 123
+  integer :: pad
+end type
+type :: t2
+  sequence
+  integer :: n = 123
+  integer :: pad
+end type
+type :: t3
+  sequence
+  integer :: k = 234
+  integer :: pad
+end type
+!ERROR: Distinct default component initializations of equivalenced objects affect 'x1a%m' more than once
+type(t1) :: x1a
+!ERROR: Distinct default component initializations of equivalenced objects affect 'x2a%n' more than once
+type(t2) :: x2a
+!ERROR: Distinct default component initializations of equivalenced objects affect 'x3%k' more than once
+type(t3), save :: x3
+!ERROR: Explicit initializations of equivalenced objects affect 'ja(2_8)' more than once
+!ERROR: Explicit initializations of equivalenced objects affect 'ka(1_8)' more than once
+integer :: ja(2), ka(2)
+data ja/345, 456/
+data ka/456, 567/
+equivalence(x1a, x2a, x3)
+! Same value: no error
+type(t1) :: x1b
+type(t2) :: x2b
+equivalence(x1b, x2b)
+equivalence(ja(2),ka(1))
+end

diff  --git a/flang/test/Semantics/data13.f90 b/flang/test/Semantics/data13.f90
new file mode 100644
index 0000000000000..4d7ecf9939e07
--- /dev/null
+++ b/flang/test/Semantics/data13.f90
@@ -0,0 +1,32 @@
+! RUN: %flang_fc1 -fsyntax-only -fdebug-dump-symbols %s 2>&1 | FileCheck %s
+! Verify that the closure of EQUIVALENCE'd symbols with any DATA
+! initialization produces a combined initializer, with explicit
+! initialization overriding any default component initialization.
+! CHECK: .F18.0, SAVE (CompilerCreated) size=8 offset=0: ObjectEntity type: INTEGER(4) shape: 1_8:2_8 init:[INTEGER(4)::456_4,234_4]
+! CHECK: ja (InDataStmt) size=8 offset=0: ObjectEntity type: INTEGER(4) shape: 1_8:2_8
+! CHECK-NOT: x0, SAVE size=8 offset=8: ObjectEntity type: TYPE(t1) init:t1(m=123_4,n=234_4)
+! CHECK: x1 size=8 offset=16: ObjectEntity type: TYPE(t1) init:t1(m=345_4,n=234_4)
+! CHECK: x2 size=8 offset=0: ObjectEntity type: TYPE(t1)
+! CHECK-NOT: x3a, SAVE size=8 offset=24: ObjectEntity type: TYPE(t3) init:t3(t2=t2(k=567_4),j=0_4)
+! CHECK: x3b size=8 offset=32: ObjectEntity type: TYPE(t3) init:t3(k=567_4,j=678_4)
+! CHECK: Equivalence Sets: (x2,ja(1)) (.F18.0,x2)
+type :: t1
+  sequence
+  integer :: m = 123
+  integer :: n = 234
+end type
+type :: t2
+  integer :: k = 567
+end type
+type, extends(t2) :: t3
+  integer :: j ! uninitialized
+end type
+type(t1), save :: x0 ! not enabled
+type(t1) :: x1 = t1(m=345)
+type(t1) :: x2
+type(t3), save :: x3a ! not enabled
+type(t3) :: x3b = t3(j=678)
+integer :: ja(2)
+equivalence(x2, ja)
+data ja(1)/456/
+end

diff  --git a/flang/test/Semantics/typeinfo01.f90 b/flang/test/Semantics/typeinfo01.f90
index 52dd5d5d77b50..7c374bc0d5bcb 100644
--- a/flang/test/Semantics/typeinfo01.f90
+++ b/flang/test/Semantics/typeinfo01.f90
@@ -6,10 +6,10 @@ module m01
     integer :: n
   end type
 !CHECK: Module scope: m01
-!CHECK: .c.t1, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.n,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
-!CHECK: .dt.t1, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .n.n, SAVE, TARGET: ObjectEntity type: CHARACTER(1_8,1) init:"n"
-!CHECK: .n.t1, SAVE, TARGET: ObjectEntity type: CHARACTER(2_8,1) init:"t1"
+!CHECK: .c.t1, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.n,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
+!CHECK: .dt.t1, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t1,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .n.n, SAVE, TARGET (CompilerCreated): ObjectEntity type: CHARACTER(1_8,1) init:"n"
+!CHECK: .n.t1, SAVE, TARGET (CompilerCreated): ObjectEntity type: CHARACTER(2_8,1) init:"t1"
 !CHECK: DerivedType scope: t1
 end module
 
@@ -20,10 +20,10 @@ module m02
   type, extends(parent) :: child
     integer :: cn
   end type
-!CHECK: .c.child, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:1_8 init:[component::component(name=.n.parent,genre=1_1,category=5_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=.dt.parent,lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.cn,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=4_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
-!CHECK: .c.parent, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.pn,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
-!CHECK: .dt.child, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.child,sizeinbytes=8_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.child,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .dt.parent, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.parent,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.parent,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .c.child, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(component) shape: 0_8:1_8 init:[component::component(name=.n.parent,genre=1_1,category=5_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=.dt.parent,lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.cn,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=4_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
+!CHECK: .c.parent, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.pn,genre=1_1,category=0_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
+!CHECK: .dt.child, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.child,sizeinbytes=8_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.child,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .dt.parent, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.parent,sizeinbytes=4_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.parent,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
 end module
 
 module m03
@@ -32,11 +32,11 @@ module m03
     real(kind=k) :: a
   end type
   type(kpdt(4)) :: x
-!CHECK: .c.kpdt.0, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.a,genre=1_1,category=1_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
-!CHECK: .dt.kpdt, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.kpdt,uninstantiated=NULL(),kindparameter=.kp.kpdt,lenparameterkind=NULL())
-!CHECK: .dt.kpdt.0, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.kpdt,sizeinbytes=4_8,uninstantiated=.dt.kpdt,kindparameter=.kp.kpdt.0,lenparameterkind=NULL(),component=.c.kpdt.0,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .kp.kpdt, SAVE, TARGET: ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::1_8]
-!CHECK: .kp.kpdt.0, SAVE, TARGET: ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::4_8]
+!CHECK: .c.kpdt.0, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.a,genre=1_1,category=1_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
+!CHECK: .dt.kpdt, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.kpdt,uninstantiated=NULL(),kindparameter=.kp.kpdt,lenparameterkind=NULL())
+!CHECK: .dt.kpdt.0, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.kpdt,sizeinbytes=4_8,uninstantiated=.dt.kpdt,kindparameter=.kp.kpdt.0,lenparameterkind=NULL(),component=.c.kpdt.0,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .kp.kpdt, SAVE, TARGET (CompilerCreated): ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::1_8]
+!CHECK: .kp.kpdt.0, SAVE, TARGET (CompilerCreated): ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::4_8]
 end module
 
 module m04
@@ -49,8 +49,8 @@ module m04
   subroutine s1(x)
     class(tbps), intent(in) :: x
   end subroutine
-!CHECK: .dt.tbps, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.tbps,name=.n.tbps,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .v.tbps, SAVE, TARGET: ObjectEntity type: TYPE(binding) shape: 0_8:1_8 init:[binding::binding(proc=s1,name=.n.b1),binding(proc=s1,name=.n.b2)]
+!CHECK: .dt.tbps, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.tbps,name=.n.tbps,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .v.tbps, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(binding) shape: 0_8:1_8 init:[binding::binding(proc=s1,name=.n.b1),binding(proc=s1,name=.n.b2)]
 end module
 
 module m05
@@ -61,8 +61,8 @@ module m05
   subroutine s1(x)
     class(t), intent(in) :: x
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=24_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .p.t, SAVE, TARGET: ObjectEntity type: TYPE(procptrcomponent) shape: 0_8:0_8 init:[procptrcomponent::procptrcomponent(name=.n.p1,offset=0_8,initialization=s1)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=24_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=.p.t,special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .p.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(procptrcomponent) shape: 0_8:0_8 init:[procptrcomponent::procptrcomponent(name=.n.p1,offset=0_8,initialization=s1)]
 end module
 
 module m06
@@ -84,12 +84,12 @@ subroutine s2(x, y)
     class(t2), intent(out) :: x
     class(t), intent(in) :: y
   end subroutine
-!CHECK: .c.t2, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.t,genre=1_1,category=5_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=.dt.t,lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
-!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=2_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .dt.t2, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t2,name=.n.t2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET: ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=1_1,isargdescriptorset=3_1,proc=s1)]
-!CHECK: .v.t, SAVE, TARGET: ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)]
-!CHECK: .v.t2, SAVE, TARGET: ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s2,name=.n.s1)]
+!CHECK: .c.t2, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.t,genre=1_1,category=5_1,kind=0_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=.dt.t,lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=2_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .dt.t2, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t2,name=.n.t2,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.t2,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=1_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=1_1,isargdescriptorset=3_1,proc=s1)]
+!CHECK: .v.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)]
+!CHECK: .v.t2, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s2,name=.n.s1)]
 end module
 
 module m07
@@ -103,9 +103,9 @@ impure elemental subroutine s1(x, y)
     class(t), intent(out) :: x
     class(t), intent(in) :: y
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=4_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET: ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,proc=s1)]
-!CHECK: .v.t, SAVE, TARGET: ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=4_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,proc=s1)]
+!CHECK: .v.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)]
 end module
 
 module m08
@@ -123,8 +123,8 @@ subroutine s2(x)
   impure elemental subroutine s3(x)
     type(t) :: x
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=3200_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1)
-!CHECK: .s.t, SAVE, TARGET: ObjectEntity type: TYPE(specialbinding) shape: 0_8:2_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=0_1,proc=s3),specialbinding(which=10_1,isargdescriptorset=1_1,proc=s1),specialbinding(which=11_1,isargdescriptorset=0_1,proc=s2)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=3200_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(specialbinding) shape: 0_8:2_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=0_1,proc=s3),specialbinding(which=10_1,isargdescriptorset=1_1,proc=s1),specialbinding(which=11_1,isargdescriptorset=0_1,proc=s2)]
 end module
 
 module m09
@@ -165,9 +165,9 @@ subroutine wu(x,u,iostat,iomsg)
     integer, intent(out) :: iostat
     character(len=*), intent(inout) :: iomsg
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET: ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=1_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=1_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=1_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=1_1,proc=wu)]
-!CHECK: .v.t, SAVE, TARGET: ObjectEntity type: TYPE(binding) shape: 0_8:3_8 init:[binding::binding(proc=rf,name=.n.rf),binding(proc=ru,name=.n.ru),binding(proc=wf,name=.n.wf),binding(proc=wu,name=.n.wu)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=1_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=1_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=1_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=1_1,proc=wu)]
+!CHECK: .v.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(binding) shape: 0_8:3_8 init:[binding::binding(proc=rf,name=.n.rf),binding(proc=ru,name=.n.ru),binding(proc=wf,name=.n.wf),binding(proc=wu,name=.n.wu)]
 end module
 
 module m10
@@ -214,8 +214,8 @@ subroutine wu(x,u,iostat,iomsg)
     integer, intent(out) :: iostat
     character(len=*), intent(inout) :: iomsg
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET: ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=0_1,proc=wu)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=0_1,proc=wu)]
 end module
 
 module m11
@@ -227,16 +227,16 @@ module m11
     character(len=len) :: chauto
     real :: automatic(len)
   end type
-!CHECK: .dt.t, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.t)
-!CHECK: .lpk.t, SAVE, TARGET: ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.t)
+!CHECK: .lpk.t, SAVE, TARGET (CompilerCreated): ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1]
  contains
   subroutine s1(x)
-!CHECK: .b.t.1.automatic, SAVE, TARGET: ObjectEntity type: TYPE(value) shape: 0_8:1_8,0_8:0_8 init:reshape([value::value(genre=2_1,value=1_8),value(genre=3_1,value=0_8)],shape=[2,1])
-!CHECK: .c.t.1, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:3_8 init:[component::component(name=.n.allocatable,genre=3_1,category=1_1,kind=4_1,rank=1_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.pointer,genre=2_1,category=1_1,kind=4_1,rank=0_1,offset=48_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=.di.t.1.pointer),component(name=.n.chauto,genre=4_1,category=3_1,kind=1_1,rank=0_1,offset=72_8,characterlen=value(genre=3_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.automatic,genre=4_1,category=1_1,kind=4_1,rank=1_1,offset=96_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.1.automatic,initialization=NULL())]
-!CHECK: .di.t.1.pointer, SAVE, TARGET: ObjectEntity type: TYPE(.dp.t.1.pointer) init:.dp.t.1.pointer(pointer=target)
-!CHECK: .dp.t.1.pointer: DerivedType components: pointer
-!CHECK: .dt.t.1, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=144_8,uninstantiated=.dt.t,kindparameter=NULL(),lenparameterkind=.lpk.t.1,component=.c.t.1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1)
-!CHECK: .lpk.t.1, SAVE, TARGET: ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1]
+!CHECK: .b.t.1.automatic, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(value) shape: 0_8:1_8,0_8:0_8 init:reshape([value::value(genre=2_1,value=1_8),value(genre=3_1,value=0_8)],shape=[2,1])
+!CHECK: .c.t.1, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(component) shape: 0_8:3_8 init:[component::component(name=.n.allocatable,genre=3_1,category=1_1,kind=4_1,rank=1_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.pointer,genre=2_1,category=1_1,kind=4_1,rank=0_1,offset=48_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=.di.t.1.pointer),component(name=.n.chauto,genre=4_1,category=3_1,kind=1_1,rank=0_1,offset=72_8,characterlen=value(genre=3_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.automatic,genre=4_1,category=1_1,kind=4_1,rank=1_1,offset=96_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.1.automatic,initialization=NULL())]
+!CHECK: .di.t.1.pointer, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(.dp.t.1.pointer) init:.dp.t.1.pointer(pointer=target)
+!CHECK: .dp.t.1.pointer (CompilerCreated): DerivedType components: pointer
+!CHECK: .dt.t.1, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=144_8,uninstantiated=.dt.t,kindparameter=NULL(),lenparameterkind=.lpk.t.1,component=.c.t.1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1)
+!CHECK: .lpk.t.1, SAVE, TARGET (CompilerCreated): ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1]
 !CHECK: DerivedType scope: .dp.t.1.pointer size=24 alignment=8 instantiation of .dp.t.1.pointer
 !CHECK: pointer, POINTER size=24 offset=0: ObjectEntity type: REAL(4)
     type(t(*)), intent(in) :: x
@@ -248,9 +248,9 @@ module m12
     integer :: n
     integer :: n2
     integer :: n_3
-    ! CHECK: .n.n, SAVE, TARGET: ObjectEntity type: CHARACTER(1_8,1) init:"n"
-    ! CHECK: .n.n2, SAVE, TARGET: ObjectEntity type: CHARACTER(2_8,1) init:"n2"
-    ! CHECK: .n.n_3, SAVE, TARGET: ObjectEntity type: CHARACTER(3_8,1) init:"n_3"
+    ! CHECK: .n.n, SAVE, TARGET (CompilerCreated): ObjectEntity type: CHARACTER(1_8,1) init:"n"
+    ! CHECK: .n.n2, SAVE, TARGET (CompilerCreated): ObjectEntity type: CHARACTER(2_8,1) init:"n2"
+    ! CHECK: .n.n_3, SAVE, TARGET (CompilerCreated): ObjectEntity type: CHARACTER(3_8,1) init:"n_3"
   end type
 end module
 
@@ -260,7 +260,7 @@ module m13
    contains
     procedure :: assign1, assign2
     generic :: assignment(=) => assign1, assign2
-    ! CHECK: .s.t1, SAVE, TARGET: ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,proc=assign1)]
+    ! CHECK: .s.t1, SAVE, TARGET (CompilerCreated): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,proc=assign1)]
   end type
  contains
   impure elemental subroutine assign1(to, from)


        


More information about the flang-commits mailing list