xref: /llvm-project/flang/lib/Semantics/runtime-type-info.cpp (revision 050f785e2c57ce4ad4d788660c898b985a25ffe7)
14fede8bcSpeter klausler //===-- lib/Semantics/runtime-type-info.cpp ---------------------*- C++ -*-===//
24fede8bcSpeter klausler //
34fede8bcSpeter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44fede8bcSpeter klausler // See https://llvm.org/LICENSE.txt for license information.
54fede8bcSpeter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64fede8bcSpeter klausler //
74fede8bcSpeter klausler //===----------------------------------------------------------------------===//
84fede8bcSpeter klausler 
94fede8bcSpeter klausler #include "flang/Semantics/runtime-type-info.h"
104fede8bcSpeter klausler #include "mod-file.h"
114fede8bcSpeter klausler #include "flang/Evaluate/fold-designator.h"
124fede8bcSpeter klausler #include "flang/Evaluate/fold.h"
134fede8bcSpeter klausler #include "flang/Evaluate/tools.h"
144fede8bcSpeter klausler #include "flang/Evaluate/type.h"
15cfd4c180SSlava Zakharin #include "flang/Optimizer/Support/InternalNames.h"
164fede8bcSpeter klausler #include "flang/Semantics/scope.h"
174fede8bcSpeter klausler #include "flang/Semantics/tools.h"
1865f52904Speter klausler #include <functional>
194fede8bcSpeter klausler #include <list>
204fede8bcSpeter klausler #include <map>
214fede8bcSpeter klausler #include <string>
224fede8bcSpeter klausler 
237cf1608bSPeter Klausler // The symbols added by this code to various scopes in the program include:
247cf1608bSPeter Klausler //   .b.TYPE.NAME  - Bounds values for an array component
257cf1608bSPeter Klausler //   .c.TYPE       - TYPE(Component) descriptions for TYPE
267cf1608bSPeter Klausler //   .di.TYPE.NAME - Data initialization for a component
277cf1608bSPeter Klausler //   .dp.TYPE.NAME - Data pointer initialization for a component
287cf1608bSPeter Klausler //   .dt.TYPE      - TYPE(DerivedType) description for TYPE
297cf1608bSPeter Klausler //   .kp.TYPE      - KIND type parameter values for TYPE
307cf1608bSPeter Klausler //   .lpk.TYPE     - Integer kinds of LEN type parameter values
317cf1608bSPeter Klausler //   .lv.TYPE.NAME - LEN type parameter values for a component's type
327cf1608bSPeter Klausler //   .n.NAME       - Character representation of a name
337cf1608bSPeter Klausler //   .p.TYPE       - TYPE(ProcPtrComponent) descriptions for TYPE
347cf1608bSPeter Klausler //   .s.TYPE       - TYPE(SpecialBinding) bindings for TYPE
357cf1608bSPeter Klausler //   .v.TYPE       - TYPE(Binding) bindings for TYPE
367cf1608bSPeter Klausler 
374fede8bcSpeter klausler namespace Fortran::semantics {
384fede8bcSpeter klausler 
394fede8bcSpeter klausler static int FindLenParameterIndex(
404fede8bcSpeter klausler     const SymbolVector &parameters, const Symbol &symbol) {
414fede8bcSpeter klausler   int lenIndex{0};
424fede8bcSpeter klausler   for (SymbolRef ref : parameters) {
434fede8bcSpeter klausler     if (&*ref == &symbol) {
444fede8bcSpeter klausler       return lenIndex;
454fede8bcSpeter klausler     }
46539a6b50SPeter Klausler     if (auto attr{ref->get<TypeParamDetails>().attr()};
47539a6b50SPeter Klausler         attr && *attr == common::TypeParamAttr::Len) {
484fede8bcSpeter klausler       ++lenIndex;
494fede8bcSpeter klausler     }
504fede8bcSpeter klausler   }
514fede8bcSpeter klausler   DIE("Length type parameter not found in parameter order");
524fede8bcSpeter klausler   return -1;
534fede8bcSpeter klausler }
544fede8bcSpeter klausler 
554fede8bcSpeter klausler class RuntimeTableBuilder {
564fede8bcSpeter klausler public:
574fede8bcSpeter klausler   RuntimeTableBuilder(SemanticsContext &, RuntimeDerivedTypeTables &);
58a48e4168Speter klausler   void DescribeTypes(Scope &scope, bool inSchemata);
594fede8bcSpeter klausler 
604fede8bcSpeter klausler private:
614fede8bcSpeter klausler   const Symbol *DescribeType(Scope &);
624fede8bcSpeter klausler   const Symbol &GetSchemaSymbol(const char *) const;
634fede8bcSpeter klausler   const DeclTypeSpec &GetSchema(const char *) const;
644fede8bcSpeter klausler   SomeExpr GetEnumValue(const char *) const;
654fede8bcSpeter klausler   Symbol &CreateObject(const std::string &, const DeclTypeSpec &, Scope &);
664fede8bcSpeter klausler   // The names of created symbols are saved in and owned by the
674fede8bcSpeter klausler   // RuntimeDerivedTypeTables instance returned by
684fede8bcSpeter klausler   // BuildRuntimeDerivedTypeTables() so that references to those names remain
694fede8bcSpeter klausler   // valid for lowering.
704fede8bcSpeter klausler   SourceName SaveObjectName(const std::string &);
714fede8bcSpeter klausler   SomeExpr SaveNameAsPointerTarget(Scope &, const std::string &);
724fede8bcSpeter klausler   const SymbolVector *GetTypeParameters(const Symbol &);
734fede8bcSpeter klausler   evaluate::StructureConstructor DescribeComponent(const Symbol &,
741971960aSJean Perier       const ObjectEntityDetails &, Scope &, Scope &,
751971960aSJean Perier       const std::string &distinctName, const SymbolVector *parameters);
764fede8bcSpeter klausler   evaluate::StructureConstructor DescribeComponent(
774fede8bcSpeter klausler       const Symbol &, const ProcEntityDetails &, Scope &);
78a48e4168Speter klausler   bool InitializeDataPointer(evaluate::StructureConstructorValues &,
79a48e4168Speter klausler       const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
80a48e4168Speter klausler       Scope &dtScope, const std::string &distinctName);
814fede8bcSpeter klausler   evaluate::StructureConstructor PackageIntValue(
824fede8bcSpeter klausler       const SomeExpr &genre, std::int64_t = 0) const;
834fede8bcSpeter klausler   SomeExpr PackageIntValueExpr(const SomeExpr &genre, std::int64_t = 0) const;
844fede8bcSpeter klausler   std::vector<evaluate::StructureConstructor> DescribeBindings(
854fede8bcSpeter klausler       const Scope &dtScope, Scope &);
867ed26ad1SPeter Klausler   std::map<int, evaluate::StructureConstructor> DescribeSpecialGenerics(
877ed26ad1SPeter Klausler       const Scope &dtScope, const Scope &thisScope,
887ed26ad1SPeter Klausler       const DerivedTypeSpec *) const;
897ed26ad1SPeter Klausler   void DescribeSpecialGeneric(const GenericDetails &,
907ed26ad1SPeter Klausler       std::map<int, evaluate::StructureConstructor> &, const Scope &,
917ed26ad1SPeter Klausler       const DerivedTypeSpec *) const;
9265f52904Speter klausler   void DescribeSpecialProc(std::map<int, evaluate::StructureConstructor> &,
934fede8bcSpeter klausler       const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
947cf1608bSPeter Klausler       std::optional<common::DefinedIo>, const Scope *, const DerivedTypeSpec *,
957cf1608bSPeter Klausler       bool isTypeBound) const;
964fede8bcSpeter klausler   void IncorporateDefinedIoGenericInterfaces(
977cf1608bSPeter Klausler       std::map<int, evaluate::StructureConstructor> &, common::DefinedIo,
98042c964dSPeter Klausler       const Scope *, const DerivedTypeSpec *);
994fede8bcSpeter klausler 
1004fede8bcSpeter klausler   // Instantiated for ParamValue and Bound
1014fede8bcSpeter klausler   template <typename A>
1024fede8bcSpeter klausler   evaluate::StructureConstructor GetValue(
1034fede8bcSpeter klausler       const A &x, const SymbolVector *parameters) {
1044fede8bcSpeter klausler     if (x.isExplicit()) {
1054fede8bcSpeter klausler       return GetValue(x.GetExplicit(), parameters);
1064fede8bcSpeter klausler     } else {
1074fede8bcSpeter klausler       return PackageIntValue(deferredEnum_);
1084fede8bcSpeter klausler     }
1094fede8bcSpeter klausler   }
1104fede8bcSpeter klausler 
1114fede8bcSpeter klausler   // Specialization for optional<Expr<SomeInteger and SubscriptInteger>>
1124fede8bcSpeter klausler   template <typename T>
1134fede8bcSpeter klausler   evaluate::StructureConstructor GetValue(
1144fede8bcSpeter klausler       const std::optional<evaluate::Expr<T>> &expr,
1154fede8bcSpeter klausler       const SymbolVector *parameters) {
1164fede8bcSpeter klausler     if (auto constValue{evaluate::ToInt64(expr)}) {
1174fede8bcSpeter klausler       return PackageIntValue(explicitEnum_, *constValue);
1184fede8bcSpeter klausler     }
1194fede8bcSpeter klausler     if (expr) {
120803f1e46Speter klausler       if (parameters) {
121803f1e46Speter klausler         if (const Symbol * lenParam{evaluate::ExtractBareLenParameter(*expr)}) {
122803f1e46Speter klausler           return PackageIntValue(
123803f1e46Speter klausler               lenParameterEnum_, FindLenParameterIndex(*parameters, *lenParam));
124803f1e46Speter klausler         }
125803f1e46Speter klausler       }
1260a79113bSPeter Klausler       // TODO: Replace a specification expression requiring actual operations
1270a79113bSPeter Klausler       // with a reference to a new anonymous LEN type parameter whose default
1280a79113bSPeter Klausler       // value captures the expression.  This replacement must take place when
1290a79113bSPeter Klausler       // the type is declared so that the new LEN type parameters appear in
1300a79113bSPeter Klausler       // all instantiations and structure constructors.
1314fede8bcSpeter klausler       context_.Say(location_,
1320a79113bSPeter Klausler           "derived type specification expression '%s' that is neither constant nor a length type parameter"_todo_en_US,
1334fede8bcSpeter klausler           expr->AsFortran());
1344fede8bcSpeter klausler     }
1354fede8bcSpeter klausler     return PackageIntValue(deferredEnum_);
1364fede8bcSpeter klausler   }
1374fede8bcSpeter klausler 
1384fede8bcSpeter klausler   SemanticsContext &context_;
1394fede8bcSpeter klausler   RuntimeDerivedTypeTables &tables_;
1404fede8bcSpeter klausler   std::map<const Symbol *, SymbolVector> orderedTypeParameters_;
1414fede8bcSpeter klausler 
1424fede8bcSpeter klausler   const DeclTypeSpec &derivedTypeSchema_; // TYPE(DerivedType)
1434fede8bcSpeter klausler   const DeclTypeSpec &componentSchema_; // TYPE(Component)
1444fede8bcSpeter klausler   const DeclTypeSpec &procPtrSchema_; // TYPE(ProcPtrComponent)
1454fede8bcSpeter klausler   const DeclTypeSpec &valueSchema_; // TYPE(Value)
1464fede8bcSpeter klausler   const DeclTypeSpec &bindingSchema_; // TYPE(Binding)
1474fede8bcSpeter klausler   const DeclTypeSpec &specialSchema_; // TYPE(SpecialBinding)
1484fede8bcSpeter klausler   SomeExpr deferredEnum_; // Value::Genre::Deferred
1494fede8bcSpeter klausler   SomeExpr explicitEnum_; // Value::Genre::Explicit
1504fede8bcSpeter klausler   SomeExpr lenParameterEnum_; // Value::Genre::LenParameter
15165f52904Speter klausler   SomeExpr scalarAssignmentEnum_; // SpecialBinding::Which::ScalarAssignment
1524fede8bcSpeter klausler   SomeExpr
1534fede8bcSpeter klausler       elementalAssignmentEnum_; // SpecialBinding::Which::ElementalAssignment
1544fede8bcSpeter klausler   SomeExpr readFormattedEnum_; // SpecialBinding::Which::ReadFormatted
1554fede8bcSpeter klausler   SomeExpr readUnformattedEnum_; // SpecialBinding::Which::ReadUnformatted
1564fede8bcSpeter klausler   SomeExpr writeFormattedEnum_; // SpecialBinding::Which::WriteFormatted
1574fede8bcSpeter klausler   SomeExpr writeUnformattedEnum_; // SpecialBinding::Which::WriteUnformatted
15865f52904Speter klausler   SomeExpr elementalFinalEnum_; // SpecialBinding::Which::ElementalFinal
15965f52904Speter klausler   SomeExpr assumedRankFinalEnum_; // SpecialBinding::Which::AssumedRankFinal
16065f52904Speter klausler   SomeExpr scalarFinalEnum_; // SpecialBinding::Which::ScalarFinal
1614fede8bcSpeter klausler   parser::CharBlock location_;
162a48e4168Speter klausler   std::set<const Scope *> ignoreScopes_;
1634fede8bcSpeter klausler };
1644fede8bcSpeter klausler 
1654fede8bcSpeter klausler RuntimeTableBuilder::RuntimeTableBuilder(
1664fede8bcSpeter klausler     SemanticsContext &c, RuntimeDerivedTypeTables &t)
1674fede8bcSpeter klausler     : context_{c}, tables_{t}, derivedTypeSchema_{GetSchema("derivedtype")},
168b21c24c3SPeter Klausler       componentSchema_{GetSchema("component")},
169b21c24c3SPeter Klausler       procPtrSchema_{GetSchema("procptrcomponent")},
170b21c24c3SPeter Klausler       valueSchema_{GetSchema("value")},
171b21c24c3SPeter Klausler       bindingSchema_{GetSchema(bindingDescCompName)},
172b21c24c3SPeter Klausler       specialSchema_{GetSchema("specialbinding")},
173b21c24c3SPeter Klausler       deferredEnum_{GetEnumValue("deferred")},
174b21c24c3SPeter Klausler       explicitEnum_{GetEnumValue("explicit")},
175b21c24c3SPeter Klausler       lenParameterEnum_{GetEnumValue("lenparameter")},
17665f52904Speter klausler       scalarAssignmentEnum_{GetEnumValue("scalarassignment")},
1774fede8bcSpeter klausler       elementalAssignmentEnum_{GetEnumValue("elementalassignment")},
1784fede8bcSpeter klausler       readFormattedEnum_{GetEnumValue("readformatted")},
1794fede8bcSpeter klausler       readUnformattedEnum_{GetEnumValue("readunformatted")},
1804fede8bcSpeter klausler       writeFormattedEnum_{GetEnumValue("writeformatted")},
18165f52904Speter klausler       writeUnformattedEnum_{GetEnumValue("writeunformatted")},
18265f52904Speter klausler       elementalFinalEnum_{GetEnumValue("elementalfinal")},
18365f52904Speter klausler       assumedRankFinalEnum_{GetEnumValue("assumedrankfinal")},
18465f52904Speter klausler       scalarFinalEnum_{GetEnumValue("scalarfinal")} {
185a48e4168Speter klausler   ignoreScopes_.insert(tables_.schemata);
186a48e4168Speter klausler }
1874fede8bcSpeter klausler 
1887cf1608bSPeter Klausler static void SetReadOnlyCompilerCreatedFlags(Symbol &symbol) {
1897cf1608bSPeter Klausler   symbol.set(Symbol::Flag::CompilerCreated);
1907cf1608bSPeter Klausler   // Runtime type info symbols may have types that are incompatible with the
1917cf1608bSPeter Klausler   // PARAMETER attribute (the main issue is that they may be TARGET, and normal
1927cf1608bSPeter Klausler   // Fortran parameters cannot be TARGETs).
1937cf1608bSPeter Klausler   if (symbol.has<semantics::ObjectEntityDetails>() ||
1947cf1608bSPeter Klausler       symbol.has<semantics::ProcEntityDetails>()) {
1957cf1608bSPeter Klausler     symbol.set(Symbol::Flag::ReadOnly);
1967cf1608bSPeter Klausler   }
1977cf1608bSPeter Klausler }
1987cf1608bSPeter Klausler 
1997cf1608bSPeter Klausler // Save an arbitrarily shaped array constant of some derived type
2007cf1608bSPeter Klausler // as an initialized data object in a scope.
2017cf1608bSPeter Klausler static SomeExpr SaveDerivedPointerTarget(Scope &scope, SourceName name,
2027cf1608bSPeter Klausler     std::vector<evaluate::StructureConstructor> &&x,
2037cf1608bSPeter Klausler     evaluate::ConstantSubscripts &&shape) {
2047cf1608bSPeter Klausler   if (x.empty()) {
2057cf1608bSPeter Klausler     return SomeExpr{evaluate::NullPointer{}};
2067cf1608bSPeter Klausler   } else {
20745760be3SPeter Klausler     auto dyType{x.front().GetType()};
20845760be3SPeter Klausler     const auto &derivedType{dyType.GetDerivedTypeSpec()};
2097cf1608bSPeter Klausler     ObjectEntityDetails object;
2107cf1608bSPeter Klausler     DeclTypeSpec typeSpec{DeclTypeSpec::TypeDerived, derivedType};
2117cf1608bSPeter Klausler     if (const DeclTypeSpec * spec{scope.FindType(typeSpec)}) {
2127cf1608bSPeter Klausler       object.set_type(*spec);
2137cf1608bSPeter Klausler     } else {
2147cf1608bSPeter Klausler       object.set_type(scope.MakeDerivedType(
2157cf1608bSPeter Klausler           DeclTypeSpec::TypeDerived, common::Clone(derivedType)));
2167cf1608bSPeter Klausler     }
2177cf1608bSPeter Klausler     if (!shape.empty()) {
2187cf1608bSPeter Klausler       ArraySpec arraySpec;
2197cf1608bSPeter Klausler       for (auto n : shape) {
2207cf1608bSPeter Klausler         arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{n - 1}));
2217cf1608bSPeter Klausler       }
2227cf1608bSPeter Klausler       object.set_shape(arraySpec);
2237cf1608bSPeter Klausler     }
2247cf1608bSPeter Klausler     object.set_init(
2257cf1608bSPeter Klausler         evaluate::AsGenericExpr(evaluate::Constant<evaluate::SomeDerived>{
2267cf1608bSPeter Klausler             derivedType, std::move(x), std::move(shape)}));
2277cf1608bSPeter Klausler     Symbol &symbol{*scope
2287cf1608bSPeter Klausler                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
2297cf1608bSPeter Klausler                             std::move(object))
2307cf1608bSPeter Klausler                         .first->second};
2317cf1608bSPeter Klausler     SetReadOnlyCompilerCreatedFlags(symbol);
2327cf1608bSPeter Klausler     return evaluate::AsGenericExpr(
2337cf1608bSPeter Klausler         evaluate::Designator<evaluate::SomeDerived>{symbol});
2347cf1608bSPeter Klausler   }
2357cf1608bSPeter Klausler }
2367cf1608bSPeter Klausler 
237a48e4168Speter klausler void RuntimeTableBuilder::DescribeTypes(Scope &scope, bool inSchemata) {
238a48e4168Speter klausler   inSchemata |= ignoreScopes_.find(&scope) != ignoreScopes_.end();
2394fede8bcSpeter klausler   if (scope.IsDerivedType()) {
240a48e4168Speter klausler     if (!inSchemata) { // don't loop trying to describe a schema
2414fede8bcSpeter klausler       DescribeType(scope);
2424fede8bcSpeter klausler     }
243a48e4168Speter klausler   } else {
244a48e4168Speter klausler     scope.InstantiateDerivedTypes();
245a48e4168Speter klausler   }
246a48e4168Speter klausler   for (Scope &child : scope.children()) {
247a48e4168Speter klausler     DescribeTypes(child, inSchemata);
2484fede8bcSpeter klausler   }
2494fede8bcSpeter klausler }
2504fede8bcSpeter klausler 
2514fede8bcSpeter klausler // Returns derived type instantiation's parameters in declaration order
2524fede8bcSpeter klausler const SymbolVector *RuntimeTableBuilder::GetTypeParameters(
2534fede8bcSpeter klausler     const Symbol &symbol) {
2544fede8bcSpeter klausler   auto iter{orderedTypeParameters_.find(&symbol)};
2554fede8bcSpeter klausler   if (iter != orderedTypeParameters_.end()) {
2564fede8bcSpeter klausler     return &iter->second;
2574fede8bcSpeter klausler   } else {
2584fede8bcSpeter klausler     return &orderedTypeParameters_
2594fede8bcSpeter klausler                 .emplace(&symbol, OrderParameterDeclarations(symbol))
2604fede8bcSpeter klausler                 .first->second;
2614fede8bcSpeter klausler   }
2624fede8bcSpeter klausler }
2634fede8bcSpeter klausler 
2644fede8bcSpeter klausler static Scope &GetContainingNonDerivedScope(Scope &scope) {
2654fede8bcSpeter klausler   Scope *p{&scope};
2664fede8bcSpeter klausler   while (p->IsDerivedType()) {
2674fede8bcSpeter klausler     p = &p->parent();
2684fede8bcSpeter klausler   }
2694fede8bcSpeter klausler   return *p;
2704fede8bcSpeter klausler }
2714fede8bcSpeter klausler 
2724fede8bcSpeter klausler static const Symbol &GetSchemaField(
2734fede8bcSpeter klausler     const DerivedTypeSpec &derived, const std::string &name) {
2744fede8bcSpeter klausler   const Scope &scope{
2754fede8bcSpeter klausler       DEREF(derived.scope() ? derived.scope() : derived.typeSymbol().scope())};
2764fede8bcSpeter klausler   auto iter{scope.find(SourceName(name))};
2774fede8bcSpeter klausler   CHECK(iter != scope.end());
2784fede8bcSpeter klausler   return *iter->second;
2794fede8bcSpeter klausler }
2804fede8bcSpeter klausler 
2814fede8bcSpeter klausler static const Symbol &GetSchemaField(
2824fede8bcSpeter klausler     const DeclTypeSpec &derived, const std::string &name) {
2834fede8bcSpeter klausler   return GetSchemaField(DEREF(derived.AsDerived()), name);
2844fede8bcSpeter klausler }
2854fede8bcSpeter klausler 
2864fede8bcSpeter klausler static evaluate::StructureConstructorValues &AddValue(
2874fede8bcSpeter klausler     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
2884fede8bcSpeter klausler     const std::string &name, SomeExpr &&x) {
2894fede8bcSpeter klausler   values.emplace(GetSchemaField(spec, name), std::move(x));
2904fede8bcSpeter klausler   return values;
2914fede8bcSpeter klausler }
2924fede8bcSpeter klausler 
2934fede8bcSpeter klausler static evaluate::StructureConstructorValues &AddValue(
2944fede8bcSpeter klausler     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
2954fede8bcSpeter klausler     const std::string &name, const SomeExpr &x) {
2964fede8bcSpeter klausler   values.emplace(GetSchemaField(spec, name), x);
2974fede8bcSpeter klausler   return values;
2984fede8bcSpeter klausler }
2994fede8bcSpeter klausler 
3004fede8bcSpeter klausler static SomeExpr IntToExpr(std::int64_t n) {
3014fede8bcSpeter klausler   return evaluate::AsGenericExpr(evaluate::ExtentExpr{n});
3024fede8bcSpeter klausler }
3034fede8bcSpeter klausler 
3044fede8bcSpeter klausler static evaluate::StructureConstructor Structure(
3054fede8bcSpeter klausler     const DeclTypeSpec &spec, evaluate::StructureConstructorValues &&values) {
3064fede8bcSpeter klausler   return {DEREF(spec.AsDerived()), std::move(values)};
3074fede8bcSpeter klausler }
3084fede8bcSpeter klausler 
3094fede8bcSpeter klausler static SomeExpr StructureExpr(evaluate::StructureConstructor &&x) {
3104fede8bcSpeter klausler   return SomeExpr{evaluate::Expr<evaluate::SomeDerived>{std::move(x)}};
3114fede8bcSpeter klausler }
3124fede8bcSpeter klausler 
3134fede8bcSpeter klausler static int GetIntegerKind(const Symbol &symbol) {
3144fede8bcSpeter klausler   auto dyType{evaluate::DynamicType::From(symbol)};
315d5cc3723SPeter Klausler   CHECK((dyType && dyType->category() == TypeCategory::Integer) ||
316d5cc3723SPeter Klausler       symbol.owner().context().HasError(symbol));
317d5cc3723SPeter Klausler   return dyType && dyType->category() == TypeCategory::Integer
318d5cc3723SPeter Klausler       ? dyType->kind()
319d5cc3723SPeter Klausler       : symbol.owner().context().GetDefaultKind(TypeCategory::Integer);
3204fede8bcSpeter klausler }
3214fede8bcSpeter klausler 
3224fede8bcSpeter klausler // Save a rank-1 array constant of some numeric type as an
3234fede8bcSpeter klausler // initialized data object in a scope.
3244fede8bcSpeter klausler template <typename T>
3254fede8bcSpeter klausler static SomeExpr SaveNumericPointerTarget(
3264fede8bcSpeter klausler     Scope &scope, SourceName name, std::vector<typename T::Scalar> &&x) {
3274fede8bcSpeter klausler   if (x.empty()) {
3284fede8bcSpeter klausler     return SomeExpr{evaluate::NullPointer{}};
3294fede8bcSpeter klausler   } else {
3304fede8bcSpeter klausler     ObjectEntityDetails object;
3314fede8bcSpeter klausler     if (const auto *spec{scope.FindType(
3324fede8bcSpeter klausler             DeclTypeSpec{NumericTypeSpec{T::category, KindExpr{T::kind}}})}) {
3334fede8bcSpeter klausler       object.set_type(*spec);
3344fede8bcSpeter klausler     } else {
3354fede8bcSpeter klausler       object.set_type(scope.MakeNumericType(T::category, KindExpr{T::kind}));
3364fede8bcSpeter klausler     }
3374fede8bcSpeter klausler     auto elements{static_cast<evaluate::ConstantSubscript>(x.size())};
3384fede8bcSpeter klausler     ArraySpec arraySpec;
3394fede8bcSpeter klausler     arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{elements - 1}));
3404fede8bcSpeter klausler     object.set_shape(arraySpec);
3414fede8bcSpeter klausler     object.set_init(evaluate::AsGenericExpr(evaluate::Constant<T>{
3424fede8bcSpeter klausler         std::move(x), evaluate::ConstantSubscripts{elements}}));
343d60a0220Speter klausler     Symbol &symbol{*scope
344d60a0220Speter klausler                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
345d60a0220Speter klausler                             std::move(object))
3464fede8bcSpeter klausler                         .first->second};
3477dd7ccd2SJean Perier     SetReadOnlyCompilerCreatedFlags(symbol);
3484fede8bcSpeter klausler     return evaluate::AsGenericExpr(
3494fede8bcSpeter klausler         evaluate::Expr<T>{evaluate::Designator<T>{symbol}});
3504fede8bcSpeter klausler   }
3514fede8bcSpeter klausler }
3524fede8bcSpeter klausler 
3534fede8bcSpeter klausler static SomeExpr SaveObjectInit(
3544fede8bcSpeter klausler     Scope &scope, SourceName name, const ObjectEntityDetails &object) {
355d60a0220Speter klausler   Symbol &symbol{*scope
3564fede8bcSpeter klausler                       .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
3574fede8bcSpeter klausler                           ObjectEntityDetails{object})
3584fede8bcSpeter klausler                       .first->second};
3594fede8bcSpeter klausler   CHECK(symbol.get<ObjectEntityDetails>().init().has_value());
3607dd7ccd2SJean Perier   SetReadOnlyCompilerCreatedFlags(symbol);
3614fede8bcSpeter klausler   return evaluate::AsGenericExpr(
3624fede8bcSpeter klausler       evaluate::Designator<evaluate::SomeDerived>{symbol});
3634fede8bcSpeter klausler }
3644fede8bcSpeter klausler 
365a48e4168Speter klausler template <int KIND> static SomeExpr IntExpr(std::int64_t n) {
366a48e4168Speter klausler   return evaluate::AsGenericExpr(
367a48e4168Speter klausler       evaluate::Constant<evaluate::Type<TypeCategory::Integer, KIND>>{n});
368a48e4168Speter klausler }
369a48e4168Speter klausler 
370f88a9497SJean Perier static std::optional<std::string> GetSuffixIfTypeKindParameters(
371f88a9497SJean Perier     const DerivedTypeSpec &derivedTypeSpec, const SymbolVector *parameters) {
372f88a9497SJean Perier   if (parameters) {
373f88a9497SJean Perier     std::optional<std::string> suffix;
374f88a9497SJean Perier     for (SymbolRef ref : *parameters) {
375f88a9497SJean Perier       const auto &tpd{ref->get<TypeParamDetails>()};
376539a6b50SPeter Klausler       if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Kind) {
377f88a9497SJean Perier         if (const auto *pv{derivedTypeSpec.FindParameter(ref->name())}) {
378f88a9497SJean Perier           if (pv->GetExplicit()) {
379f88a9497SJean Perier             if (auto instantiatedValue{evaluate::ToInt64(*pv->GetExplicit())}) {
380f88a9497SJean Perier               if (suffix.has_value()) {
381cfd4c180SSlava Zakharin                 *suffix +=
382cfd4c180SSlava Zakharin                     (fir::kNameSeparator + llvm::Twine(*instantiatedValue))
383cfd4c180SSlava Zakharin                         .str();
384f88a9497SJean Perier               } else {
385cfd4c180SSlava Zakharin                 suffix = (fir::kNameSeparator + llvm::Twine(*instantiatedValue))
386cfd4c180SSlava Zakharin                              .str();
387f88a9497SJean Perier               }
388f88a9497SJean Perier             }
389f88a9497SJean Perier           }
390f88a9497SJean Perier         }
391f88a9497SJean Perier       }
392f88a9497SJean Perier     }
393f88a9497SJean Perier     return suffix;
394f88a9497SJean Perier   }
395f88a9497SJean Perier   return std::nullopt;
396f88a9497SJean Perier }
397f88a9497SJean Perier 
3984fede8bcSpeter klausler const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
3994fede8bcSpeter klausler   if (const Symbol * info{dtScope.runtimeDerivedTypeDescription()}) {
4004fede8bcSpeter klausler     return info;
4014fede8bcSpeter klausler   }
4024fede8bcSpeter klausler   const DerivedTypeSpec *derivedTypeSpec{dtScope.derivedTypeSpec()};
403f2da8f5eSJean Perier   if (!derivedTypeSpec && !dtScope.IsDerivedTypeWithKindParameter() &&
404a48e4168Speter klausler       dtScope.symbol()) {
405a48e4168Speter klausler     // This derived type was declared (obviously, there's a Scope) but never
406a48e4168Speter klausler     // used in this compilation (no instantiated DerivedTypeSpec points here).
407a48e4168Speter klausler     // Create a DerivedTypeSpec now for it so that ComponentIterator
408a48e4168Speter klausler     // will work. This covers the case of a derived type that's declared in
409a48e4168Speter klausler     // a module but used only by clients and submodules, enabling the
410a48e4168Speter klausler     // run-time "no initialization needed here" flag to work.
411a48e4168Speter klausler     DerivedTypeSpec derived{dtScope.symbol()->name(), *dtScope.symbol()};
412f88a9497SJean Perier     if (const SymbolVector *
413f88a9497SJean Perier         lenParameters{GetTypeParameters(*dtScope.symbol())}) {
414f88a9497SJean Perier       // Create dummy deferred values for the length parameters so that the
415f88a9497SJean Perier       // DerivedTypeSpec is complete and can be used in helpers.
416f88a9497SJean Perier       for (SymbolRef lenParam : *lenParameters) {
41706be1488SAndrzej Warzynski         (void)lenParam;
418f88a9497SJean Perier         derived.AddRawParamValue(
4199e855a6cSPeter Klausler             nullptr, ParamValue::Deferred(common::TypeParamAttr::Len));
420f88a9497SJean Perier       }
421f88a9497SJean Perier       derived.CookParameters(context_.foldingContext());
422f88a9497SJean Perier     }
423a48e4168Speter klausler     DeclTypeSpec &decl{
424a48e4168Speter klausler         dtScope.MakeDerivedType(DeclTypeSpec::TypeDerived, std::move(derived))};
425a48e4168Speter klausler     derivedTypeSpec = &decl.derivedTypeSpec();
426a48e4168Speter klausler   }
4274fede8bcSpeter klausler   const Symbol *dtSymbol{
4284fede8bcSpeter klausler       derivedTypeSpec ? &derivedTypeSpec->typeSymbol() : dtScope.symbol()};
4294fede8bcSpeter klausler   if (!dtSymbol) {
4304fede8bcSpeter klausler     return nullptr;
4314fede8bcSpeter klausler   }
4324fede8bcSpeter klausler   auto locationRestorer{common::ScopedSet(location_, dtSymbol->name())};
4334fede8bcSpeter klausler   // Check for an existing description that can be imported from a USE'd module
4344fede8bcSpeter klausler   std::string typeName{dtSymbol->name().ToString()};
435c14cf92bSPeter Klausler   if (typeName.empty() ||
436c14cf92bSPeter Klausler       (typeName.front() == '.' && !context_.IsTempName(typeName))) {
4374fede8bcSpeter klausler     return nullptr;
4384fede8bcSpeter klausler   }
439c9da9c0dSPeter Klausler   bool isPDTDefinitionWithKindParameters{
440c9da9c0dSPeter Klausler       !derivedTypeSpec && dtScope.IsDerivedTypeWithKindParameter()};
441c9da9c0dSPeter Klausler   bool isPDTInstantiation{derivedTypeSpec && &dtScope != dtSymbol->scope()};
442f88a9497SJean Perier   const SymbolVector *parameters{GetTypeParameters(*dtSymbol)};
4434fede8bcSpeter klausler   std::string distinctName{typeName};
444c9da9c0dSPeter Klausler   if (isPDTInstantiation) {
445f88a9497SJean Perier     // Only create new type descriptions for different kind parameter values.
446f88a9497SJean Perier     // Type with different length parameters/same kind parameters can all
447f88a9497SJean Perier     // share the same type description available in the current scope.
448f88a9497SJean Perier     if (auto suffix{
449f88a9497SJean Perier             GetSuffixIfTypeKindParameters(*derivedTypeSpec, parameters)}) {
450f88a9497SJean Perier       distinctName += *suffix;
451f88a9497SJean Perier     }
452c9da9c0dSPeter Klausler   } else if (isPDTDefinitionWithKindParameters) {
453c9da9c0dSPeter Klausler     return nullptr;
4544fede8bcSpeter klausler   }
455cfd4c180SSlava Zakharin   std::string dtDescName{(fir::kTypeDescriptorSeparator + distinctName).str()};
456f88a9497SJean Perier   Scope *dtSymbolScope{const_cast<Scope *>(dtSymbol->scope())};
457f88a9497SJean Perier   Scope &scope{
458f88a9497SJean Perier       GetContainingNonDerivedScope(dtSymbolScope ? *dtSymbolScope : dtScope)};
459f88a9497SJean Perier   if (const auto it{scope.find(SourceName{dtDescName})}; it != scope.end()) {
460f88a9497SJean Perier     dtScope.set_runtimeDerivedTypeDescription(*it->second);
461f88a9497SJean Perier     return &*it->second;
4624fede8bcSpeter klausler   }
463f88a9497SJean Perier 
4644fede8bcSpeter klausler   // Create a new description object before populating it so that mutual
4654fede8bcSpeter klausler   // references will work as pointer targets.
4664fede8bcSpeter klausler   Symbol &dtObject{CreateObject(dtDescName, derivedTypeSchema_, scope)};
4674fede8bcSpeter klausler   dtScope.set_runtimeDerivedTypeDescription(dtObject);
4684fede8bcSpeter klausler   evaluate::StructureConstructorValues dtValues;
4694fede8bcSpeter klausler   AddValue(dtValues, derivedTypeSchema_, "name"s,
4704fede8bcSpeter klausler       SaveNameAsPointerTarget(scope, typeName));
471c9da9c0dSPeter Klausler   if (!isPDTDefinitionWithKindParameters) {
4724fede8bcSpeter klausler     auto sizeInBytes{static_cast<common::ConstantSubscript>(dtScope.size())};
4734fede8bcSpeter klausler     if (auto alignment{dtScope.alignment().value_or(0)}) {
4744fede8bcSpeter klausler       sizeInBytes += alignment - 1;
4754fede8bcSpeter klausler       sizeInBytes /= alignment;
4764fede8bcSpeter klausler       sizeInBytes *= alignment;
4774fede8bcSpeter klausler     }
4784fede8bcSpeter klausler     AddValue(
4794fede8bcSpeter klausler         dtValues, derivedTypeSchema_, "sizeinbytes"s, IntToExpr(sizeInBytes));
4804fede8bcSpeter klausler   }
481c9da9c0dSPeter Klausler   if (const Symbol *
482c9da9c0dSPeter Klausler       uninstDescObject{isPDTInstantiation
483c9da9c0dSPeter Klausler               ? DescribeType(DEREF(const_cast<Scope *>(dtSymbol->scope())))
484c9da9c0dSPeter Klausler               : nullptr}) {
4854fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
4864fede8bcSpeter klausler         evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
4874fede8bcSpeter klausler             evaluate::Designator<evaluate::SomeDerived>{
4884fede8bcSpeter klausler                 DEREF(uninstDescObject)}}));
4894fede8bcSpeter klausler   } else {
4904fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
4914fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
4924fede8bcSpeter klausler   }
4934fede8bcSpeter klausler   using Int8 = evaluate::Type<TypeCategory::Integer, 8>;
4944fede8bcSpeter klausler   using Int1 = evaluate::Type<TypeCategory::Integer, 1>;
4954fede8bcSpeter klausler   std::vector<Int8::Scalar> kinds;
4964fede8bcSpeter klausler   std::vector<Int1::Scalar> lenKinds;
4974fede8bcSpeter klausler   if (parameters) {
4984fede8bcSpeter klausler     // Package the derived type's parameters in declaration order for
4994fede8bcSpeter klausler     // each category of parameter.  KIND= type parameters are described
5004fede8bcSpeter klausler     // by their instantiated (or default) values, while LEN= type
5014fede8bcSpeter klausler     // parameters are described by their INTEGER kinds.
5024fede8bcSpeter klausler     for (SymbolRef ref : *parameters) {
503c9da9c0dSPeter Klausler       if (const auto *inst{dtScope.FindComponent(ref->name())}) {
504c9da9c0dSPeter Klausler         const auto &tpd{inst->get<TypeParamDetails>()};
505539a6b50SPeter Klausler         if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Kind) {
5064fede8bcSpeter klausler           auto value{evaluate::ToInt64(tpd.init()).value_or(0)};
5074fede8bcSpeter klausler           if (derivedTypeSpec) {
508c9da9c0dSPeter Klausler             if (const auto *pv{derivedTypeSpec->FindParameter(inst->name())}) {
5094fede8bcSpeter klausler               if (pv->GetExplicit()) {
5104fede8bcSpeter klausler                 if (auto instantiatedValue{
5114fede8bcSpeter klausler                         evaluate::ToInt64(*pv->GetExplicit())}) {
5124fede8bcSpeter klausler                   value = *instantiatedValue;
5134fede8bcSpeter klausler                 }
5144fede8bcSpeter klausler               }
5154fede8bcSpeter klausler             }
5164fede8bcSpeter klausler           }
5174fede8bcSpeter klausler           kinds.emplace_back(value);
5184fede8bcSpeter klausler         } else { // LEN= parameter
519c9da9c0dSPeter Klausler           lenKinds.emplace_back(GetIntegerKind(*inst));
520c9da9c0dSPeter Klausler         }
5214fede8bcSpeter klausler       }
5224fede8bcSpeter klausler     }
5234fede8bcSpeter klausler   }
5244fede8bcSpeter klausler   AddValue(dtValues, derivedTypeSchema_, "kindparameter"s,
525cfd4c180SSlava Zakharin       SaveNumericPointerTarget<Int8>(scope,
526cfd4c180SSlava Zakharin           SaveObjectName((fir::kKindParameterSeparator + distinctName).str()),
527cfd4c180SSlava Zakharin           std::move(kinds)));
5284fede8bcSpeter klausler   AddValue(dtValues, derivedTypeSchema_, "lenparameterkind"s,
529cfd4c180SSlava Zakharin       SaveNumericPointerTarget<Int1>(scope,
530cfd4c180SSlava Zakharin           SaveObjectName((fir::kLenKindSeparator + distinctName).str()),
531cfd4c180SSlava Zakharin           std::move(lenKinds)));
5324fede8bcSpeter klausler   // Traverse the components of the derived type
533c9da9c0dSPeter Klausler   if (!isPDTDefinitionWithKindParameters) {
53479caf69cSpeter klausler     std::vector<const Symbol *> dataComponentSymbols;
5354fede8bcSpeter klausler     std::vector<evaluate::StructureConstructor> procPtrComponents;
5364fede8bcSpeter klausler     for (const auto &pair : dtScope) {
5374fede8bcSpeter klausler       const Symbol &symbol{*pair.second};
5384fede8bcSpeter klausler       auto locationRestorer{common::ScopedSet(location_, symbol.name())};
539cd03e96fSPeter Klausler       common::visit(
5404fede8bcSpeter klausler           common::visitors{
5414fede8bcSpeter klausler               [&](const TypeParamDetails &) {
5424fede8bcSpeter klausler                 // already handled above in declaration order
5434fede8bcSpeter klausler               },
54479caf69cSpeter klausler               [&](const ObjectEntityDetails &) {
54579caf69cSpeter klausler                 dataComponentSymbols.push_back(&symbol);
5464fede8bcSpeter klausler               },
5474fede8bcSpeter klausler               [&](const ProcEntityDetails &proc) {
5484fede8bcSpeter klausler                 if (IsProcedurePointer(symbol)) {
5494fede8bcSpeter klausler                   procPtrComponents.emplace_back(
5501971960aSJean Perier                       DescribeComponent(symbol, proc, scope));
5514fede8bcSpeter klausler                 }
5524fede8bcSpeter klausler               },
5534fede8bcSpeter klausler               [&](const ProcBindingDetails &) { // handled in a later pass
5544fede8bcSpeter klausler               },
5557ed26ad1SPeter Klausler               [&](const GenericDetails &) { // ditto
5564fede8bcSpeter klausler               },
5574fede8bcSpeter klausler               [&](const auto &) {
5584fede8bcSpeter klausler                 common::die(
5594fede8bcSpeter klausler                     "unexpected details on symbol '%s' in derived type scope",
5604fede8bcSpeter klausler                     symbol.name().ToString().c_str());
5614fede8bcSpeter klausler               },
5624fede8bcSpeter klausler           },
5634fede8bcSpeter klausler           symbol.details());
5644fede8bcSpeter klausler     }
56553c260d9SjeanPerier     // Sort the data component symbols by offset before emitting them, placing
56653c260d9SjeanPerier     // the parent component first if any.
56779caf69cSpeter klausler     std::sort(dataComponentSymbols.begin(), dataComponentSymbols.end(),
56879caf69cSpeter klausler         [](const Symbol *x, const Symbol *y) {
56953c260d9SjeanPerier           return x->test(Symbol::Flag::ParentComp) || x->offset() < y->offset();
57079caf69cSpeter klausler         });
57179caf69cSpeter klausler     std::vector<evaluate::StructureConstructor> dataComponents;
57279caf69cSpeter klausler     for (const Symbol *symbol : dataComponentSymbols) {
57379caf69cSpeter klausler       auto locationRestorer{common::ScopedSet(location_, symbol->name())};
57479caf69cSpeter klausler       dataComponents.emplace_back(
57579caf69cSpeter klausler           DescribeComponent(*symbol, symbol->get<ObjectEntityDetails>(), scope,
57679caf69cSpeter klausler               dtScope, distinctName, parameters));
57779caf69cSpeter klausler     }
5784fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "component"s,
579cfd4c180SSlava Zakharin         SaveDerivedPointerTarget(scope,
580cfd4c180SSlava Zakharin             SaveObjectName((fir::kComponentSeparator + distinctName).str()),
5814fede8bcSpeter klausler             std::move(dataComponents),
5824fede8bcSpeter klausler             evaluate::ConstantSubscripts{
5834fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(
5844fede8bcSpeter klausler                     dataComponents.size())}));
5854fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "procptr"s,
586cfd4c180SSlava Zakharin         SaveDerivedPointerTarget(scope,
587cfd4c180SSlava Zakharin             SaveObjectName((fir::kProcPtrSeparator + distinctName).str()),
5884fede8bcSpeter klausler             std::move(procPtrComponents),
5894fede8bcSpeter klausler             evaluate::ConstantSubscripts{
5904fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(
5914fede8bcSpeter klausler                     procPtrComponents.size())}));
5924fede8bcSpeter klausler     // Compile the "vtable" of type-bound procedure bindings
593ceccfc85SPeter Klausler     std::uint32_t specialBitSet{0};
59401c38ab7SPeter Klausler     if (!dtSymbol->attrs().test(Attr::ABSTRACT)) {
5954fede8bcSpeter klausler       std::vector<evaluate::StructureConstructor> bindings{
5964fede8bcSpeter klausler           DescribeBindings(dtScope, scope)};
5974c5dee77SRenaud-K       AddValue(dtValues, derivedTypeSchema_, bindingDescCompName,
598cfd4c180SSlava Zakharin           SaveDerivedPointerTarget(scope,
599cfd4c180SSlava Zakharin               SaveObjectName(
600cfd4c180SSlava Zakharin                   (fir::kBindingTableSeparator + distinctName).str()),
6014fede8bcSpeter klausler               std::move(bindings),
6024fede8bcSpeter klausler               evaluate::ConstantSubscripts{
6034fede8bcSpeter klausler                   static_cast<evaluate::ConstantSubscript>(bindings.size())}));
6044fede8bcSpeter klausler       // Describe "special" bindings to defined assignments, FINAL subroutines,
6057cf1608bSPeter Klausler       // and defined derived type I/O subroutines.  Defined assignments and I/O
6067cf1608bSPeter Klausler       // subroutines override any parent bindings, but FINAL subroutines do not
6077cf1608bSPeter Klausler       // (the runtime will call all of them).
6087ed26ad1SPeter Klausler       std::map<int, evaluate::StructureConstructor> specials{
6097ed26ad1SPeter Klausler           DescribeSpecialGenerics(dtScope, dtScope, derivedTypeSpec)};
610042c964dSPeter Klausler       if (derivedTypeSpec) {
611d84faa42SPeter Klausler         for (auto &ref : FinalsForDerivedTypeInstantiation(*derivedTypeSpec)) {
612b21c24c3SPeter Klausler           DescribeSpecialProc(specials, *ref, /*isAssignment-*/ false,
613b21c24c3SPeter Klausler               /*isFinal=*/true, std::nullopt, nullptr, derivedTypeSpec,
614b21c24c3SPeter Klausler               /*isTypeBound=*/true);
615d84faa42SPeter Klausler         }
616042c964dSPeter Klausler         IncorporateDefinedIoGenericInterfaces(specials,
6177cf1608bSPeter Klausler             common::DefinedIo::ReadFormatted, &scope, derivedTypeSpec);
618042c964dSPeter Klausler         IncorporateDefinedIoGenericInterfaces(specials,
6197cf1608bSPeter Klausler             common::DefinedIo::ReadUnformatted, &scope, derivedTypeSpec);
620042c964dSPeter Klausler         IncorporateDefinedIoGenericInterfaces(specials,
6217cf1608bSPeter Klausler             common::DefinedIo::WriteFormatted, &scope, derivedTypeSpec);
622042c964dSPeter Klausler         IncorporateDefinedIoGenericInterfaces(specials,
6237cf1608bSPeter Klausler             common::DefinedIo::WriteUnformatted, &scope, derivedTypeSpec);
624042c964dSPeter Klausler       }
62565f52904Speter klausler       // Pack the special procedure bindings in ascending order of their "which"
62665f52904Speter klausler       // code values, and compile a little-endian bit-set of those codes for
62765f52904Speter klausler       // use in O(1) look-up at run time.
62865f52904Speter klausler       std::vector<evaluate::StructureConstructor> sortedSpecials;
62965f52904Speter klausler       for (auto &pair : specials) {
63065f52904Speter klausler         auto bit{std::uint32_t{1} << pair.first};
63165f52904Speter klausler         CHECK(!(specialBitSet & bit));
63265f52904Speter klausler         specialBitSet |= bit;
63365f52904Speter klausler         sortedSpecials.emplace_back(std::move(pair.second));
63465f52904Speter klausler       }
6354fede8bcSpeter klausler       AddValue(dtValues, derivedTypeSchema_, "special"s,
636cfd4c180SSlava Zakharin           SaveDerivedPointerTarget(scope,
637cfd4c180SSlava Zakharin               SaveObjectName(
638cfd4c180SSlava Zakharin                   (fir::kSpecialBindingSeparator + distinctName).str()),
63965f52904Speter klausler               std::move(sortedSpecials),
6404fede8bcSpeter klausler               evaluate::ConstantSubscripts{
6414fede8bcSpeter klausler                   static_cast<evaluate::ConstantSubscript>(specials.size())}));
642ceccfc85SPeter Klausler     }
64365f52904Speter klausler     AddValue(dtValues, derivedTypeSchema_, "specialbitset"s,
64465f52904Speter klausler         IntExpr<4>(specialBitSet));
645a48e4168Speter klausler     // Note the presence/absence of a parent component
646a48e4168Speter klausler     AddValue(dtValues, derivedTypeSchema_, "hasparent"s,
647a48e4168Speter klausler         IntExpr<1>(dtScope.GetDerivedTypeParent() != nullptr));
648a48e4168Speter klausler     // To avoid wasting run time attempting to initialize derived type
649a48e4168Speter klausler     // instances without any initialized components, analyze the type
650a48e4168Speter klausler     // and set a flag if there's nothing to do for it at run time.
651a48e4168Speter klausler     AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s,
65227cf6ba1SPeter Klausler         IntExpr<1>(derivedTypeSpec &&
65327cf6ba1SPeter Klausler             !derivedTypeSpec->HasDefaultInitialization(false, false)));
654a48e4168Speter klausler     // Similarly, a flag to short-circuit destruction when not needed.
655a48e4168Speter klausler     AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s,
65601c38ab7SPeter Klausler         IntExpr<1>(derivedTypeSpec && !derivedTypeSpec->HasDestruction()));
65765f52904Speter klausler     // Similarly, a flag to short-circuit finalization when not needed.
65865f52904Speter klausler     AddValue(dtValues, derivedTypeSchema_, "nofinalizationneeded"s,
659710503fcSjeanPerier         IntExpr<1>(
660710503fcSjeanPerier             derivedTypeSpec && !MayRequireFinalization(*derivedTypeSpec)));
6614fede8bcSpeter klausler   }
6624fede8bcSpeter klausler   dtObject.get<ObjectEntityDetails>().set_init(MaybeExpr{
6634fede8bcSpeter klausler       StructureExpr(Structure(derivedTypeSchema_, std::move(dtValues)))});
6644fede8bcSpeter klausler   return &dtObject;
6654fede8bcSpeter klausler }
6664fede8bcSpeter klausler 
6674fede8bcSpeter klausler static const Symbol &GetSymbol(const Scope &schemata, SourceName name) {
6684fede8bcSpeter klausler   auto iter{schemata.find(name)};
6694fede8bcSpeter klausler   CHECK(iter != schemata.end());
6704fede8bcSpeter klausler   const Symbol &symbol{*iter->second};
6714fede8bcSpeter klausler   return symbol;
6724fede8bcSpeter klausler }
6734fede8bcSpeter klausler 
6744fede8bcSpeter klausler const Symbol &RuntimeTableBuilder::GetSchemaSymbol(const char *name) const {
6754fede8bcSpeter klausler   return GetSymbol(
6764fede8bcSpeter klausler       DEREF(tables_.schemata), SourceName{name, std::strlen(name)});
6774fede8bcSpeter klausler }
6784fede8bcSpeter klausler 
6794fede8bcSpeter klausler const DeclTypeSpec &RuntimeTableBuilder::GetSchema(
6804fede8bcSpeter klausler     const char *schemaName) const {
6814fede8bcSpeter klausler   Scope &schemata{DEREF(tables_.schemata)};
6824fede8bcSpeter klausler   SourceName name{schemaName, std::strlen(schemaName)};
6834fede8bcSpeter klausler   const Symbol &symbol{GetSymbol(schemata, name)};
6844fede8bcSpeter klausler   CHECK(symbol.has<DerivedTypeDetails>());
6854fede8bcSpeter klausler   CHECK(symbol.scope());
6864fede8bcSpeter klausler   CHECK(symbol.scope()->IsDerivedType());
6874fede8bcSpeter klausler   const DeclTypeSpec *spec{nullptr};
6884fede8bcSpeter klausler   if (symbol.scope()->derivedTypeSpec()) {
6894fede8bcSpeter klausler     DeclTypeSpec typeSpec{
6904fede8bcSpeter klausler         DeclTypeSpec::TypeDerived, *symbol.scope()->derivedTypeSpec()};
6914fede8bcSpeter klausler     spec = schemata.FindType(typeSpec);
6924fede8bcSpeter klausler   }
6934fede8bcSpeter klausler   if (!spec) {
6944fede8bcSpeter klausler     DeclTypeSpec typeSpec{
6954fede8bcSpeter klausler         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol}};
6964fede8bcSpeter klausler     spec = schemata.FindType(typeSpec);
6974fede8bcSpeter klausler   }
6984fede8bcSpeter klausler   if (!spec) {
6994fede8bcSpeter klausler     spec = &schemata.MakeDerivedType(
7004fede8bcSpeter klausler         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol});
7014fede8bcSpeter klausler   }
7024fede8bcSpeter klausler   CHECK(spec->AsDerived());
7034fede8bcSpeter klausler   return *spec;
7044fede8bcSpeter klausler }
7054fede8bcSpeter klausler 
7064fede8bcSpeter klausler SomeExpr RuntimeTableBuilder::GetEnumValue(const char *name) const {
7074fede8bcSpeter klausler   const Symbol &symbol{GetSchemaSymbol(name)};
7084fede8bcSpeter klausler   auto value{evaluate::ToInt64(symbol.get<ObjectEntityDetails>().init())};
7094fede8bcSpeter klausler   CHECK(value.has_value());
7104fede8bcSpeter klausler   return IntExpr<1>(*value);
7114fede8bcSpeter klausler }
7124fede8bcSpeter klausler 
7134fede8bcSpeter klausler Symbol &RuntimeTableBuilder::CreateObject(
7144fede8bcSpeter klausler     const std::string &name, const DeclTypeSpec &type, Scope &scope) {
7154fede8bcSpeter klausler   ObjectEntityDetails object;
7164fede8bcSpeter klausler   object.set_type(type);
7174fede8bcSpeter klausler   auto pair{scope.try_emplace(SaveObjectName(name),
7184fede8bcSpeter klausler       Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))};
7194fede8bcSpeter klausler   CHECK(pair.second);
7204fede8bcSpeter klausler   Symbol &result{*pair.first->second};
7217dd7ccd2SJean Perier   SetReadOnlyCompilerCreatedFlags(result);
7224fede8bcSpeter klausler   return result;
7234fede8bcSpeter klausler }
7244fede8bcSpeter klausler 
7254fede8bcSpeter klausler SourceName RuntimeTableBuilder::SaveObjectName(const std::string &name) {
7264fede8bcSpeter klausler   return *tables_.names.insert(name).first;
7274fede8bcSpeter klausler }
7284fede8bcSpeter klausler 
7294fede8bcSpeter klausler SomeExpr RuntimeTableBuilder::SaveNameAsPointerTarget(
7304fede8bcSpeter klausler     Scope &scope, const std::string &name) {
7314fede8bcSpeter klausler   CHECK(!name.empty());
732c14cf92bSPeter Klausler   CHECK(name.front() != '.' || context_.IsTempName(name));
7334fede8bcSpeter klausler   ObjectEntityDetails object;
7344fede8bcSpeter klausler   auto len{static_cast<common::ConstantSubscript>(name.size())};
7354fede8bcSpeter klausler   if (const auto *spec{scope.FindType(DeclTypeSpec{CharacterTypeSpec{
7364fede8bcSpeter klausler           ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}}})}) {
7374fede8bcSpeter klausler     object.set_type(*spec);
7384fede8bcSpeter klausler   } else {
7394fede8bcSpeter klausler     object.set_type(scope.MakeCharacterType(
7404fede8bcSpeter klausler         ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}));
7414fede8bcSpeter klausler   }
7426965a776Speter klausler   using evaluate::Ascii;
7434fede8bcSpeter klausler   using AsciiExpr = evaluate::Expr<Ascii>;
7444fede8bcSpeter klausler   object.set_init(evaluate::AsGenericExpr(AsciiExpr{name}));
745cfd4c180SSlava Zakharin   Symbol &symbol{
746cfd4c180SSlava Zakharin       *scope
747cfd4c180SSlava Zakharin            .try_emplace(
748cfd4c180SSlava Zakharin                SaveObjectName((fir::kNameStringSeparator + name).str()),
7494fede8bcSpeter klausler                Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
7504fede8bcSpeter klausler            .first->second};
7517dd7ccd2SJean Perier   SetReadOnlyCompilerCreatedFlags(symbol);
7524fede8bcSpeter klausler   return evaluate::AsGenericExpr(
7534fede8bcSpeter klausler       AsciiExpr{evaluate::Designator<Ascii>{symbol}});
7544fede8bcSpeter klausler }
7554fede8bcSpeter klausler 
7564fede8bcSpeter klausler evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
7574fede8bcSpeter klausler     const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
7581971960aSJean Perier     Scope &dtScope, const std::string &distinctName,
7591971960aSJean Perier     const SymbolVector *parameters) {
7604fede8bcSpeter klausler   evaluate::StructureConstructorValues values;
7618989268dSPeter Steinfeld   auto &foldingContext{context_.foldingContext()};
7624fede8bcSpeter klausler   auto typeAndShape{evaluate::characteristics::TypeAndShape::Characterize(
7638989268dSPeter Steinfeld       symbol, foldingContext)};
7644fede8bcSpeter klausler   CHECK(typeAndShape.has_value());
7654fede8bcSpeter klausler   auto dyType{typeAndShape->type()};
76673cf0142SjeanPerier   int rank{typeAndShape->Rank()};
7674fede8bcSpeter klausler   AddValue(values, componentSchema_, "name"s,
7684fede8bcSpeter klausler       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
7694fede8bcSpeter klausler   AddValue(values, componentSchema_, "category"s,
7704fede8bcSpeter klausler       IntExpr<1>(static_cast<int>(dyType.category())));
7714fede8bcSpeter klausler   if (dyType.IsUnlimitedPolymorphic() ||
7724fede8bcSpeter klausler       dyType.category() == TypeCategory::Derived) {
7734fede8bcSpeter klausler     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(0));
7744fede8bcSpeter klausler   } else {
7754fede8bcSpeter klausler     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(dyType.kind()));
7764fede8bcSpeter klausler   }
7774fede8bcSpeter klausler   AddValue(values, componentSchema_, "offset"s, IntExpr<8>(symbol.offset()));
7784fede8bcSpeter klausler   // CHARACTER length
7798989268dSPeter Steinfeld   auto len{typeAndShape->LEN()};
7801971960aSJean Perier   if (const semantics::DerivedTypeSpec *
7811971960aSJean Perier       pdtInstance{dtScope.derivedTypeSpec()}) {
7828989268dSPeter Steinfeld     auto restorer{foldingContext.WithPDTInstance(*pdtInstance)};
7838989268dSPeter Steinfeld     len = Fold(foldingContext, std::move(len));
7848989268dSPeter Steinfeld   }
7854fede8bcSpeter klausler   if (dyType.category() == TypeCategory::Character && len) {
78678d60094SPeter Klausler     // Ignore IDIM(x) (represented as MAX(0, x))
78778d60094SPeter Klausler     if (const auto *clamped{evaluate::UnwrapExpr<
78878d60094SPeter Klausler             evaluate::Extremum<evaluate::SubscriptInteger>>(*len)}) {
78978d60094SPeter Klausler       if (clamped->ordering == evaluate::Ordering::Greater &&
79078d60094SPeter Klausler           clamped->left() == evaluate::Expr<evaluate::SubscriptInteger>{0}) {
7910a79113bSPeter Klausler         len = common::Clone(clamped->right());
79278d60094SPeter Klausler       }
79378d60094SPeter Klausler     }
7944fede8bcSpeter klausler     AddValue(values, componentSchema_, "characterlen"s,
7954fede8bcSpeter klausler         evaluate::AsGenericExpr(GetValue(len, parameters)));
7964fede8bcSpeter klausler   } else {
7974fede8bcSpeter klausler     AddValue(values, componentSchema_, "characterlen"s,
7984fede8bcSpeter klausler         PackageIntValueExpr(deferredEnum_));
7994fede8bcSpeter klausler   }
8004fede8bcSpeter klausler   // Describe component's derived type
8014fede8bcSpeter klausler   std::vector<evaluate::StructureConstructor> lenParams;
8024fede8bcSpeter klausler   if (dyType.category() == TypeCategory::Derived &&
8034fede8bcSpeter klausler       !dyType.IsUnlimitedPolymorphic()) {
8044fede8bcSpeter klausler     const DerivedTypeSpec &spec{dyType.GetDerivedTypeSpec()};
8054fede8bcSpeter klausler     Scope *derivedScope{const_cast<Scope *>(
8064fede8bcSpeter klausler         spec.scope() ? spec.scope() : spec.typeSymbol().scope())};
80774bebee0SPeter Klausler     if (const Symbol * derivedDescription{DescribeType(DEREF(derivedScope))}) {
8084fede8bcSpeter klausler       AddValue(values, componentSchema_, "derived"s,
8094fede8bcSpeter klausler           evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
8104fede8bcSpeter klausler               evaluate::Designator<evaluate::SomeDerived>{
8114fede8bcSpeter klausler                   DEREF(derivedDescription)}}));
8124fede8bcSpeter klausler       // Package values of LEN parameters, if any
81374bebee0SPeter Klausler       if (const SymbolVector *
81474bebee0SPeter Klausler           specParams{GetTypeParameters(spec.typeSymbol())}) {
8154fede8bcSpeter klausler         for (SymbolRef ref : *specParams) {
8164fede8bcSpeter klausler           const auto &tpd{ref->get<TypeParamDetails>()};
817539a6b50SPeter Klausler           if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Len) {
81874bebee0SPeter Klausler             if (const ParamValue *
81974bebee0SPeter Klausler                 paramValue{spec.FindParameter(ref->name())}) {
8204fede8bcSpeter klausler               lenParams.emplace_back(GetValue(*paramValue, parameters));
8214fede8bcSpeter klausler             } else {
8224fede8bcSpeter klausler               lenParams.emplace_back(GetValue(tpd.init(), parameters));
8234fede8bcSpeter klausler             }
8244fede8bcSpeter klausler           }
8254fede8bcSpeter klausler         }
8264fede8bcSpeter klausler       }
82774bebee0SPeter Klausler     }
8284fede8bcSpeter klausler   } else {
8294fede8bcSpeter klausler     // Subtle: a category of Derived with a null derived type pointer
8304fede8bcSpeter klausler     // signifies CLASS(*)
8314fede8bcSpeter klausler     AddValue(values, componentSchema_, "derived"s,
8324fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
8334fede8bcSpeter klausler   }
8344fede8bcSpeter klausler   // LEN type parameter values for the component's type
8354fede8bcSpeter klausler   if (!lenParams.empty()) {
8364fede8bcSpeter klausler     AddValue(values, componentSchema_, "lenvalue"s,
8374fede8bcSpeter klausler         SaveDerivedPointerTarget(scope,
838cfd4c180SSlava Zakharin             SaveObjectName((fir::kLenParameterSeparator + distinctName +
839cfd4c180SSlava Zakharin                 fir::kNameSeparator + symbol.name().ToString())
840cfd4c180SSlava Zakharin                                .str()),
8414fede8bcSpeter klausler             std::move(lenParams),
8424fede8bcSpeter klausler             evaluate::ConstantSubscripts{
8434fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(lenParams.size())}));
8444fede8bcSpeter klausler   } else {
8454fede8bcSpeter klausler     AddValue(values, componentSchema_, "lenvalue"s,
8464fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
8474fede8bcSpeter klausler   }
8484fede8bcSpeter klausler   // Shape information
8494fede8bcSpeter klausler   AddValue(values, componentSchema_, "rank"s, IntExpr<1>(rank));
850803f1e46Speter klausler   if (rank > 0 && !IsAllocatable(symbol) && !IsPointer(symbol)) {
8514fede8bcSpeter klausler     std::vector<evaluate::StructureConstructor> bounds;
8524fede8bcSpeter klausler     evaluate::NamedEntity entity{symbol};
8534fede8bcSpeter klausler     for (int j{0}; j < rank; ++j) {
8543b61587cSPeter Klausler       bounds.emplace_back(
8553b61587cSPeter Klausler           GetValue(std::make_optional(
8563b61587cSPeter Klausler                        evaluate::GetRawLowerBound(foldingContext, entity, j)),
8574fede8bcSpeter klausler               parameters));
8584fede8bcSpeter klausler       bounds.emplace_back(GetValue(
859ca46521aSJean Perier           evaluate::GetRawUpperBound(foldingContext, entity, j), parameters));
8604fede8bcSpeter klausler     }
8614fede8bcSpeter klausler     AddValue(values, componentSchema_, "bounds"s,
8624fede8bcSpeter klausler         SaveDerivedPointerTarget(scope,
863cfd4c180SSlava Zakharin             SaveObjectName((fir::kBoundsSeparator + distinctName +
864cfd4c180SSlava Zakharin                 fir::kNameSeparator + symbol.name().ToString())
865cfd4c180SSlava Zakharin                                .str()),
8664fede8bcSpeter klausler             std::move(bounds), evaluate::ConstantSubscripts{2, rank}));
8674fede8bcSpeter klausler   } else {
8684fede8bcSpeter klausler     AddValue(
8694fede8bcSpeter klausler         values, componentSchema_, "bounds"s, SomeExpr{evaluate::NullPointer{}});
8704fede8bcSpeter klausler   }
8714fede8bcSpeter klausler   // Default component initialization
8724fede8bcSpeter klausler   bool hasDataInit{false};
8734fede8bcSpeter klausler   if (IsAllocatable(symbol)) {
8744fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("allocatable"));
8754fede8bcSpeter klausler   } else if (IsPointer(symbol)) {
8764fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("pointer"));
877a48e4168Speter klausler     hasDataInit = InitializeDataPointer(
878a48e4168Speter klausler         values, symbol, object, scope, dtScope, distinctName);
879996ef895SPeter Klausler   } else if (IsAutomatic(symbol)) {
8804fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("automatic"));
8814fede8bcSpeter klausler   } else {
8824fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("data"));
8834fede8bcSpeter klausler     hasDataInit = object.init().has_value();
8844fede8bcSpeter klausler     if (hasDataInit) {
8854fede8bcSpeter klausler       AddValue(values, componentSchema_, "initialization"s,
8864fede8bcSpeter klausler           SaveObjectInit(scope,
887cfd4c180SSlava Zakharin               SaveObjectName((fir::kComponentInitSeparator + distinctName +
888cfd4c180SSlava Zakharin                   fir::kNameSeparator + symbol.name().ToString())
889cfd4c180SSlava Zakharin                                  .str()),
8904fede8bcSpeter klausler               object));
8914fede8bcSpeter klausler     }
8924fede8bcSpeter klausler   }
8934fede8bcSpeter klausler   if (!hasDataInit) {
8944fede8bcSpeter klausler     AddValue(values, componentSchema_, "initialization"s,
8954fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
8964fede8bcSpeter klausler   }
8974fede8bcSpeter klausler   return {DEREF(componentSchema_.AsDerived()), std::move(values)};
8984fede8bcSpeter klausler }
8994fede8bcSpeter klausler 
9004fede8bcSpeter klausler evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
9014fede8bcSpeter klausler     const Symbol &symbol, const ProcEntityDetails &proc, Scope &scope) {
9024fede8bcSpeter klausler   evaluate::StructureConstructorValues values;
9034fede8bcSpeter klausler   AddValue(values, procPtrSchema_, "name"s,
9044fede8bcSpeter klausler       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
9054fede8bcSpeter klausler   AddValue(values, procPtrSchema_, "offset"s, IntExpr<8>(symbol.offset()));
9064fede8bcSpeter klausler   if (auto init{proc.init()}; init && *init) {
9074fede8bcSpeter klausler     AddValue(values, procPtrSchema_, "initialization"s,
9084fede8bcSpeter klausler         SomeExpr{evaluate::ProcedureDesignator{**init}});
9094fede8bcSpeter klausler   } else {
9104fede8bcSpeter klausler     AddValue(values, procPtrSchema_, "initialization"s,
9114fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
9124fede8bcSpeter klausler   }
9134fede8bcSpeter klausler   return {DEREF(procPtrSchema_.AsDerived()), std::move(values)};
9144fede8bcSpeter klausler }
9154fede8bcSpeter klausler 
916a48e4168Speter klausler // Create a static pointer object with the same initialization
917a48e4168Speter klausler // from whence the runtime can memcpy() the data pointer
918a48e4168Speter klausler // component initialization.
919a48e4168Speter klausler // Creates and interconnects the symbols, scopes, and types for
920a48e4168Speter klausler //   TYPE :: ptrDt
921a48e4168Speter klausler //     type, POINTER :: name
922a48e4168Speter klausler //   END TYPE
923a48e4168Speter klausler //   TYPE(ptrDt), TARGET, SAVE :: ptrInit = ptrDt(designator)
924a48e4168Speter klausler // and then initializes the original component by setting
925a48e4168Speter klausler //   initialization = ptrInit
926a48e4168Speter klausler // which takes the address of ptrInit because the type is C_PTR.
927a48e4168Speter klausler // This technique of wrapping the data pointer component into
928a48e4168Speter klausler // a derived type instance disables any reason for lowering to
929a48e4168Speter klausler // attempt to dereference the RHS of an initializer, thereby
930a48e4168Speter klausler // allowing the runtime to actually perform the initialization
931a48e4168Speter klausler // by means of a simple memcpy() of the wrapped descriptor in
932a48e4168Speter klausler // ptrInit to the data pointer component being initialized.
933a48e4168Speter klausler bool RuntimeTableBuilder::InitializeDataPointer(
934a48e4168Speter klausler     evaluate::StructureConstructorValues &values, const Symbol &symbol,
935a48e4168Speter klausler     const ObjectEntityDetails &object, Scope &scope, Scope &dtScope,
936a48e4168Speter klausler     const std::string &distinctName) {
937a48e4168Speter klausler   if (object.init().has_value()) {
938cfd4c180SSlava Zakharin     SourceName ptrDtName{SaveObjectName((fir::kDataPtrInitSeparator +
939cfd4c180SSlava Zakharin         distinctName + fir::kNameSeparator + symbol.name().ToString())
940cfd4c180SSlava Zakharin                                             .str())};
941a48e4168Speter klausler     Symbol &ptrDtSym{
942a48e4168Speter klausler         *scope.try_emplace(ptrDtName, Attrs{}, UnknownDetails{}).first->second};
9437dd7ccd2SJean Perier     SetReadOnlyCompilerCreatedFlags(ptrDtSym);
944a48e4168Speter klausler     Scope &ptrDtScope{scope.MakeScope(Scope::Kind::DerivedType, &ptrDtSym)};
945a48e4168Speter klausler     ignoreScopes_.insert(&ptrDtScope);
946a48e4168Speter klausler     ObjectEntityDetails ptrDtObj;
947a48e4168Speter klausler     ptrDtObj.set_type(DEREF(object.type()));
948a48e4168Speter klausler     ptrDtObj.set_shape(object.shape());
949a48e4168Speter klausler     Symbol &ptrDtComp{*ptrDtScope
950a48e4168Speter klausler                            .try_emplace(symbol.name(), Attrs{Attr::POINTER},
951a48e4168Speter klausler                                std::move(ptrDtObj))
952a48e4168Speter klausler                            .first->second};
953a48e4168Speter klausler     DerivedTypeDetails ptrDtDetails;
954a48e4168Speter klausler     ptrDtDetails.add_component(ptrDtComp);
955a48e4168Speter klausler     ptrDtSym.set_details(std::move(ptrDtDetails));
956a48e4168Speter klausler     ptrDtSym.set_scope(&ptrDtScope);
957a48e4168Speter klausler     DeclTypeSpec &ptrDtDeclType{
958a48e4168Speter klausler         scope.MakeDerivedType(DeclTypeSpec::Category::TypeDerived,
959a48e4168Speter klausler             DerivedTypeSpec{ptrDtName, ptrDtSym})};
960a48e4168Speter klausler     DerivedTypeSpec &ptrDtDerived{DEREF(ptrDtDeclType.AsDerived())};
961a48e4168Speter klausler     ptrDtDerived.set_scope(ptrDtScope);
962a48e4168Speter klausler     ptrDtDerived.CookParameters(context_.foldingContext());
963a48e4168Speter klausler     ptrDtDerived.Instantiate(scope);
964a48e4168Speter klausler     ObjectEntityDetails ptrInitObj;
965a48e4168Speter klausler     ptrInitObj.set_type(ptrDtDeclType);
966a48e4168Speter klausler     evaluate::StructureConstructorValues ptrInitValues;
967a48e4168Speter klausler     AddValue(
968a48e4168Speter klausler         ptrInitValues, ptrDtDeclType, symbol.name().ToString(), *object.init());
969a48e4168Speter klausler     ptrInitObj.set_init(evaluate::AsGenericExpr(
970a48e4168Speter klausler         Structure(ptrDtDeclType, std::move(ptrInitValues))));
971a48e4168Speter klausler     AddValue(values, componentSchema_, "initialization"s,
972a48e4168Speter klausler         SaveObjectInit(scope,
973cfd4c180SSlava Zakharin             SaveObjectName((fir::kComponentInitSeparator + distinctName +
974cfd4c180SSlava Zakharin                 fir::kNameSeparator + symbol.name().ToString())
975cfd4c180SSlava Zakharin                                .str()),
976a48e4168Speter klausler             ptrInitObj));
977a48e4168Speter klausler     return true;
978a48e4168Speter klausler   } else {
979a48e4168Speter klausler     return false;
980a48e4168Speter klausler   }
981a48e4168Speter klausler }
982a48e4168Speter klausler 
9834fede8bcSpeter klausler evaluate::StructureConstructor RuntimeTableBuilder::PackageIntValue(
9844fede8bcSpeter klausler     const SomeExpr &genre, std::int64_t n) const {
9854fede8bcSpeter klausler   evaluate::StructureConstructorValues xs;
9864fede8bcSpeter klausler   AddValue(xs, valueSchema_, "genre"s, genre);
9874fede8bcSpeter klausler   AddValue(xs, valueSchema_, "value"s, IntToExpr(n));
9884fede8bcSpeter klausler   return Structure(valueSchema_, std::move(xs));
9894fede8bcSpeter klausler }
9904fede8bcSpeter klausler 
9914fede8bcSpeter klausler SomeExpr RuntimeTableBuilder::PackageIntValueExpr(
9924fede8bcSpeter klausler     const SomeExpr &genre, std::int64_t n) const {
9934fede8bcSpeter klausler   return StructureExpr(PackageIntValue(genre, n));
9944fede8bcSpeter klausler }
9954fede8bcSpeter klausler 
996d38735e6SValentin Clement SymbolVector CollectBindings(const Scope &dtScope) {
997d38735e6SValentin Clement   SymbolVector result;
9987f7bbc73SPeter Klausler   std::map<SourceName, Symbol *> localBindings;
9994fede8bcSpeter klausler   // Collect local bindings
10004fede8bcSpeter klausler   for (auto pair : dtScope) {
10017f7bbc73SPeter Klausler     Symbol &symbol{const_cast<Symbol &>(*pair.second)};
10027f7bbc73SPeter Klausler     if (auto *binding{symbol.detailsIf<ProcBindingDetails>()}) {
10034fede8bcSpeter klausler       localBindings.emplace(symbol.name(), &symbol);
10047f7bbc73SPeter Klausler       binding->set_numPrivatesNotOverridden(0);
10054fede8bcSpeter klausler     }
10064fede8bcSpeter klausler   }
10074fede8bcSpeter klausler   if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) {
10084fede8bcSpeter klausler     result = CollectBindings(*parentScope);
10094fede8bcSpeter klausler     // Apply overrides from the local bindings of the extended type
10104fede8bcSpeter klausler     for (auto iter{result.begin()}; iter != result.end(); ++iter) {
10114fede8bcSpeter klausler       const Symbol &symbol{**iter};
10127f7bbc73SPeter Klausler       auto overriderIter{localBindings.find(symbol.name())};
10137f7bbc73SPeter Klausler       if (overriderIter != localBindings.end()) {
10147f7bbc73SPeter Klausler         Symbol &overrider{*overriderIter->second};
10157f7bbc73SPeter Klausler         if (symbol.attrs().test(Attr::PRIVATE) &&
10167f7bbc73SPeter Klausler             FindModuleContaining(symbol.owner()) !=
10177f7bbc73SPeter Klausler                 FindModuleContaining(dtScope)) {
10187f7bbc73SPeter Klausler           // Don't override inaccessible PRIVATE bindings
10197f7bbc73SPeter Klausler           auto &binding{overrider.get<ProcBindingDetails>()};
10207f7bbc73SPeter Klausler           binding.set_numPrivatesNotOverridden(
10217f7bbc73SPeter Klausler               binding.numPrivatesNotOverridden() + 1);
10227f7bbc73SPeter Klausler         } else {
10237f7bbc73SPeter Klausler           *iter = overrider;
10247f7bbc73SPeter Klausler           localBindings.erase(overriderIter);
10257f7bbc73SPeter Klausler         }
10264fede8bcSpeter klausler       }
10274fede8bcSpeter klausler     }
10284fede8bcSpeter klausler   }
10294fede8bcSpeter klausler   // Add remaining (non-overriding) local bindings in name order to the result
10304fede8bcSpeter klausler   for (auto pair : localBindings) {
1031d38735e6SValentin Clement     result.push_back(*pair.second);
10324fede8bcSpeter klausler   }
10334fede8bcSpeter klausler   return result;
10344fede8bcSpeter klausler }
10354fede8bcSpeter klausler 
10364fede8bcSpeter klausler std::vector<evaluate::StructureConstructor>
10374fede8bcSpeter klausler RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) {
10384fede8bcSpeter klausler   std::vector<evaluate::StructureConstructor> result;
1039d38735e6SValentin Clement   for (const SymbolRef &ref : CollectBindings(dtScope)) {
10404fede8bcSpeter klausler     evaluate::StructureConstructorValues values;
10414c5dee77SRenaud-K     AddValue(values, bindingSchema_, procCompName,
10424fede8bcSpeter klausler         SomeExpr{evaluate::ProcedureDesignator{
1043d38735e6SValentin Clement             ref.get().get<ProcBindingDetails>().symbol()}});
10444fede8bcSpeter klausler     AddValue(values, bindingSchema_, "name"s,
1045d38735e6SValentin Clement         SaveNameAsPointerTarget(scope, ref.get().name().ToString()));
10464fede8bcSpeter klausler     result.emplace_back(DEREF(bindingSchema_.AsDerived()), std::move(values));
10474fede8bcSpeter klausler   }
10484fede8bcSpeter klausler   return result;
10494fede8bcSpeter klausler }
10504fede8bcSpeter klausler 
10517ed26ad1SPeter Klausler std::map<int, evaluate::StructureConstructor>
10527ed26ad1SPeter Klausler RuntimeTableBuilder::DescribeSpecialGenerics(const Scope &dtScope,
10537ed26ad1SPeter Klausler     const Scope &thisScope, const DerivedTypeSpec *derivedTypeSpec) const {
10547ed26ad1SPeter Klausler   std::map<int, evaluate::StructureConstructor> specials;
10557ed26ad1SPeter Klausler   if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) {
10567ed26ad1SPeter Klausler     specials =
10577ed26ad1SPeter Klausler         DescribeSpecialGenerics(*parentScope, thisScope, derivedTypeSpec);
10587ed26ad1SPeter Klausler   }
10597ed26ad1SPeter Klausler   for (auto pair : dtScope) {
10607ed26ad1SPeter Klausler     const Symbol &symbol{*pair.second};
10617ed26ad1SPeter Klausler     if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
10627ed26ad1SPeter Klausler       DescribeSpecialGeneric(*generic, specials, thisScope, derivedTypeSpec);
10637ed26ad1SPeter Klausler     }
10647ed26ad1SPeter Klausler   }
10657ed26ad1SPeter Klausler   return specials;
10667ed26ad1SPeter Klausler }
10677ed26ad1SPeter Klausler 
10687ed26ad1SPeter Klausler void RuntimeTableBuilder::DescribeSpecialGeneric(const GenericDetails &generic,
1069042c964dSPeter Klausler     std::map<int, evaluate::StructureConstructor> &specials,
10707ed26ad1SPeter Klausler     const Scope &dtScope, const DerivedTypeSpec *derivedTypeSpec) const {
10716f7a3b07SV Donaldson   common::visit(
10726f7a3b07SV Donaldson       common::visitors{
10734fede8bcSpeter klausler           [&](const GenericKind::OtherKind &k) {
10744fede8bcSpeter klausler             if (k == GenericKind::OtherKind::Assignment) {
10754fede8bcSpeter klausler               for (auto ref : generic.specificProcs()) {
1076b21c24c3SPeter Klausler                 DescribeSpecialProc(specials, *ref, /*isAssignment=*/true,
1077b21c24c3SPeter Klausler                     /*isFinal=*/false, std::nullopt, &dtScope, derivedTypeSpec,
1078b21c24c3SPeter Klausler                     /*isTypeBound=*/true);
10794fede8bcSpeter klausler               }
10804fede8bcSpeter klausler             }
10814fede8bcSpeter klausler           },
10827cf1608bSPeter Klausler           [&](const common::DefinedIo &io) {
10834fede8bcSpeter klausler             switch (io) {
10847cf1608bSPeter Klausler             case common::DefinedIo::ReadFormatted:
10857cf1608bSPeter Klausler             case common::DefinedIo::ReadUnformatted:
10867cf1608bSPeter Klausler             case common::DefinedIo::WriteFormatted:
10877cf1608bSPeter Klausler             case common::DefinedIo::WriteUnformatted:
10884fede8bcSpeter klausler               for (auto ref : generic.specificProcs()) {
1089b21c24c3SPeter Klausler                 DescribeSpecialProc(specials, *ref, /*isAssignment=*/false,
1090b21c24c3SPeter Klausler                     /*isFinal=*/false, io, &dtScope, derivedTypeSpec,
1091b21c24c3SPeter Klausler                     /*isTypeBound=*/true);
10924fede8bcSpeter klausler               }
10934fede8bcSpeter klausler               break;
10944fede8bcSpeter klausler             }
10954fede8bcSpeter klausler           },
10964fede8bcSpeter klausler           [](const auto &) {},
10974fede8bcSpeter klausler       },
10984fede8bcSpeter klausler       generic.kind().u);
10994fede8bcSpeter klausler }
11004fede8bcSpeter klausler 
11014fede8bcSpeter klausler void RuntimeTableBuilder::DescribeSpecialProc(
110265f52904Speter klausler     std::map<int, evaluate::StructureConstructor> &specials,
11034fede8bcSpeter klausler     const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
11047cf1608bSPeter Klausler     std::optional<common::DefinedIo> io, const Scope *dtScope,
11057cf1608bSPeter Klausler     const DerivedTypeSpec *derivedTypeSpec, bool isTypeBound) const {
11064fede8bcSpeter klausler   const auto *binding{specificOrBinding.detailsIf<ProcBindingDetails>()};
11077ed26ad1SPeter Klausler   if (binding && dtScope) { // use most recent override
11087ed26ad1SPeter Klausler     binding = &DEREF(dtScope->FindComponent(specificOrBinding.name()))
11097ed26ad1SPeter Klausler                    .get<ProcBindingDetails>();
11107ed26ad1SPeter Klausler   }
11114fede8bcSpeter klausler   const Symbol &specific{*(binding ? &binding->symbol() : &specificOrBinding)};
11124fede8bcSpeter klausler   if (auto proc{evaluate::characteristics::Procedure::Characterize(
11134fede8bcSpeter klausler           specific, context_.foldingContext())}) {
11144fede8bcSpeter klausler     std::uint8_t isArgDescriptorSet{0};
1115b21c24c3SPeter Klausler     std::uint8_t isArgContiguousSet{0};
11164fede8bcSpeter klausler     int argThatMightBeDescriptor{0};
11174fede8bcSpeter klausler     MaybeExpr which;
1118467525bdSpeter klausler     if (isAssignment) {
1119467525bdSpeter klausler       // Only type-bound asst's with the same type on both dummy arguments
1120467525bdSpeter klausler       // are germane to the runtime, which needs only these to implement
1121467525bdSpeter klausler       // component assignment as part of intrinsic assignment.
1122467525bdSpeter klausler       // Non-type-bound generic INTERFACEs and assignments from distinct
1123467525bdSpeter klausler       // types must not be used for component intrinsic assignment.
11244fede8bcSpeter klausler       CHECK(proc->dummyArguments.size() == 2);
1125*050f785eSPhilip Reames       const auto t1{
1126467525bdSpeter klausler           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1127*050f785eSPhilip Reames                     &proc->dummyArguments[0].u))
1128*050f785eSPhilip Reames               .type.type()};
1129467525bdSpeter klausler       const auto t2{
1130467525bdSpeter klausler           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1131467525bdSpeter klausler                     &proc->dummyArguments[1].u))
1132467525bdSpeter klausler               .type.type()};
1133467525bdSpeter klausler       if (!binding || t1.category() != TypeCategory::Derived ||
1134467525bdSpeter klausler           t2.category() != TypeCategory::Derived ||
1135467525bdSpeter klausler           t1.IsUnlimitedPolymorphic() || t2.IsUnlimitedPolymorphic() ||
1136467525bdSpeter klausler           t1.GetDerivedTypeSpec() != t2.GetDerivedTypeSpec()) {
1137467525bdSpeter klausler         return;
1138467525bdSpeter klausler       }
113965f52904Speter klausler       which = proc->IsElemental() ? elementalAssignmentEnum_
114065f52904Speter klausler                                   : scalarAssignmentEnum_;
11414fede8bcSpeter klausler       if (binding && binding->passName() &&
11424fede8bcSpeter klausler           *binding->passName() == proc->dummyArguments[1].name) {
11434fede8bcSpeter klausler         argThatMightBeDescriptor = 1;
11444fede8bcSpeter klausler         isArgDescriptorSet |= 2;
11454fede8bcSpeter klausler       } else {
11464fede8bcSpeter klausler         argThatMightBeDescriptor = 2; // the non-passed-object argument
11474fede8bcSpeter klausler         isArgDescriptorSet |= 1;
11484fede8bcSpeter klausler       }
11494fede8bcSpeter klausler     } else if (isFinal) {
11504fede8bcSpeter klausler       CHECK(binding == nullptr); // FINALs are not bindings
11514fede8bcSpeter klausler       CHECK(proc->dummyArguments.size() == 1);
11524fede8bcSpeter klausler       if (proc->IsElemental()) {
11534fede8bcSpeter klausler         which = elementalFinalEnum_;
11544fede8bcSpeter klausler       } else {
1155b21c24c3SPeter Klausler         const auto &dummyData{
11564fede8bcSpeter klausler             std::get<evaluate::characteristics::DummyDataObject>(
1157b21c24c3SPeter Klausler                 proc->dummyArguments.at(0).u)};
1158b21c24c3SPeter Klausler         const auto &typeAndShape{dummyData.type};
11594fede8bcSpeter klausler         if (typeAndShape.attrs().test(
11604fede8bcSpeter klausler                 evaluate::characteristics::TypeAndShape::Attr::AssumedRank)) {
11614fede8bcSpeter klausler           which = assumedRankFinalEnum_;
11624fede8bcSpeter klausler           isArgDescriptorSet |= 1;
11634fede8bcSpeter klausler         } else {
116465f52904Speter klausler           which = scalarFinalEnum_;
116573cf0142SjeanPerier           if (int rank{typeAndShape.Rank()}; rank > 0) {
116665f52904Speter klausler             which = IntExpr<1>(ToInt64(which).value() + rank);
1167b477d39bSjeanPerier             if (dummyData.IsPassedByDescriptor(proc->IsBindC())) {
1168b21c24c3SPeter Klausler               argThatMightBeDescriptor = 1;
1169b21c24c3SPeter Klausler             }
1170b21c24c3SPeter Klausler             if (!typeAndShape.attrs().test(evaluate::characteristics::
1171b21c24c3SPeter Klausler                         TypeAndShape::Attr::AssumedShape) ||
1172b21c24c3SPeter Klausler                 dummyData.attrs.test(evaluate::characteristics::
1173b21c24c3SPeter Klausler                         DummyDataObject::Attr::Contiguous)) {
1174b21c24c3SPeter Klausler               isArgContiguousSet |= 1;
1175b21c24c3SPeter Klausler             }
11764fede8bcSpeter klausler           }
11774fede8bcSpeter klausler         }
11784fede8bcSpeter klausler       }
11797cf1608bSPeter Klausler     } else { // defined derived type I/O
11804fede8bcSpeter klausler       CHECK(proc->dummyArguments.size() >= 4);
1181099a62e1SPeter Klausler       const auto *ddo{std::get_if<evaluate::characteristics::DummyDataObject>(
1182099a62e1SPeter Klausler           &proc->dummyArguments[0].u)};
1183099a62e1SPeter Klausler       if (!ddo) {
1184099a62e1SPeter Klausler         return;
1185099a62e1SPeter Klausler       }
1186042c964dSPeter Klausler       if (derivedTypeSpec &&
1187099a62e1SPeter Klausler           !ddo->type.type().IsTkCompatibleWith(
1188099a62e1SPeter Klausler               evaluate::DynamicType{*derivedTypeSpec})) {
1189042c964dSPeter Klausler         // Defined I/O specific procedure is not for this derived type.
1190042c964dSPeter Klausler         return;
1191042c964dSPeter Klausler       }
1192099a62e1SPeter Klausler       if (ddo->type.type().IsPolymorphic()) {
11934fede8bcSpeter klausler         isArgDescriptorSet |= 1;
11944fede8bcSpeter klausler       }
11954fede8bcSpeter klausler       switch (io.value()) {
11967cf1608bSPeter Klausler       case common::DefinedIo::ReadFormatted:
11974fede8bcSpeter klausler         which = readFormattedEnum_;
11984fede8bcSpeter klausler         break;
11997cf1608bSPeter Klausler       case common::DefinedIo::ReadUnformatted:
12004fede8bcSpeter klausler         which = readUnformattedEnum_;
12014fede8bcSpeter klausler         break;
12027cf1608bSPeter Klausler       case common::DefinedIo::WriteFormatted:
12034fede8bcSpeter klausler         which = writeFormattedEnum_;
12044fede8bcSpeter klausler         break;
12057cf1608bSPeter Klausler       case common::DefinedIo::WriteUnformatted:
12064fede8bcSpeter klausler         which = writeUnformattedEnum_;
12074fede8bcSpeter klausler         break;
12084fede8bcSpeter klausler       }
12094fede8bcSpeter klausler     }
1210b477d39bSjeanPerier     if (argThatMightBeDescriptor != 0) {
1211b477d39bSjeanPerier       if (const auto *dummyData{
1212b477d39bSjeanPerier               std::get_if<evaluate::characteristics::DummyDataObject>(
1213b477d39bSjeanPerier                   &proc->dummyArguments.at(argThatMightBeDescriptor - 1).u)}) {
1214b477d39bSjeanPerier         if (dummyData->IsPassedByDescriptor(proc->IsBindC())) {
12154fede8bcSpeter klausler           isArgDescriptorSet |= 1 << (argThatMightBeDescriptor - 1);
12164fede8bcSpeter klausler         }
1217b477d39bSjeanPerier       }
1218b477d39bSjeanPerier     }
12194fede8bcSpeter klausler     evaluate::StructureConstructorValues values;
122065f52904Speter klausler     auto index{evaluate::ToInt64(which)};
122165f52904Speter klausler     CHECK(index.has_value());
12224fede8bcSpeter klausler     AddValue(
12234fede8bcSpeter klausler         values, specialSchema_, "which"s, SomeExpr{std::move(which.value())});
12244fede8bcSpeter klausler     AddValue(values, specialSchema_, "isargdescriptorset"s,
12254fede8bcSpeter klausler         IntExpr<1>(isArgDescriptorSet));
12267cf1608bSPeter Klausler     AddValue(values, specialSchema_, "istypebound"s,
12277cf1608bSPeter Klausler         IntExpr<1>(isTypeBound ? 1 : 0));
1228b21c24c3SPeter Klausler     AddValue(values, specialSchema_, "isargcontiguousset"s,
1229b21c24c3SPeter Klausler         IntExpr<1>(isArgContiguousSet));
12304c5dee77SRenaud-K     AddValue(values, specialSchema_, procCompName,
12314fede8bcSpeter klausler         SomeExpr{evaluate::ProcedureDesignator{specific}});
12327ed26ad1SPeter Klausler     // index might already be present in the case of an override
12337ed26ad1SPeter Klausler     specials.emplace(*index,
12347ed26ad1SPeter Klausler         evaluate::StructureConstructor{
12357ed26ad1SPeter Klausler             DEREF(specialSchema_.AsDerived()), std::move(values)});
12364fede8bcSpeter klausler   }
12374fede8bcSpeter klausler }
12384fede8bcSpeter klausler 
12394fede8bcSpeter klausler void RuntimeTableBuilder::IncorporateDefinedIoGenericInterfaces(
124019d86426SPeter Klausler     std::map<int, evaluate::StructureConstructor> &specials,
12417cf1608bSPeter Klausler     common::DefinedIo definedIo, const Scope *scope,
1242042c964dSPeter Klausler     const DerivedTypeSpec *derivedTypeSpec) {
124319d86426SPeter Klausler   SourceName name{GenericKind::AsFortran(definedIo)};
12444fede8bcSpeter klausler   for (; !scope->IsGlobal(); scope = &scope->parent()) {
12454fede8bcSpeter klausler     if (auto asst{scope->find(name)}; asst != scope->end()) {
12463726626aSPeter Klausler       const Symbol &generic{asst->second->GetUltimate()};
12474fede8bcSpeter klausler       const auto &genericDetails{generic.get<GenericDetails>()};
12487cf1608bSPeter Klausler       CHECK(std::holds_alternative<common::DefinedIo>(genericDetails.kind().u));
12497cf1608bSPeter Klausler       CHECK(std::get<common::DefinedIo>(genericDetails.kind().u) == definedIo);
12504fede8bcSpeter klausler       for (auto ref : genericDetails.specificProcs()) {
12517cf1608bSPeter Klausler         DescribeSpecialProc(specials, *ref, false, false, definedIo, nullptr,
12527cf1608bSPeter Klausler             derivedTypeSpec, false);
12534fede8bcSpeter klausler       }
12544fede8bcSpeter klausler     }
12554fede8bcSpeter klausler   }
12564fede8bcSpeter klausler }
12574fede8bcSpeter klausler 
12584fede8bcSpeter klausler RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(
12594fede8bcSpeter klausler     SemanticsContext &context) {
12604fede8bcSpeter klausler   RuntimeDerivedTypeTables result;
1261dc55c443SPeter Klausler   // Do not attempt to read __fortran_type_info.mod when compiling
1262dc55c443SPeter Klausler   // the module on which it depends.
1263dc55c443SPeter Klausler   const auto &allSources{context.allCookedSources().allSources()};
1264dc55c443SPeter Klausler   if (auto firstProv{allSources.GetFirstFileProvenance()}) {
1265dc55c443SPeter Klausler     if (const auto *srcFile{allSources.GetSourceFile(firstProv->start())}) {
1266dc55c443SPeter Klausler       if (srcFile->path().find("__fortran_builtins.f90") != std::string::npos) {
1267dc55c443SPeter Klausler         return result;
1268dc55c443SPeter Klausler       }
1269dc55c443SPeter Klausler     }
1270dc55c443SPeter Klausler   }
12717dd7ccd2SJean Perier   result.schemata = context.GetBuiltinModule(typeInfoBuiltinModule);
12724fede8bcSpeter klausler   if (result.schemata) {
12734fede8bcSpeter klausler     RuntimeTableBuilder builder{context, result};
1274a48e4168Speter klausler     builder.DescribeTypes(context.globalScope(), false);
12754fede8bcSpeter klausler   }
12764fede8bcSpeter klausler   return result;
12774fede8bcSpeter klausler }
1278ded52a44SValentin Clement 
12796f7a3b07SV Donaldson // Find the type of a defined I/O procedure's interface's initial "dtv"
12806f7a3b07SV Donaldson // dummy argument.  Returns a non-null DeclTypeSpec pointer only if that
12816f7a3b07SV Donaldson // dtv argument exists and is a derived type.
12826f7a3b07SV Donaldson static const DeclTypeSpec *GetDefinedIoSpecificArgType(const Symbol &specific) {
1283b21c24c3SPeter Klausler   const Symbol *interface{&specific.GetUltimate()};
12846f7a3b07SV Donaldson   if (const auto *procEntity{specific.detailsIf<ProcEntityDetails>()}) {
12856f7a3b07SV Donaldson     interface = procEntity->procInterface();
12866f7a3b07SV Donaldson   }
12876f7a3b07SV Donaldson   if (interface) {
12886f7a3b07SV Donaldson     if (const SubprogramDetails *
12896f7a3b07SV Donaldson             subprogram{interface->detailsIf<SubprogramDetails>()};
12906f7a3b07SV Donaldson         subprogram && !subprogram->dummyArgs().empty()) {
12916f7a3b07SV Donaldson       if (const Symbol * dtvArg{subprogram->dummyArgs().at(0)}) {
12926f7a3b07SV Donaldson         if (const DeclTypeSpec * declType{dtvArg->GetType()}) {
12936f7a3b07SV Donaldson           return declType->AsDerived() ? declType : nullptr;
12946f7a3b07SV Donaldson         }
12956f7a3b07SV Donaldson       }
12966f7a3b07SV Donaldson     }
12976f7a3b07SV Donaldson   }
12986f7a3b07SV Donaldson   return nullptr;
12996f7a3b07SV Donaldson }
13006f7a3b07SV Donaldson 
13016f7a3b07SV Donaldson // Locate a particular scope's generic interface for a specific kind of
13026f7a3b07SV Donaldson // defined I/O.
13036f7a3b07SV Donaldson static const Symbol *FindGenericDefinedIo(
13046f7a3b07SV Donaldson     const Scope &scope, common::DefinedIo which) {
13056f7a3b07SV Donaldson   if (const Symbol * symbol{scope.FindSymbol(GenericKind::AsFortran(which))}) {
13066f7a3b07SV Donaldson     const Symbol &generic{symbol->GetUltimate()};
13076f7a3b07SV Donaldson     const auto &genericDetails{generic.get<GenericDetails>()};
13086f7a3b07SV Donaldson     CHECK(std::holds_alternative<common::DefinedIo>(genericDetails.kind().u));
13096f7a3b07SV Donaldson     CHECK(std::get<common::DefinedIo>(genericDetails.kind().u) == which);
13106f7a3b07SV Donaldson     return &generic;
13116f7a3b07SV Donaldson   } else {
13126f7a3b07SV Donaldson     return nullptr;
13136f7a3b07SV Donaldson   }
13146f7a3b07SV Donaldson }
13156f7a3b07SV Donaldson 
13167cf1608bSPeter Klausler std::multimap<const Symbol *, NonTbpDefinedIo>
13176f7a3b07SV Donaldson CollectNonTbpDefinedIoGenericInterfaces(
13186f7a3b07SV Donaldson     const Scope &scope, bool useRuntimeTypeInfoEntries) {
13197cf1608bSPeter Klausler   std::multimap<const Symbol *, NonTbpDefinedIo> result;
13207cf1608bSPeter Klausler   if (!scope.IsTopLevel() &&
13217cf1608bSPeter Klausler       (scope.GetImportKind() == Scope::ImportKind::All ||
13227cf1608bSPeter Klausler           scope.GetImportKind() == Scope::ImportKind::Default)) {
13236f7a3b07SV Donaldson     result = CollectNonTbpDefinedIoGenericInterfaces(
13246f7a3b07SV Donaldson         scope.parent(), useRuntimeTypeInfoEntries);
13257cf1608bSPeter Klausler   }
13267cf1608bSPeter Klausler   if (scope.kind() != Scope::Kind::DerivedType) {
13277cf1608bSPeter Klausler     for (common::DefinedIo which :
13287cf1608bSPeter Klausler         {common::DefinedIo::ReadFormatted, common::DefinedIo::ReadUnformatted,
13297cf1608bSPeter Klausler             common::DefinedIo::WriteFormatted,
13307cf1608bSPeter Klausler             common::DefinedIo::WriteUnformatted}) {
13316f7a3b07SV Donaldson       if (const Symbol * generic{FindGenericDefinedIo(scope, which)}) {
13326f7a3b07SV Donaldson         for (auto specific : generic->get<GenericDetails>().specificProcs()) {
13336f7a3b07SV Donaldson           if (const DeclTypeSpec *
13346f7a3b07SV Donaldson               declType{GetDefinedIoSpecificArgType(*specific)}) {
13356f7a3b07SV Donaldson             const DerivedTypeSpec &derived{DEREF(declType->AsDerived())};
13367cf1608bSPeter Klausler             if (const Symbol *
13376f7a3b07SV Donaldson                 dtDesc{derived.scope()
13386f7a3b07SV Donaldson                         ? derived.scope()->runtimeDerivedTypeDescription()
13397cf1608bSPeter Klausler                         : nullptr}) {
13406f7a3b07SV Donaldson               if (useRuntimeTypeInfoEntries &&
13416f7a3b07SV Donaldson                   &derived.scope()->parent() == &generic->owner()) {
13427cf1608bSPeter Klausler                 // This non-TBP defined I/O generic was defined in the
13437cf1608bSPeter Klausler                 // same scope as the derived type, and it will be
13447cf1608bSPeter Klausler                 // included in the derived type's special bindings
13457cf1608bSPeter Klausler                 // by IncorporateDefinedIoGenericInterfaces().
13467cf1608bSPeter Klausler               } else {
13477cf1608bSPeter Klausler                 // Local scope's specific overrides host's for this type
13487cf1608bSPeter Klausler                 bool updated{false};
13497cf1608bSPeter Klausler                 for (auto [iter, end]{result.equal_range(dtDesc)}; iter != end;
13507cf1608bSPeter Klausler                      ++iter) {
13517cf1608bSPeter Klausler                   NonTbpDefinedIo &nonTbp{iter->second};
13527cf1608bSPeter Klausler                   if (nonTbp.definedIo == which) {
13537cf1608bSPeter Klausler                     nonTbp.subroutine = &*specific;
13547cf1608bSPeter Klausler                     nonTbp.isDtvArgPolymorphic = declType->IsPolymorphic();
13557cf1608bSPeter Klausler                     updated = true;
13567cf1608bSPeter Klausler                   }
13577cf1608bSPeter Klausler                 }
13587cf1608bSPeter Klausler                 if (!updated) {
13597cf1608bSPeter Klausler                   result.emplace(dtDesc,
13607cf1608bSPeter Klausler                       NonTbpDefinedIo{
13617cf1608bSPeter Klausler                           &*specific, which, declType->IsPolymorphic()});
13627cf1608bSPeter Klausler                 }
13637cf1608bSPeter Klausler               }
13647cf1608bSPeter Klausler             }
13657cf1608bSPeter Klausler           }
13667cf1608bSPeter Klausler         }
13677cf1608bSPeter Klausler       }
13687cf1608bSPeter Klausler     }
13696f7a3b07SV Donaldson   }
13707cf1608bSPeter Klausler   return result;
13717cf1608bSPeter Klausler }
13727cf1608bSPeter Klausler 
13736f7a3b07SV Donaldson // ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces()
13746f7a3b07SV Donaldson //
13756f7a3b07SV Donaldson // Returns a true result when a kind of defined I/O generic procedure
13766f7a3b07SV Donaldson // has a type (from a symbol or a NAMELIST) such that
13776f7a3b07SV Donaldson // (1) there is a specific procedure matching that type for a non-type-bound
13786f7a3b07SV Donaldson //     generic defined in the scope of the type, and
13796f7a3b07SV Donaldson // (2) that specific procedure is unavailable or overridden in a particular
13806f7a3b07SV Donaldson //     local scope.
13816f7a3b07SV Donaldson // Specific procedures of non-type-bound defined I/O generic interfaces
13826f7a3b07SV Donaldson // declared in the scope of a derived type are identified as special bindings
13836f7a3b07SV Donaldson // in the derived type's runtime type information, as if they had been
13846f7a3b07SV Donaldson // type-bound.  This predicate is meant to determine local situations in
13856f7a3b07SV Donaldson // which those special bindings are not to be used.  Its result is intended
13866f7a3b07SV Donaldson // to be put into the "ignoreNonTbpEntries" flag of
13876f7a3b07SV Donaldson // runtime::NonTbpDefinedIoTable and passed (negated) as the
13886f7a3b07SV Donaldson // "useRuntimeTypeInfoEntries" argument of
13896f7a3b07SV Donaldson // CollectNonTbpDefinedIoGenericInterfaces() above.
13906f7a3b07SV Donaldson 
13916f7a3b07SV Donaldson static const Symbol *FindSpecificDefinedIo(const Scope &scope,
13926f7a3b07SV Donaldson     const evaluate::DynamicType &derived, common::DefinedIo which) {
13936f7a3b07SV Donaldson   if (const Symbol * generic{FindGenericDefinedIo(scope, which)}) {
13946f7a3b07SV Donaldson     for (auto ref : generic->get<GenericDetails>().specificProcs()) {
13956f7a3b07SV Donaldson       const Symbol &specific{*ref};
13966f7a3b07SV Donaldson       if (const DeclTypeSpec *
13976f7a3b07SV Donaldson           thisType{GetDefinedIoSpecificArgType(specific)}) {
13986f7a3b07SV Donaldson         if (evaluate::DynamicType{DEREF(thisType->AsDerived()), true}
13996f7a3b07SV Donaldson                 .IsTkCompatibleWith(derived)) {
14006f7a3b07SV Donaldson           return &specific.GetUltimate();
14016f7a3b07SV Donaldson         }
14026f7a3b07SV Donaldson       }
14036f7a3b07SV Donaldson     }
14046f7a3b07SV Donaldson   }
14056f7a3b07SV Donaldson   return nullptr;
14066f7a3b07SV Donaldson }
14076f7a3b07SV Donaldson 
14086f7a3b07SV Donaldson bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
14096f7a3b07SV Donaldson     const Scope &scope, const DerivedTypeSpec *derived) {
14106f7a3b07SV Donaldson   if (!derived) {
14116f7a3b07SV Donaldson     return false;
14126f7a3b07SV Donaldson   }
14136f7a3b07SV Donaldson   const Symbol &typeSymbol{derived->typeSymbol()};
14146f7a3b07SV Donaldson   const Scope &typeScope{typeSymbol.GetUltimate().owner()};
14156f7a3b07SV Donaldson   evaluate::DynamicType dyType{*derived};
14166f7a3b07SV Donaldson   for (common::DefinedIo which :
14176f7a3b07SV Donaldson       {common::DefinedIo::ReadFormatted, common::DefinedIo::ReadUnformatted,
14186f7a3b07SV Donaldson           common::DefinedIo::WriteFormatted,
14196f7a3b07SV Donaldson           common::DefinedIo::WriteUnformatted}) {
14206f7a3b07SV Donaldson     if (const Symbol *
14216f7a3b07SV Donaldson         specific{FindSpecificDefinedIo(typeScope, dyType, which)}) {
14226f7a3b07SV Donaldson       // There's a non-TBP defined I/O procedure in the scope of the type's
14236f7a3b07SV Donaldson       // definition that applies to this type.  It will appear in the type's
14246f7a3b07SV Donaldson       // runtime information.  Determine whether it still applies in the
14256f7a3b07SV Donaldson       // scope of interest.
14266f7a3b07SV Donaldson       if (FindSpecificDefinedIo(scope, dyType, which) != specific) {
14276f7a3b07SV Donaldson         return true;
14286f7a3b07SV Donaldson       }
14296f7a3b07SV Donaldson     }
14306f7a3b07SV Donaldson   }
14316f7a3b07SV Donaldson   return false;
14326f7a3b07SV Donaldson }
14336f7a3b07SV Donaldson 
14346f7a3b07SV Donaldson bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
14356f7a3b07SV Donaldson     const Scope &scope, const DeclTypeSpec *type) {
14366f7a3b07SV Donaldson   return type &&
14376f7a3b07SV Donaldson       ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
14386f7a3b07SV Donaldson           scope, type->AsDerived());
14396f7a3b07SV Donaldson }
14406f7a3b07SV Donaldson 
14416f7a3b07SV Donaldson bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
14426f7a3b07SV Donaldson     const Scope &scope, const Symbol *symbol) {
14436f7a3b07SV Donaldson   if (!symbol) {
14446f7a3b07SV Donaldson     return false;
14456f7a3b07SV Donaldson   }
14466f7a3b07SV Donaldson   return common::visit(
14476f7a3b07SV Donaldson       common::visitors{
14486f7a3b07SV Donaldson           [&](const NamelistDetails &x) {
14496f7a3b07SV Donaldson             for (auto ref : x.objects()) {
14506f7a3b07SV Donaldson               if (ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
14516f7a3b07SV Donaldson                       scope, &*ref)) {
14526f7a3b07SV Donaldson                 return true;
14536f7a3b07SV Donaldson               }
14546f7a3b07SV Donaldson             }
14556f7a3b07SV Donaldson             return false;
14566f7a3b07SV Donaldson           },
14576f7a3b07SV Donaldson           [&](const auto &) {
14586f7a3b07SV Donaldson             return ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
14596f7a3b07SV Donaldson                 scope, symbol->GetType());
14606f7a3b07SV Donaldson           },
14616f7a3b07SV Donaldson       },
14626f7a3b07SV Donaldson       symbol->GetUltimate().details());
14636f7a3b07SV Donaldson }
14646f7a3b07SV Donaldson 
14654fede8bcSpeter klausler } // namespace Fortran::semantics
1466