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"
154fede8bcSpeter klausler #include "flang/Semantics/scope.h"
164fede8bcSpeter klausler #include "flang/Semantics/tools.h"
1765f52904Speter klausler #include <functional>
184fede8bcSpeter klausler #include <list>
194fede8bcSpeter klausler #include <map>
204fede8bcSpeter klausler #include <string>
214fede8bcSpeter klausler 
224fede8bcSpeter klausler namespace Fortran::semantics {
234fede8bcSpeter klausler 
FindLenParameterIndex(const SymbolVector & parameters,const Symbol & symbol)244fede8bcSpeter klausler static int FindLenParameterIndex(
254fede8bcSpeter klausler     const SymbolVector &parameters, const Symbol &symbol) {
264fede8bcSpeter klausler   int lenIndex{0};
274fede8bcSpeter klausler   for (SymbolRef ref : parameters) {
284fede8bcSpeter klausler     if (&*ref == &symbol) {
294fede8bcSpeter klausler       return lenIndex;
304fede8bcSpeter klausler     }
314fede8bcSpeter klausler     if (ref->get<TypeParamDetails>().attr() == common::TypeParamAttr::Len) {
324fede8bcSpeter klausler       ++lenIndex;
334fede8bcSpeter klausler     }
344fede8bcSpeter klausler   }
354fede8bcSpeter klausler   DIE("Length type parameter not found in parameter order");
364fede8bcSpeter klausler   return -1;
374fede8bcSpeter klausler }
384fede8bcSpeter klausler 
394fede8bcSpeter klausler class RuntimeTableBuilder {
404fede8bcSpeter klausler public:
414fede8bcSpeter klausler   RuntimeTableBuilder(SemanticsContext &, RuntimeDerivedTypeTables &);
42a48e4168Speter klausler   void DescribeTypes(Scope &scope, bool inSchemata);
434fede8bcSpeter klausler 
444fede8bcSpeter klausler private:
454fede8bcSpeter klausler   const Symbol *DescribeType(Scope &);
464fede8bcSpeter klausler   const Symbol &GetSchemaSymbol(const char *) const;
474fede8bcSpeter klausler   const DeclTypeSpec &GetSchema(const char *) const;
484fede8bcSpeter klausler   SomeExpr GetEnumValue(const char *) const;
494fede8bcSpeter klausler   Symbol &CreateObject(const std::string &, const DeclTypeSpec &, Scope &);
504fede8bcSpeter klausler   // The names of created symbols are saved in and owned by the
514fede8bcSpeter klausler   // RuntimeDerivedTypeTables instance returned by
524fede8bcSpeter klausler   // BuildRuntimeDerivedTypeTables() so that references to those names remain
534fede8bcSpeter klausler   // valid for lowering.
544fede8bcSpeter klausler   SourceName SaveObjectName(const std::string &);
554fede8bcSpeter klausler   SomeExpr SaveNameAsPointerTarget(Scope &, const std::string &);
564fede8bcSpeter klausler   const SymbolVector *GetTypeParameters(const Symbol &);
574fede8bcSpeter klausler   evaluate::StructureConstructor DescribeComponent(const Symbol &,
581971960aSJean Perier       const ObjectEntityDetails &, Scope &, Scope &,
591971960aSJean Perier       const std::string &distinctName, const SymbolVector *parameters);
604fede8bcSpeter klausler   evaluate::StructureConstructor DescribeComponent(
614fede8bcSpeter klausler       const Symbol &, const ProcEntityDetails &, Scope &);
62a48e4168Speter klausler   bool InitializeDataPointer(evaluate::StructureConstructorValues &,
63a48e4168Speter klausler       const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
64a48e4168Speter klausler       Scope &dtScope, const std::string &distinctName);
654fede8bcSpeter klausler   evaluate::StructureConstructor PackageIntValue(
664fede8bcSpeter klausler       const SomeExpr &genre, std::int64_t = 0) const;
674fede8bcSpeter klausler   SomeExpr PackageIntValueExpr(const SomeExpr &genre, std::int64_t = 0) const;
684fede8bcSpeter klausler   std::vector<const Symbol *> CollectBindings(const Scope &dtScope) const;
694fede8bcSpeter klausler   std::vector<evaluate::StructureConstructor> DescribeBindings(
704fede8bcSpeter klausler       const Scope &dtScope, Scope &);
714fede8bcSpeter klausler   void DescribeGeneric(
7265f52904Speter klausler       const GenericDetails &, std::map<int, evaluate::StructureConstructor> &);
7365f52904Speter klausler   void DescribeSpecialProc(std::map<int, evaluate::StructureConstructor> &,
744fede8bcSpeter klausler       const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
754fede8bcSpeter klausler       std::optional<GenericKind::DefinedIo>);
764fede8bcSpeter klausler   void IncorporateDefinedIoGenericInterfaces(
7719d86426SPeter Klausler       std::map<int, evaluate::StructureConstructor> &, GenericKind::DefinedIo,
7819d86426SPeter Klausler       const Scope *);
794fede8bcSpeter klausler 
804fede8bcSpeter klausler   // Instantiated for ParamValue and Bound
814fede8bcSpeter klausler   template <typename A>
GetValue(const A & x,const SymbolVector * parameters)824fede8bcSpeter klausler   evaluate::StructureConstructor GetValue(
834fede8bcSpeter klausler       const A &x, const SymbolVector *parameters) {
844fede8bcSpeter klausler     if (x.isExplicit()) {
854fede8bcSpeter klausler       return GetValue(x.GetExplicit(), parameters);
864fede8bcSpeter klausler     } else {
874fede8bcSpeter klausler       return PackageIntValue(deferredEnum_);
884fede8bcSpeter klausler     }
894fede8bcSpeter klausler   }
904fede8bcSpeter klausler 
914fede8bcSpeter klausler   // Specialization for optional<Expr<SomeInteger and SubscriptInteger>>
924fede8bcSpeter klausler   template <typename T>
GetValue(const std::optional<evaluate::Expr<T>> & expr,const SymbolVector * parameters)934fede8bcSpeter klausler   evaluate::StructureConstructor GetValue(
944fede8bcSpeter klausler       const std::optional<evaluate::Expr<T>> &expr,
954fede8bcSpeter klausler       const SymbolVector *parameters) {
964fede8bcSpeter klausler     if (auto constValue{evaluate::ToInt64(expr)}) {
974fede8bcSpeter klausler       return PackageIntValue(explicitEnum_, *constValue);
984fede8bcSpeter klausler     }
994fede8bcSpeter klausler     if (expr) {
100803f1e46Speter klausler       if (parameters) {
101803f1e46Speter klausler         if (const Symbol * lenParam{evaluate::ExtractBareLenParameter(*expr)}) {
102803f1e46Speter klausler           return PackageIntValue(
103803f1e46Speter klausler               lenParameterEnum_, FindLenParameterIndex(*parameters, *lenParam));
104803f1e46Speter klausler         }
105803f1e46Speter klausler       }
106*0a79113bSPeter Klausler       // TODO: Replace a specification expression requiring actual operations
107*0a79113bSPeter Klausler       // with a reference to a new anonymous LEN type parameter whose default
108*0a79113bSPeter Klausler       // value captures the expression.  This replacement must take place when
109*0a79113bSPeter Klausler       // the type is declared so that the new LEN type parameters appear in
110*0a79113bSPeter Klausler       // all instantiations and structure constructors.
1114fede8bcSpeter klausler       context_.Say(location_,
112*0a79113bSPeter Klausler           "derived type specification expression '%s' that is neither constant nor a length type parameter"_todo_en_US,
1134fede8bcSpeter klausler           expr->AsFortran());
1144fede8bcSpeter klausler     }
1154fede8bcSpeter klausler     return PackageIntValue(deferredEnum_);
1164fede8bcSpeter klausler   }
1174fede8bcSpeter klausler 
1184fede8bcSpeter klausler   SemanticsContext &context_;
1194fede8bcSpeter klausler   RuntimeDerivedTypeTables &tables_;
1204fede8bcSpeter klausler   std::map<const Symbol *, SymbolVector> orderedTypeParameters_;
1214fede8bcSpeter klausler 
1224fede8bcSpeter klausler   const DeclTypeSpec &derivedTypeSchema_; // TYPE(DerivedType)
1234fede8bcSpeter klausler   const DeclTypeSpec &componentSchema_; // TYPE(Component)
1244fede8bcSpeter klausler   const DeclTypeSpec &procPtrSchema_; // TYPE(ProcPtrComponent)
1254fede8bcSpeter klausler   const DeclTypeSpec &valueSchema_; // TYPE(Value)
1264fede8bcSpeter klausler   const DeclTypeSpec &bindingSchema_; // TYPE(Binding)
1274fede8bcSpeter klausler   const DeclTypeSpec &specialSchema_; // TYPE(SpecialBinding)
1284fede8bcSpeter klausler   SomeExpr deferredEnum_; // Value::Genre::Deferred
1294fede8bcSpeter klausler   SomeExpr explicitEnum_; // Value::Genre::Explicit
1304fede8bcSpeter klausler   SomeExpr lenParameterEnum_; // Value::Genre::LenParameter
13165f52904Speter klausler   SomeExpr scalarAssignmentEnum_; // SpecialBinding::Which::ScalarAssignment
1324fede8bcSpeter klausler   SomeExpr
1334fede8bcSpeter klausler       elementalAssignmentEnum_; // SpecialBinding::Which::ElementalAssignment
1344fede8bcSpeter klausler   SomeExpr readFormattedEnum_; // SpecialBinding::Which::ReadFormatted
1354fede8bcSpeter klausler   SomeExpr readUnformattedEnum_; // SpecialBinding::Which::ReadUnformatted
1364fede8bcSpeter klausler   SomeExpr writeFormattedEnum_; // SpecialBinding::Which::WriteFormatted
1374fede8bcSpeter klausler   SomeExpr writeUnformattedEnum_; // SpecialBinding::Which::WriteUnformatted
13865f52904Speter klausler   SomeExpr elementalFinalEnum_; // SpecialBinding::Which::ElementalFinal
13965f52904Speter klausler   SomeExpr assumedRankFinalEnum_; // SpecialBinding::Which::AssumedRankFinal
14065f52904Speter klausler   SomeExpr scalarFinalEnum_; // SpecialBinding::Which::ScalarFinal
1414fede8bcSpeter klausler   parser::CharBlock location_;
142a48e4168Speter klausler   std::set<const Scope *> ignoreScopes_;
1434fede8bcSpeter klausler };
1444fede8bcSpeter klausler 
RuntimeTableBuilder(SemanticsContext & c,RuntimeDerivedTypeTables & t)1454fede8bcSpeter klausler RuntimeTableBuilder::RuntimeTableBuilder(
1464fede8bcSpeter klausler     SemanticsContext &c, RuntimeDerivedTypeTables &t)
1474fede8bcSpeter klausler     : context_{c}, tables_{t}, derivedTypeSchema_{GetSchema("derivedtype")},
1484fede8bcSpeter klausler       componentSchema_{GetSchema("component")}, procPtrSchema_{GetSchema(
1494fede8bcSpeter klausler                                                     "procptrcomponent")},
1504fede8bcSpeter klausler       valueSchema_{GetSchema("value")}, bindingSchema_{GetSchema("binding")},
1514fede8bcSpeter klausler       specialSchema_{GetSchema("specialbinding")}, deferredEnum_{GetEnumValue(
1524fede8bcSpeter klausler                                                        "deferred")},
1534fede8bcSpeter klausler       explicitEnum_{GetEnumValue("explicit")}, lenParameterEnum_{GetEnumValue(
1544fede8bcSpeter klausler                                                    "lenparameter")},
15565f52904Speter klausler       scalarAssignmentEnum_{GetEnumValue("scalarassignment")},
1564fede8bcSpeter klausler       elementalAssignmentEnum_{GetEnumValue("elementalassignment")},
1574fede8bcSpeter klausler       readFormattedEnum_{GetEnumValue("readformatted")},
1584fede8bcSpeter klausler       readUnformattedEnum_{GetEnumValue("readunformatted")},
1594fede8bcSpeter klausler       writeFormattedEnum_{GetEnumValue("writeformatted")},
16065f52904Speter klausler       writeUnformattedEnum_{GetEnumValue("writeunformatted")},
16165f52904Speter klausler       elementalFinalEnum_{GetEnumValue("elementalfinal")},
16265f52904Speter klausler       assumedRankFinalEnum_{GetEnumValue("assumedrankfinal")},
16365f52904Speter klausler       scalarFinalEnum_{GetEnumValue("scalarfinal")} {
164a48e4168Speter klausler   ignoreScopes_.insert(tables_.schemata);
165a48e4168Speter klausler }
1664fede8bcSpeter klausler 
DescribeTypes(Scope & scope,bool inSchemata)167a48e4168Speter klausler void RuntimeTableBuilder::DescribeTypes(Scope &scope, bool inSchemata) {
168a48e4168Speter klausler   inSchemata |= ignoreScopes_.find(&scope) != ignoreScopes_.end();
1694fede8bcSpeter klausler   if (scope.IsDerivedType()) {
170a48e4168Speter klausler     if (!inSchemata) { // don't loop trying to describe a schema
1714fede8bcSpeter klausler       DescribeType(scope);
1724fede8bcSpeter klausler     }
173a48e4168Speter klausler   } else {
174a48e4168Speter klausler     scope.InstantiateDerivedTypes();
175a48e4168Speter klausler   }
176a48e4168Speter klausler   for (Scope &child : scope.children()) {
177a48e4168Speter klausler     DescribeTypes(child, inSchemata);
1784fede8bcSpeter klausler   }
1794fede8bcSpeter klausler }
1804fede8bcSpeter klausler 
1814fede8bcSpeter klausler // Returns derived type instantiation's parameters in declaration order
GetTypeParameters(const Symbol & symbol)1824fede8bcSpeter klausler const SymbolVector *RuntimeTableBuilder::GetTypeParameters(
1834fede8bcSpeter klausler     const Symbol &symbol) {
1844fede8bcSpeter klausler   auto iter{orderedTypeParameters_.find(&symbol)};
1854fede8bcSpeter klausler   if (iter != orderedTypeParameters_.end()) {
1864fede8bcSpeter klausler     return &iter->second;
1874fede8bcSpeter klausler   } else {
1884fede8bcSpeter klausler     return &orderedTypeParameters_
1894fede8bcSpeter klausler                 .emplace(&symbol, OrderParameterDeclarations(symbol))
1904fede8bcSpeter klausler                 .first->second;
1914fede8bcSpeter klausler   }
1924fede8bcSpeter klausler }
1934fede8bcSpeter klausler 
GetContainingNonDerivedScope(Scope & scope)1944fede8bcSpeter klausler static Scope &GetContainingNonDerivedScope(Scope &scope) {
1954fede8bcSpeter klausler   Scope *p{&scope};
1964fede8bcSpeter klausler   while (p->IsDerivedType()) {
1974fede8bcSpeter klausler     p = &p->parent();
1984fede8bcSpeter klausler   }
1994fede8bcSpeter klausler   return *p;
2004fede8bcSpeter klausler }
2014fede8bcSpeter klausler 
GetSchemaField(const DerivedTypeSpec & derived,const std::string & name)2024fede8bcSpeter klausler static const Symbol &GetSchemaField(
2034fede8bcSpeter klausler     const DerivedTypeSpec &derived, const std::string &name) {
2044fede8bcSpeter klausler   const Scope &scope{
2054fede8bcSpeter klausler       DEREF(derived.scope() ? derived.scope() : derived.typeSymbol().scope())};
2064fede8bcSpeter klausler   auto iter{scope.find(SourceName(name))};
2074fede8bcSpeter klausler   CHECK(iter != scope.end());
2084fede8bcSpeter klausler   return *iter->second;
2094fede8bcSpeter klausler }
2104fede8bcSpeter klausler 
GetSchemaField(const DeclTypeSpec & derived,const std::string & name)2114fede8bcSpeter klausler static const Symbol &GetSchemaField(
2124fede8bcSpeter klausler     const DeclTypeSpec &derived, const std::string &name) {
2134fede8bcSpeter klausler   return GetSchemaField(DEREF(derived.AsDerived()), name);
2144fede8bcSpeter klausler }
2154fede8bcSpeter klausler 
AddValue(evaluate::StructureConstructorValues & values,const DeclTypeSpec & spec,const std::string & name,SomeExpr && x)2164fede8bcSpeter klausler static evaluate::StructureConstructorValues &AddValue(
2174fede8bcSpeter klausler     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
2184fede8bcSpeter klausler     const std::string &name, SomeExpr &&x) {
2194fede8bcSpeter klausler   values.emplace(GetSchemaField(spec, name), std::move(x));
2204fede8bcSpeter klausler   return values;
2214fede8bcSpeter klausler }
2224fede8bcSpeter klausler 
AddValue(evaluate::StructureConstructorValues & values,const DeclTypeSpec & spec,const std::string & name,const SomeExpr & x)2234fede8bcSpeter klausler static evaluate::StructureConstructorValues &AddValue(
2244fede8bcSpeter klausler     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
2254fede8bcSpeter klausler     const std::string &name, const SomeExpr &x) {
2264fede8bcSpeter klausler   values.emplace(GetSchemaField(spec, name), x);
2274fede8bcSpeter klausler   return values;
2284fede8bcSpeter klausler }
2294fede8bcSpeter klausler 
IntToExpr(std::int64_t n)2304fede8bcSpeter klausler static SomeExpr IntToExpr(std::int64_t n) {
2314fede8bcSpeter klausler   return evaluate::AsGenericExpr(evaluate::ExtentExpr{n});
2324fede8bcSpeter klausler }
2334fede8bcSpeter klausler 
Structure(const DeclTypeSpec & spec,evaluate::StructureConstructorValues && values)2344fede8bcSpeter klausler static evaluate::StructureConstructor Structure(
2354fede8bcSpeter klausler     const DeclTypeSpec &spec, evaluate::StructureConstructorValues &&values) {
2364fede8bcSpeter klausler   return {DEREF(spec.AsDerived()), std::move(values)};
2374fede8bcSpeter klausler }
2384fede8bcSpeter klausler 
StructureExpr(evaluate::StructureConstructor && x)2394fede8bcSpeter klausler static SomeExpr StructureExpr(evaluate::StructureConstructor &&x) {
2404fede8bcSpeter klausler   return SomeExpr{evaluate::Expr<evaluate::SomeDerived>{std::move(x)}};
2414fede8bcSpeter klausler }
2424fede8bcSpeter klausler 
GetIntegerKind(const Symbol & symbol)2434fede8bcSpeter klausler static int GetIntegerKind(const Symbol &symbol) {
2444fede8bcSpeter klausler   auto dyType{evaluate::DynamicType::From(symbol)};
2454fede8bcSpeter klausler   CHECK(dyType && dyType->category() == TypeCategory::Integer);
2464fede8bcSpeter klausler   return dyType->kind();
2474fede8bcSpeter klausler }
2484fede8bcSpeter klausler 
SetReadOnlyCompilerCreatedFlags(Symbol & symbol)2497dd7ccd2SJean Perier static void SetReadOnlyCompilerCreatedFlags(Symbol &symbol) {
2507dd7ccd2SJean Perier   symbol.set(Symbol::Flag::CompilerCreated);
2517dd7ccd2SJean Perier   // Runtime type info symbols may have types that are incompatible with the
2527dd7ccd2SJean Perier   // PARAMETER attribute (the main issue is that they may be TARGET, and normal
2537dd7ccd2SJean Perier   // Fortran parameters cannot be TARGETs).
2547dd7ccd2SJean Perier   if (symbol.has<semantics::ObjectEntityDetails>() ||
2557dd7ccd2SJean Perier       symbol.has<semantics::ProcEntityDetails>()) {
2567dd7ccd2SJean Perier     symbol.set(Symbol::Flag::ReadOnly);
2577dd7ccd2SJean Perier   }
2587dd7ccd2SJean Perier }
2597dd7ccd2SJean Perier 
2604fede8bcSpeter klausler // Save a rank-1 array constant of some numeric type as an
2614fede8bcSpeter klausler // initialized data object in a scope.
2624fede8bcSpeter klausler template <typename T>
SaveNumericPointerTarget(Scope & scope,SourceName name,std::vector<typename T::Scalar> && x)2634fede8bcSpeter klausler static SomeExpr SaveNumericPointerTarget(
2644fede8bcSpeter klausler     Scope &scope, SourceName name, std::vector<typename T::Scalar> &&x) {
2654fede8bcSpeter klausler   if (x.empty()) {
2664fede8bcSpeter klausler     return SomeExpr{evaluate::NullPointer{}};
2674fede8bcSpeter klausler   } else {
2684fede8bcSpeter klausler     ObjectEntityDetails object;
2694fede8bcSpeter klausler     if (const auto *spec{scope.FindType(
2704fede8bcSpeter klausler             DeclTypeSpec{NumericTypeSpec{T::category, KindExpr{T::kind}}})}) {
2714fede8bcSpeter klausler       object.set_type(*spec);
2724fede8bcSpeter klausler     } else {
2734fede8bcSpeter klausler       object.set_type(scope.MakeNumericType(T::category, KindExpr{T::kind}));
2744fede8bcSpeter klausler     }
2754fede8bcSpeter klausler     auto elements{static_cast<evaluate::ConstantSubscript>(x.size())};
2764fede8bcSpeter klausler     ArraySpec arraySpec;
2774fede8bcSpeter klausler     arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{elements - 1}));
2784fede8bcSpeter klausler     object.set_shape(arraySpec);
2794fede8bcSpeter klausler     object.set_init(evaluate::AsGenericExpr(evaluate::Constant<T>{
2804fede8bcSpeter klausler         std::move(x), evaluate::ConstantSubscripts{elements}}));
281d60a0220Speter klausler     Symbol &symbol{*scope
282d60a0220Speter klausler                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
283d60a0220Speter klausler                             std::move(object))
2844fede8bcSpeter klausler                         .first->second};
2857dd7ccd2SJean Perier     SetReadOnlyCompilerCreatedFlags(symbol);
2864fede8bcSpeter klausler     return evaluate::AsGenericExpr(
2874fede8bcSpeter klausler         evaluate::Expr<T>{evaluate::Designator<T>{symbol}});
2884fede8bcSpeter klausler   }
2894fede8bcSpeter klausler }
2904fede8bcSpeter klausler 
2914fede8bcSpeter klausler // Save an arbitrarily shaped array constant of some derived type
2924fede8bcSpeter klausler // as an initialized data object in a scope.
SaveDerivedPointerTarget(Scope & scope,SourceName name,std::vector<evaluate::StructureConstructor> && x,evaluate::ConstantSubscripts && shape)2934fede8bcSpeter klausler static SomeExpr SaveDerivedPointerTarget(Scope &scope, SourceName name,
2944fede8bcSpeter klausler     std::vector<evaluate::StructureConstructor> &&x,
2954fede8bcSpeter klausler     evaluate::ConstantSubscripts &&shape) {
2964fede8bcSpeter klausler   if (x.empty()) {
2974fede8bcSpeter klausler     return SomeExpr{evaluate::NullPointer{}};
2984fede8bcSpeter klausler   } else {
2994fede8bcSpeter klausler     const auto &derivedType{x.front().GetType().GetDerivedTypeSpec()};
3004fede8bcSpeter klausler     ObjectEntityDetails object;
3014fede8bcSpeter klausler     DeclTypeSpec typeSpec{DeclTypeSpec::TypeDerived, derivedType};
3024fede8bcSpeter klausler     if (const DeclTypeSpec * spec{scope.FindType(typeSpec)}) {
3034fede8bcSpeter klausler       object.set_type(*spec);
3044fede8bcSpeter klausler     } else {
3054fede8bcSpeter klausler       object.set_type(scope.MakeDerivedType(
3064fede8bcSpeter klausler           DeclTypeSpec::TypeDerived, common::Clone(derivedType)));
3074fede8bcSpeter klausler     }
3084fede8bcSpeter klausler     if (!shape.empty()) {
3094fede8bcSpeter klausler       ArraySpec arraySpec;
3104fede8bcSpeter klausler       for (auto n : shape) {
3114fede8bcSpeter klausler         arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{n - 1}));
3124fede8bcSpeter klausler       }
3134fede8bcSpeter klausler       object.set_shape(arraySpec);
3144fede8bcSpeter klausler     }
3154fede8bcSpeter klausler     object.set_init(
3164fede8bcSpeter klausler         evaluate::AsGenericExpr(evaluate::Constant<evaluate::SomeDerived>{
3174fede8bcSpeter klausler             derivedType, std::move(x), std::move(shape)}));
318d60a0220Speter klausler     Symbol &symbol{*scope
319d60a0220Speter klausler                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
320d60a0220Speter klausler                             std::move(object))
3214fede8bcSpeter klausler                         .first->second};
3227dd7ccd2SJean Perier     SetReadOnlyCompilerCreatedFlags(symbol);
3234fede8bcSpeter klausler     return evaluate::AsGenericExpr(
3244fede8bcSpeter klausler         evaluate::Designator<evaluate::SomeDerived>{symbol});
3254fede8bcSpeter klausler   }
3264fede8bcSpeter klausler }
3274fede8bcSpeter klausler 
SaveObjectInit(Scope & scope,SourceName name,const ObjectEntityDetails & object)3284fede8bcSpeter klausler static SomeExpr SaveObjectInit(
3294fede8bcSpeter klausler     Scope &scope, SourceName name, const ObjectEntityDetails &object) {
330d60a0220Speter klausler   Symbol &symbol{*scope
3314fede8bcSpeter klausler                       .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
3324fede8bcSpeter klausler                           ObjectEntityDetails{object})
3334fede8bcSpeter klausler                       .first->second};
3344fede8bcSpeter klausler   CHECK(symbol.get<ObjectEntityDetails>().init().has_value());
3357dd7ccd2SJean Perier   SetReadOnlyCompilerCreatedFlags(symbol);
3364fede8bcSpeter klausler   return evaluate::AsGenericExpr(
3374fede8bcSpeter klausler       evaluate::Designator<evaluate::SomeDerived>{symbol});
3384fede8bcSpeter klausler }
3394fede8bcSpeter klausler 
IntExpr(std::int64_t n)340a48e4168Speter klausler template <int KIND> static SomeExpr IntExpr(std::int64_t n) {
341a48e4168Speter klausler   return evaluate::AsGenericExpr(
342a48e4168Speter klausler       evaluate::Constant<evaluate::Type<TypeCategory::Integer, KIND>>{n});
343a48e4168Speter klausler }
344a48e4168Speter klausler 
GetSuffixIfTypeKindParameters(const DerivedTypeSpec & derivedTypeSpec,const SymbolVector * parameters)345f88a9497SJean Perier static std::optional<std::string> GetSuffixIfTypeKindParameters(
346f88a9497SJean Perier     const DerivedTypeSpec &derivedTypeSpec, const SymbolVector *parameters) {
347f88a9497SJean Perier   if (parameters) {
348f88a9497SJean Perier     std::optional<std::string> suffix;
349f88a9497SJean Perier     for (SymbolRef ref : *parameters) {
350f88a9497SJean Perier       const auto &tpd{ref->get<TypeParamDetails>()};
351f88a9497SJean Perier       if (tpd.attr() == common::TypeParamAttr::Kind) {
352f88a9497SJean Perier         if (const auto *pv{derivedTypeSpec.FindParameter(ref->name())}) {
353f88a9497SJean Perier           if (pv->GetExplicit()) {
354f88a9497SJean Perier             if (auto instantiatedValue{evaluate::ToInt64(*pv->GetExplicit())}) {
355f88a9497SJean Perier               if (suffix.has_value()) {
356f88a9497SJean Perier                 *suffix += "."s + std::to_string(*instantiatedValue);
357f88a9497SJean Perier               } else {
358f88a9497SJean Perier                 suffix = "."s + std::to_string(*instantiatedValue);
359f88a9497SJean Perier               }
360f88a9497SJean Perier             }
361f88a9497SJean Perier           }
362f88a9497SJean Perier         }
363f88a9497SJean Perier       }
364f88a9497SJean Perier     }
365f88a9497SJean Perier     return suffix;
366f88a9497SJean Perier   }
367f88a9497SJean Perier   return std::nullopt;
368f88a9497SJean Perier }
369f88a9497SJean Perier 
DescribeType(Scope & dtScope)3704fede8bcSpeter klausler const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
3714fede8bcSpeter klausler   if (const Symbol * info{dtScope.runtimeDerivedTypeDescription()}) {
3724fede8bcSpeter klausler     return info;
3734fede8bcSpeter klausler   }
3744fede8bcSpeter klausler   const DerivedTypeSpec *derivedTypeSpec{dtScope.derivedTypeSpec()};
375f2da8f5eSJean Perier   if (!derivedTypeSpec && !dtScope.IsDerivedTypeWithKindParameter() &&
376a48e4168Speter klausler       dtScope.symbol()) {
377a48e4168Speter klausler     // This derived type was declared (obviously, there's a Scope) but never
378a48e4168Speter klausler     // used in this compilation (no instantiated DerivedTypeSpec points here).
379a48e4168Speter klausler     // Create a DerivedTypeSpec now for it so that ComponentIterator
380a48e4168Speter klausler     // will work. This covers the case of a derived type that's declared in
381a48e4168Speter klausler     // a module but used only by clients and submodules, enabling the
382a48e4168Speter klausler     // run-time "no initialization needed here" flag to work.
383a48e4168Speter klausler     DerivedTypeSpec derived{dtScope.symbol()->name(), *dtScope.symbol()};
384f88a9497SJean Perier     if (const SymbolVector *
385f88a9497SJean Perier         lenParameters{GetTypeParameters(*dtScope.symbol())}) {
386f88a9497SJean Perier       // Create dummy deferred values for the length parameters so that the
387f88a9497SJean Perier       // DerivedTypeSpec is complete and can be used in helpers.
388f88a9497SJean Perier       for (SymbolRef lenParam : *lenParameters) {
38906be1488SAndrzej Warzynski         (void)lenParam;
390f88a9497SJean Perier         derived.AddRawParamValue(
391f88a9497SJean Perier             std::nullopt, ParamValue::Deferred(common::TypeParamAttr::Len));
392f88a9497SJean Perier       }
393f88a9497SJean Perier       derived.CookParameters(context_.foldingContext());
394f88a9497SJean Perier     }
395a48e4168Speter klausler     DeclTypeSpec &decl{
396a48e4168Speter klausler         dtScope.MakeDerivedType(DeclTypeSpec::TypeDerived, std::move(derived))};
397a48e4168Speter klausler     derivedTypeSpec = &decl.derivedTypeSpec();
398a48e4168Speter klausler   }
3994fede8bcSpeter klausler   const Symbol *dtSymbol{
4004fede8bcSpeter klausler       derivedTypeSpec ? &derivedTypeSpec->typeSymbol() : dtScope.symbol()};
4014fede8bcSpeter klausler   if (!dtSymbol) {
4024fede8bcSpeter klausler     return nullptr;
4034fede8bcSpeter klausler   }
4044fede8bcSpeter klausler   auto locationRestorer{common::ScopedSet(location_, dtSymbol->name())};
4054fede8bcSpeter klausler   // Check for an existing description that can be imported from a USE'd module
4064fede8bcSpeter klausler   std::string typeName{dtSymbol->name().ToString()};
407c14cf92bSPeter Klausler   if (typeName.empty() ||
408c14cf92bSPeter Klausler       (typeName.front() == '.' && !context_.IsTempName(typeName))) {
4094fede8bcSpeter klausler     return nullptr;
4104fede8bcSpeter klausler   }
411f88a9497SJean Perier   const SymbolVector *parameters{GetTypeParameters(*dtSymbol)};
4124fede8bcSpeter klausler   std::string distinctName{typeName};
413f88a9497SJean Perier   if (&dtScope != dtSymbol->scope() && derivedTypeSpec) {
414f88a9497SJean Perier     // Only create new type descriptions for different kind parameter values.
415f88a9497SJean Perier     // Type with different length parameters/same kind parameters can all
416f88a9497SJean Perier     // share the same type description available in the current scope.
417f88a9497SJean Perier     if (auto suffix{
418f88a9497SJean Perier             GetSuffixIfTypeKindParameters(*derivedTypeSpec, parameters)}) {
419f88a9497SJean Perier       distinctName += *suffix;
420f88a9497SJean Perier     }
4214fede8bcSpeter klausler   }
4224fede8bcSpeter klausler   std::string dtDescName{".dt."s + distinctName};
423f88a9497SJean Perier   Scope *dtSymbolScope{const_cast<Scope *>(dtSymbol->scope())};
424f88a9497SJean Perier   Scope &scope{
425f88a9497SJean Perier       GetContainingNonDerivedScope(dtSymbolScope ? *dtSymbolScope : dtScope)};
426f88a9497SJean Perier   if (const auto it{scope.find(SourceName{dtDescName})}; it != scope.end()) {
427f88a9497SJean Perier     dtScope.set_runtimeDerivedTypeDescription(*it->second);
428f88a9497SJean Perier     return &*it->second;
4294fede8bcSpeter klausler   }
430f88a9497SJean Perier 
4314fede8bcSpeter klausler   // Create a new description object before populating it so that mutual
4324fede8bcSpeter klausler   // references will work as pointer targets.
4334fede8bcSpeter klausler   Symbol &dtObject{CreateObject(dtDescName, derivedTypeSchema_, scope)};
4344fede8bcSpeter klausler   dtScope.set_runtimeDerivedTypeDescription(dtObject);
4354fede8bcSpeter klausler   evaluate::StructureConstructorValues dtValues;
4364fede8bcSpeter klausler   AddValue(dtValues, derivedTypeSchema_, "name"s,
4374fede8bcSpeter klausler       SaveNameAsPointerTarget(scope, typeName));
438f88a9497SJean Perier   bool isPDTdefinitionWithKindParameters{
439f2da8f5eSJean Perier       !derivedTypeSpec && dtScope.IsDerivedTypeWithKindParameter()};
440f88a9497SJean Perier   if (!isPDTdefinitionWithKindParameters) {
4414fede8bcSpeter klausler     auto sizeInBytes{static_cast<common::ConstantSubscript>(dtScope.size())};
4424fede8bcSpeter klausler     if (auto alignment{dtScope.alignment().value_or(0)}) {
4434fede8bcSpeter klausler       sizeInBytes += alignment - 1;
4444fede8bcSpeter klausler       sizeInBytes /= alignment;
4454fede8bcSpeter klausler       sizeInBytes *= alignment;
4464fede8bcSpeter klausler     }
4474fede8bcSpeter klausler     AddValue(
4484fede8bcSpeter klausler         dtValues, derivedTypeSchema_, "sizeinbytes"s, IntToExpr(sizeInBytes));
4494fede8bcSpeter klausler   }
4504fede8bcSpeter klausler   bool isPDTinstantiation{derivedTypeSpec && &dtScope != dtSymbol->scope()};
4514fede8bcSpeter klausler   if (isPDTinstantiation) {
4524fede8bcSpeter klausler     // is PDT instantiation
4534fede8bcSpeter klausler     const Symbol *uninstDescObject{
4544fede8bcSpeter klausler         DescribeType(DEREF(const_cast<Scope *>(dtSymbol->scope())))};
4554fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
4564fede8bcSpeter klausler         evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
4574fede8bcSpeter klausler             evaluate::Designator<evaluate::SomeDerived>{
4584fede8bcSpeter klausler                 DEREF(uninstDescObject)}}));
4594fede8bcSpeter klausler   } else {
4604fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
4614fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
4624fede8bcSpeter klausler   }
4634fede8bcSpeter klausler   using Int8 = evaluate::Type<TypeCategory::Integer, 8>;
4644fede8bcSpeter klausler   using Int1 = evaluate::Type<TypeCategory::Integer, 1>;
4654fede8bcSpeter klausler   std::vector<Int8::Scalar> kinds;
4664fede8bcSpeter klausler   std::vector<Int1::Scalar> lenKinds;
4674fede8bcSpeter klausler   if (parameters) {
4684fede8bcSpeter klausler     // Package the derived type's parameters in declaration order for
4694fede8bcSpeter klausler     // each category of parameter.  KIND= type parameters are described
4704fede8bcSpeter klausler     // by their instantiated (or default) values, while LEN= type
4714fede8bcSpeter klausler     // parameters are described by their INTEGER kinds.
4724fede8bcSpeter klausler     for (SymbolRef ref : *parameters) {
4734fede8bcSpeter klausler       const auto &tpd{ref->get<TypeParamDetails>()};
4744fede8bcSpeter klausler       if (tpd.attr() == common::TypeParamAttr::Kind) {
4754fede8bcSpeter klausler         auto value{evaluate::ToInt64(tpd.init()).value_or(0)};
4764fede8bcSpeter klausler         if (derivedTypeSpec) {
4774fede8bcSpeter klausler           if (const auto *pv{derivedTypeSpec->FindParameter(ref->name())}) {
4784fede8bcSpeter klausler             if (pv->GetExplicit()) {
4794fede8bcSpeter klausler               if (auto instantiatedValue{
4804fede8bcSpeter klausler                       evaluate::ToInt64(*pv->GetExplicit())}) {
4814fede8bcSpeter klausler                 value = *instantiatedValue;
4824fede8bcSpeter klausler               }
4834fede8bcSpeter klausler             }
4844fede8bcSpeter klausler           }
4854fede8bcSpeter klausler         }
4864fede8bcSpeter klausler         kinds.emplace_back(value);
4874fede8bcSpeter klausler       } else { // LEN= parameter
4884fede8bcSpeter klausler         lenKinds.emplace_back(GetIntegerKind(*ref));
4894fede8bcSpeter klausler       }
4904fede8bcSpeter klausler     }
4914fede8bcSpeter klausler   }
4924fede8bcSpeter klausler   AddValue(dtValues, derivedTypeSchema_, "kindparameter"s,
4934fede8bcSpeter klausler       SaveNumericPointerTarget<Int8>(
4944fede8bcSpeter klausler           scope, SaveObjectName(".kp."s + distinctName), std::move(kinds)));
4954fede8bcSpeter klausler   AddValue(dtValues, derivedTypeSchema_, "lenparameterkind"s,
4964fede8bcSpeter klausler       SaveNumericPointerTarget<Int1>(
4974fede8bcSpeter klausler           scope, SaveObjectName(".lpk."s + distinctName), std::move(lenKinds)));
4984fede8bcSpeter klausler   // Traverse the components of the derived type
499f88a9497SJean Perier   if (!isPDTdefinitionWithKindParameters) {
50079caf69cSpeter klausler     std::vector<const Symbol *> dataComponentSymbols;
5014fede8bcSpeter klausler     std::vector<evaluate::StructureConstructor> procPtrComponents;
50265f52904Speter klausler     std::map<int, evaluate::StructureConstructor> specials;
5034fede8bcSpeter klausler     for (const auto &pair : dtScope) {
5044fede8bcSpeter klausler       const Symbol &symbol{*pair.second};
5054fede8bcSpeter klausler       auto locationRestorer{common::ScopedSet(location_, symbol.name())};
506cd03e96fSPeter Klausler       common::visit(
5074fede8bcSpeter klausler           common::visitors{
5084fede8bcSpeter klausler               [&](const TypeParamDetails &) {
5094fede8bcSpeter klausler                 // already handled above in declaration order
5104fede8bcSpeter klausler               },
51179caf69cSpeter klausler               [&](const ObjectEntityDetails &) {
51279caf69cSpeter klausler                 dataComponentSymbols.push_back(&symbol);
5134fede8bcSpeter klausler               },
5144fede8bcSpeter klausler               [&](const ProcEntityDetails &proc) {
5154fede8bcSpeter klausler                 if (IsProcedurePointer(symbol)) {
5164fede8bcSpeter klausler                   procPtrComponents.emplace_back(
5171971960aSJean Perier                       DescribeComponent(symbol, proc, scope));
5184fede8bcSpeter klausler                 }
5194fede8bcSpeter klausler               },
5204fede8bcSpeter klausler               [&](const ProcBindingDetails &) { // handled in a later pass
5214fede8bcSpeter klausler               },
5224fede8bcSpeter klausler               [&](const GenericDetails &generic) {
5234fede8bcSpeter klausler                 DescribeGeneric(generic, specials);
5244fede8bcSpeter klausler               },
5254fede8bcSpeter klausler               [&](const auto &) {
5264fede8bcSpeter klausler                 common::die(
5274fede8bcSpeter klausler                     "unexpected details on symbol '%s' in derived type scope",
5284fede8bcSpeter klausler                     symbol.name().ToString().c_str());
5294fede8bcSpeter klausler               },
5304fede8bcSpeter klausler           },
5314fede8bcSpeter klausler           symbol.details());
5324fede8bcSpeter klausler     }
53379caf69cSpeter klausler     // Sort the data component symbols by offset before emitting them
53479caf69cSpeter klausler     std::sort(dataComponentSymbols.begin(), dataComponentSymbols.end(),
53579caf69cSpeter klausler         [](const Symbol *x, const Symbol *y) {
53679caf69cSpeter klausler           return x->offset() < y->offset();
53779caf69cSpeter klausler         });
53879caf69cSpeter klausler     std::vector<evaluate::StructureConstructor> dataComponents;
53979caf69cSpeter klausler     for (const Symbol *symbol : dataComponentSymbols) {
54079caf69cSpeter klausler       auto locationRestorer{common::ScopedSet(location_, symbol->name())};
54179caf69cSpeter klausler       dataComponents.emplace_back(
54279caf69cSpeter klausler           DescribeComponent(*symbol, symbol->get<ObjectEntityDetails>(), scope,
54379caf69cSpeter klausler               dtScope, distinctName, parameters));
54479caf69cSpeter klausler     }
5454fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "component"s,
5464fede8bcSpeter klausler         SaveDerivedPointerTarget(scope, SaveObjectName(".c."s + distinctName),
5474fede8bcSpeter klausler             std::move(dataComponents),
5484fede8bcSpeter klausler             evaluate::ConstantSubscripts{
5494fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(
5504fede8bcSpeter klausler                     dataComponents.size())}));
5514fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "procptr"s,
5524fede8bcSpeter klausler         SaveDerivedPointerTarget(scope, SaveObjectName(".p."s + distinctName),
5534fede8bcSpeter klausler             std::move(procPtrComponents),
5544fede8bcSpeter klausler             evaluate::ConstantSubscripts{
5554fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(
5564fede8bcSpeter klausler                     procPtrComponents.size())}));
5574fede8bcSpeter klausler     // Compile the "vtable" of type-bound procedure bindings
5584fede8bcSpeter klausler     std::vector<evaluate::StructureConstructor> bindings{
5594fede8bcSpeter klausler         DescribeBindings(dtScope, scope)};
5604fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "binding"s,
5614fede8bcSpeter klausler         SaveDerivedPointerTarget(scope, SaveObjectName(".v."s + distinctName),
5624fede8bcSpeter klausler             std::move(bindings),
5634fede8bcSpeter klausler             evaluate::ConstantSubscripts{
5644fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(bindings.size())}));
5654fede8bcSpeter klausler     // Describe "special" bindings to defined assignments, FINAL subroutines,
5664fede8bcSpeter klausler     // and user-defined derived type I/O subroutines.
56765f52904Speter klausler     const DerivedTypeDetails &dtDetails{dtSymbol->get<DerivedTypeDetails>()};
56865f52904Speter klausler     for (const auto &pair : dtDetails.finals()) {
56965f52904Speter klausler       DescribeSpecialProc(
57065f52904Speter klausler           specials, *pair.second, false /*!isAssignment*/, true, std::nullopt);
5714fede8bcSpeter klausler     }
57219d86426SPeter Klausler     IncorporateDefinedIoGenericInterfaces(
57319d86426SPeter Klausler         specials, GenericKind::DefinedIo::ReadFormatted, &scope);
57419d86426SPeter Klausler     IncorporateDefinedIoGenericInterfaces(
57519d86426SPeter Klausler         specials, GenericKind::DefinedIo::ReadUnformatted, &scope);
57619d86426SPeter Klausler     IncorporateDefinedIoGenericInterfaces(
57719d86426SPeter Klausler         specials, GenericKind::DefinedIo::WriteFormatted, &scope);
57819d86426SPeter Klausler     IncorporateDefinedIoGenericInterfaces(
57919d86426SPeter Klausler         specials, GenericKind::DefinedIo::WriteUnformatted, &scope);
58065f52904Speter klausler     // Pack the special procedure bindings in ascending order of their "which"
58165f52904Speter klausler     // code values, and compile a little-endian bit-set of those codes for
58265f52904Speter klausler     // use in O(1) look-up at run time.
58365f52904Speter klausler     std::vector<evaluate::StructureConstructor> sortedSpecials;
58465f52904Speter klausler     std::uint32_t specialBitSet{0};
58565f52904Speter klausler     for (auto &pair : specials) {
58665f52904Speter klausler       auto bit{std::uint32_t{1} << pair.first};
58765f52904Speter klausler       CHECK(!(specialBitSet & bit));
58865f52904Speter klausler       specialBitSet |= bit;
58965f52904Speter klausler       sortedSpecials.emplace_back(std::move(pair.second));
59065f52904Speter klausler     }
5914fede8bcSpeter klausler     AddValue(dtValues, derivedTypeSchema_, "special"s,
5924fede8bcSpeter klausler         SaveDerivedPointerTarget(scope, SaveObjectName(".s."s + distinctName),
59365f52904Speter klausler             std::move(sortedSpecials),
5944fede8bcSpeter klausler             evaluate::ConstantSubscripts{
5954fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(specials.size())}));
59665f52904Speter klausler     AddValue(dtValues, derivedTypeSchema_, "specialbitset"s,
59765f52904Speter klausler         IntExpr<4>(specialBitSet));
598a48e4168Speter klausler     // Note the presence/absence of a parent component
599a48e4168Speter klausler     AddValue(dtValues, derivedTypeSchema_, "hasparent"s,
600a48e4168Speter klausler         IntExpr<1>(dtScope.GetDerivedTypeParent() != nullptr));
601a48e4168Speter klausler     // To avoid wasting run time attempting to initialize derived type
602a48e4168Speter klausler     // instances without any initialized components, analyze the type
603a48e4168Speter klausler     // and set a flag if there's nothing to do for it at run time.
604a48e4168Speter klausler     AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s,
605a48e4168Speter klausler         IntExpr<1>(
606a48e4168Speter klausler             derivedTypeSpec && !derivedTypeSpec->HasDefaultInitialization()));
607a48e4168Speter klausler     // Similarly, a flag to short-circuit destruction when not needed.
608a48e4168Speter klausler     AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s,
609a48e4168Speter klausler         IntExpr<1>(derivedTypeSpec && !derivedTypeSpec->HasDestruction()));
61065f52904Speter klausler     // Similarly, a flag to short-circuit finalization when not needed.
61165f52904Speter klausler     AddValue(dtValues, derivedTypeSchema_, "nofinalizationneeded"s,
61265f52904Speter klausler         IntExpr<1>(derivedTypeSpec && !IsFinalizable(*derivedTypeSpec)));
6134fede8bcSpeter klausler   }
6144fede8bcSpeter klausler   dtObject.get<ObjectEntityDetails>().set_init(MaybeExpr{
6154fede8bcSpeter klausler       StructureExpr(Structure(derivedTypeSchema_, std::move(dtValues)))});
6164fede8bcSpeter klausler   return &dtObject;
6174fede8bcSpeter klausler }
6184fede8bcSpeter klausler 
GetSymbol(const Scope & schemata,SourceName name)6194fede8bcSpeter klausler static const Symbol &GetSymbol(const Scope &schemata, SourceName name) {
6204fede8bcSpeter klausler   auto iter{schemata.find(name)};
6214fede8bcSpeter klausler   CHECK(iter != schemata.end());
6224fede8bcSpeter klausler   const Symbol &symbol{*iter->second};
6234fede8bcSpeter klausler   return symbol;
6244fede8bcSpeter klausler }
6254fede8bcSpeter klausler 
GetSchemaSymbol(const char * name) const6264fede8bcSpeter klausler const Symbol &RuntimeTableBuilder::GetSchemaSymbol(const char *name) const {
6274fede8bcSpeter klausler   return GetSymbol(
6284fede8bcSpeter klausler       DEREF(tables_.schemata), SourceName{name, std::strlen(name)});
6294fede8bcSpeter klausler }
6304fede8bcSpeter klausler 
GetSchema(const char * schemaName) const6314fede8bcSpeter klausler const DeclTypeSpec &RuntimeTableBuilder::GetSchema(
6324fede8bcSpeter klausler     const char *schemaName) const {
6334fede8bcSpeter klausler   Scope &schemata{DEREF(tables_.schemata)};
6344fede8bcSpeter klausler   SourceName name{schemaName, std::strlen(schemaName)};
6354fede8bcSpeter klausler   const Symbol &symbol{GetSymbol(schemata, name)};
6364fede8bcSpeter klausler   CHECK(symbol.has<DerivedTypeDetails>());
6374fede8bcSpeter klausler   CHECK(symbol.scope());
6384fede8bcSpeter klausler   CHECK(symbol.scope()->IsDerivedType());
6394fede8bcSpeter klausler   const DeclTypeSpec *spec{nullptr};
6404fede8bcSpeter klausler   if (symbol.scope()->derivedTypeSpec()) {
6414fede8bcSpeter klausler     DeclTypeSpec typeSpec{
6424fede8bcSpeter klausler         DeclTypeSpec::TypeDerived, *symbol.scope()->derivedTypeSpec()};
6434fede8bcSpeter klausler     spec = schemata.FindType(typeSpec);
6444fede8bcSpeter klausler   }
6454fede8bcSpeter klausler   if (!spec) {
6464fede8bcSpeter klausler     DeclTypeSpec typeSpec{
6474fede8bcSpeter klausler         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol}};
6484fede8bcSpeter klausler     spec = schemata.FindType(typeSpec);
6494fede8bcSpeter klausler   }
6504fede8bcSpeter klausler   if (!spec) {
6514fede8bcSpeter klausler     spec = &schemata.MakeDerivedType(
6524fede8bcSpeter klausler         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol});
6534fede8bcSpeter klausler   }
6544fede8bcSpeter klausler   CHECK(spec->AsDerived());
6554fede8bcSpeter klausler   return *spec;
6564fede8bcSpeter klausler }
6574fede8bcSpeter klausler 
GetEnumValue(const char * name) const6584fede8bcSpeter klausler SomeExpr RuntimeTableBuilder::GetEnumValue(const char *name) const {
6594fede8bcSpeter klausler   const Symbol &symbol{GetSchemaSymbol(name)};
6604fede8bcSpeter klausler   auto value{evaluate::ToInt64(symbol.get<ObjectEntityDetails>().init())};
6614fede8bcSpeter klausler   CHECK(value.has_value());
6624fede8bcSpeter klausler   return IntExpr<1>(*value);
6634fede8bcSpeter klausler }
6644fede8bcSpeter klausler 
CreateObject(const std::string & name,const DeclTypeSpec & type,Scope & scope)6654fede8bcSpeter klausler Symbol &RuntimeTableBuilder::CreateObject(
6664fede8bcSpeter klausler     const std::string &name, const DeclTypeSpec &type, Scope &scope) {
6674fede8bcSpeter klausler   ObjectEntityDetails object;
6684fede8bcSpeter klausler   object.set_type(type);
6694fede8bcSpeter klausler   auto pair{scope.try_emplace(SaveObjectName(name),
6704fede8bcSpeter klausler       Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))};
6714fede8bcSpeter klausler   CHECK(pair.second);
6724fede8bcSpeter klausler   Symbol &result{*pair.first->second};
6737dd7ccd2SJean Perier   SetReadOnlyCompilerCreatedFlags(result);
6744fede8bcSpeter klausler   return result;
6754fede8bcSpeter klausler }
6764fede8bcSpeter klausler 
SaveObjectName(const std::string & name)6774fede8bcSpeter klausler SourceName RuntimeTableBuilder::SaveObjectName(const std::string &name) {
6784fede8bcSpeter klausler   return *tables_.names.insert(name).first;
6794fede8bcSpeter klausler }
6804fede8bcSpeter klausler 
SaveNameAsPointerTarget(Scope & scope,const std::string & name)6814fede8bcSpeter klausler SomeExpr RuntimeTableBuilder::SaveNameAsPointerTarget(
6824fede8bcSpeter klausler     Scope &scope, const std::string &name) {
6834fede8bcSpeter klausler   CHECK(!name.empty());
684c14cf92bSPeter Klausler   CHECK(name.front() != '.' || context_.IsTempName(name));
6854fede8bcSpeter klausler   ObjectEntityDetails object;
6864fede8bcSpeter klausler   auto len{static_cast<common::ConstantSubscript>(name.size())};
6874fede8bcSpeter klausler   if (const auto *spec{scope.FindType(DeclTypeSpec{CharacterTypeSpec{
6884fede8bcSpeter klausler           ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}}})}) {
6894fede8bcSpeter klausler     object.set_type(*spec);
6904fede8bcSpeter klausler   } else {
6914fede8bcSpeter klausler     object.set_type(scope.MakeCharacterType(
6924fede8bcSpeter klausler         ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}));
6934fede8bcSpeter klausler   }
6946965a776Speter klausler   using evaluate::Ascii;
6954fede8bcSpeter klausler   using AsciiExpr = evaluate::Expr<Ascii>;
6964fede8bcSpeter klausler   object.set_init(evaluate::AsGenericExpr(AsciiExpr{name}));
697d60a0220Speter klausler   Symbol &symbol{*scope
6984fede8bcSpeter klausler                       .try_emplace(SaveObjectName(".n."s + name),
6994fede8bcSpeter klausler                           Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
7004fede8bcSpeter klausler                       .first->second};
7017dd7ccd2SJean Perier   SetReadOnlyCompilerCreatedFlags(symbol);
7024fede8bcSpeter klausler   return evaluate::AsGenericExpr(
7034fede8bcSpeter klausler       AsciiExpr{evaluate::Designator<Ascii>{symbol}});
7044fede8bcSpeter klausler }
7054fede8bcSpeter klausler 
DescribeComponent(const Symbol & symbol,const ObjectEntityDetails & object,Scope & scope,Scope & dtScope,const std::string & distinctName,const SymbolVector * parameters)7064fede8bcSpeter klausler evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
7074fede8bcSpeter klausler     const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
7081971960aSJean Perier     Scope &dtScope, const std::string &distinctName,
7091971960aSJean Perier     const SymbolVector *parameters) {
7104fede8bcSpeter klausler   evaluate::StructureConstructorValues values;
7118989268dSPeter Steinfeld   auto &foldingContext{context_.foldingContext()};
7124fede8bcSpeter klausler   auto typeAndShape{evaluate::characteristics::TypeAndShape::Characterize(
7138989268dSPeter Steinfeld       symbol, foldingContext)};
7144fede8bcSpeter klausler   CHECK(typeAndShape.has_value());
7154fede8bcSpeter klausler   auto dyType{typeAndShape->type()};
7164fede8bcSpeter klausler   const auto &shape{typeAndShape->shape()};
7174fede8bcSpeter klausler   AddValue(values, componentSchema_, "name"s,
7184fede8bcSpeter klausler       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
7194fede8bcSpeter klausler   AddValue(values, componentSchema_, "category"s,
7204fede8bcSpeter klausler       IntExpr<1>(static_cast<int>(dyType.category())));
7214fede8bcSpeter klausler   if (dyType.IsUnlimitedPolymorphic() ||
7224fede8bcSpeter klausler       dyType.category() == TypeCategory::Derived) {
7234fede8bcSpeter klausler     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(0));
7244fede8bcSpeter klausler   } else {
7254fede8bcSpeter klausler     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(dyType.kind()));
7264fede8bcSpeter klausler   }
7274fede8bcSpeter klausler   AddValue(values, componentSchema_, "offset"s, IntExpr<8>(symbol.offset()));
7284fede8bcSpeter klausler   // CHARACTER length
7298989268dSPeter Steinfeld   auto len{typeAndShape->LEN()};
7301971960aSJean Perier   if (const semantics::DerivedTypeSpec *
7311971960aSJean Perier       pdtInstance{dtScope.derivedTypeSpec()}) {
7328989268dSPeter Steinfeld     auto restorer{foldingContext.WithPDTInstance(*pdtInstance)};
7338989268dSPeter Steinfeld     len = Fold(foldingContext, std::move(len));
7348989268dSPeter Steinfeld   }
7354fede8bcSpeter klausler   if (dyType.category() == TypeCategory::Character && len) {
73678d60094SPeter Klausler     // Ignore IDIM(x) (represented as MAX(0, x))
73778d60094SPeter Klausler     if (const auto *clamped{evaluate::UnwrapExpr<
73878d60094SPeter Klausler             evaluate::Extremum<evaluate::SubscriptInteger>>(*len)}) {
73978d60094SPeter Klausler       if (clamped->ordering == evaluate::Ordering::Greater &&
74078d60094SPeter Klausler           clamped->left() == evaluate::Expr<evaluate::SubscriptInteger>{0}) {
741*0a79113bSPeter Klausler         len = common::Clone(clamped->right());
74278d60094SPeter Klausler       }
74378d60094SPeter Klausler     }
7444fede8bcSpeter klausler     AddValue(values, componentSchema_, "characterlen"s,
7454fede8bcSpeter klausler         evaluate::AsGenericExpr(GetValue(len, parameters)));
7464fede8bcSpeter klausler   } else {
7474fede8bcSpeter klausler     AddValue(values, componentSchema_, "characterlen"s,
7484fede8bcSpeter klausler         PackageIntValueExpr(deferredEnum_));
7494fede8bcSpeter klausler   }
7504fede8bcSpeter klausler   // Describe component's derived type
7514fede8bcSpeter klausler   std::vector<evaluate::StructureConstructor> lenParams;
7524fede8bcSpeter klausler   if (dyType.category() == TypeCategory::Derived &&
7534fede8bcSpeter klausler       !dyType.IsUnlimitedPolymorphic()) {
7544fede8bcSpeter klausler     const DerivedTypeSpec &spec{dyType.GetDerivedTypeSpec()};
7554fede8bcSpeter klausler     Scope *derivedScope{const_cast<Scope *>(
7564fede8bcSpeter klausler         spec.scope() ? spec.scope() : spec.typeSymbol().scope())};
7574fede8bcSpeter klausler     const Symbol *derivedDescription{DescribeType(DEREF(derivedScope))};
7584fede8bcSpeter klausler     AddValue(values, componentSchema_, "derived"s,
7594fede8bcSpeter klausler         evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
7604fede8bcSpeter klausler             evaluate::Designator<evaluate::SomeDerived>{
7614fede8bcSpeter klausler                 DEREF(derivedDescription)}}));
7624fede8bcSpeter klausler     // Package values of LEN parameters, if any
7634fede8bcSpeter klausler     if (const SymbolVector * specParams{GetTypeParameters(spec.typeSymbol())}) {
7644fede8bcSpeter klausler       for (SymbolRef ref : *specParams) {
7654fede8bcSpeter klausler         const auto &tpd{ref->get<TypeParamDetails>()};
7664fede8bcSpeter klausler         if (tpd.attr() == common::TypeParamAttr::Len) {
7674fede8bcSpeter klausler           if (const ParamValue * paramValue{spec.FindParameter(ref->name())}) {
7684fede8bcSpeter klausler             lenParams.emplace_back(GetValue(*paramValue, parameters));
7694fede8bcSpeter klausler           } else {
7704fede8bcSpeter klausler             lenParams.emplace_back(GetValue(tpd.init(), parameters));
7714fede8bcSpeter klausler           }
7724fede8bcSpeter klausler         }
7734fede8bcSpeter klausler       }
7744fede8bcSpeter klausler     }
7754fede8bcSpeter klausler   } else {
7764fede8bcSpeter klausler     // Subtle: a category of Derived with a null derived type pointer
7774fede8bcSpeter klausler     // signifies CLASS(*)
7784fede8bcSpeter klausler     AddValue(values, componentSchema_, "derived"s,
7794fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
7804fede8bcSpeter klausler   }
7814fede8bcSpeter klausler   // LEN type parameter values for the component's type
7824fede8bcSpeter klausler   if (!lenParams.empty()) {
7834fede8bcSpeter klausler     AddValue(values, componentSchema_, "lenvalue"s,
7844fede8bcSpeter klausler         SaveDerivedPointerTarget(scope,
7854fede8bcSpeter klausler             SaveObjectName(
7864fede8bcSpeter klausler                 ".lv."s + distinctName + "."s + symbol.name().ToString()),
7874fede8bcSpeter klausler             std::move(lenParams),
7884fede8bcSpeter klausler             evaluate::ConstantSubscripts{
7894fede8bcSpeter klausler                 static_cast<evaluate::ConstantSubscript>(lenParams.size())}));
7904fede8bcSpeter klausler   } else {
7914fede8bcSpeter klausler     AddValue(values, componentSchema_, "lenvalue"s,
7924fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
7934fede8bcSpeter klausler   }
7944fede8bcSpeter klausler   // Shape information
7954fede8bcSpeter klausler   int rank{evaluate::GetRank(shape)};
7964fede8bcSpeter klausler   AddValue(values, componentSchema_, "rank"s, IntExpr<1>(rank));
797803f1e46Speter klausler   if (rank > 0 && !IsAllocatable(symbol) && !IsPointer(symbol)) {
7984fede8bcSpeter klausler     std::vector<evaluate::StructureConstructor> bounds;
7994fede8bcSpeter klausler     evaluate::NamedEntity entity{symbol};
8004fede8bcSpeter klausler     for (int j{0}; j < rank; ++j) {
8013b61587cSPeter Klausler       bounds.emplace_back(
8023b61587cSPeter Klausler           GetValue(std::make_optional(
8033b61587cSPeter Klausler                        evaluate::GetRawLowerBound(foldingContext, entity, j)),
8044fede8bcSpeter klausler               parameters));
8054fede8bcSpeter klausler       bounds.emplace_back(GetValue(
806ca46521aSJean Perier           evaluate::GetRawUpperBound(foldingContext, entity, j), parameters));
8074fede8bcSpeter klausler     }
8084fede8bcSpeter klausler     AddValue(values, componentSchema_, "bounds"s,
8094fede8bcSpeter klausler         SaveDerivedPointerTarget(scope,
8104fede8bcSpeter klausler             SaveObjectName(
8114fede8bcSpeter klausler                 ".b."s + distinctName + "."s + symbol.name().ToString()),
8124fede8bcSpeter klausler             std::move(bounds), evaluate::ConstantSubscripts{2, rank}));
8134fede8bcSpeter klausler   } else {
8144fede8bcSpeter klausler     AddValue(
8154fede8bcSpeter klausler         values, componentSchema_, "bounds"s, SomeExpr{evaluate::NullPointer{}});
8164fede8bcSpeter klausler   }
8174fede8bcSpeter klausler   // Default component initialization
8184fede8bcSpeter klausler   bool hasDataInit{false};
8194fede8bcSpeter klausler   if (IsAllocatable(symbol)) {
8204fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("allocatable"));
8214fede8bcSpeter klausler   } else if (IsPointer(symbol)) {
8224fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("pointer"));
823a48e4168Speter klausler     hasDataInit = InitializeDataPointer(
824a48e4168Speter klausler         values, symbol, object, scope, dtScope, distinctName);
825996ef895SPeter Klausler   } else if (IsAutomatic(symbol)) {
8264fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("automatic"));
8274fede8bcSpeter klausler   } else {
8284fede8bcSpeter klausler     AddValue(values, componentSchema_, "genre"s, GetEnumValue("data"));
8294fede8bcSpeter klausler     hasDataInit = object.init().has_value();
8304fede8bcSpeter klausler     if (hasDataInit) {
8314fede8bcSpeter klausler       AddValue(values, componentSchema_, "initialization"s,
8324fede8bcSpeter klausler           SaveObjectInit(scope,
8334fede8bcSpeter klausler               SaveObjectName(
8344fede8bcSpeter klausler                   ".di."s + distinctName + "."s + symbol.name().ToString()),
8354fede8bcSpeter klausler               object));
8364fede8bcSpeter klausler     }
8374fede8bcSpeter klausler   }
8384fede8bcSpeter klausler   if (!hasDataInit) {
8394fede8bcSpeter klausler     AddValue(values, componentSchema_, "initialization"s,
8404fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
8414fede8bcSpeter klausler   }
8424fede8bcSpeter klausler   return {DEREF(componentSchema_.AsDerived()), std::move(values)};
8434fede8bcSpeter klausler }
8444fede8bcSpeter klausler 
DescribeComponent(const Symbol & symbol,const ProcEntityDetails & proc,Scope & scope)8454fede8bcSpeter klausler evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
8464fede8bcSpeter klausler     const Symbol &symbol, const ProcEntityDetails &proc, Scope &scope) {
8474fede8bcSpeter klausler   evaluate::StructureConstructorValues values;
8484fede8bcSpeter klausler   AddValue(values, procPtrSchema_, "name"s,
8494fede8bcSpeter klausler       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
8504fede8bcSpeter klausler   AddValue(values, procPtrSchema_, "offset"s, IntExpr<8>(symbol.offset()));
8514fede8bcSpeter klausler   if (auto init{proc.init()}; init && *init) {
8524fede8bcSpeter klausler     AddValue(values, procPtrSchema_, "initialization"s,
8534fede8bcSpeter klausler         SomeExpr{evaluate::ProcedureDesignator{**init}});
8544fede8bcSpeter klausler   } else {
8554fede8bcSpeter klausler     AddValue(values, procPtrSchema_, "initialization"s,
8564fede8bcSpeter klausler         SomeExpr{evaluate::NullPointer{}});
8574fede8bcSpeter klausler   }
8584fede8bcSpeter klausler   return {DEREF(procPtrSchema_.AsDerived()), std::move(values)};
8594fede8bcSpeter klausler }
8604fede8bcSpeter klausler 
861a48e4168Speter klausler // Create a static pointer object with the same initialization
862a48e4168Speter klausler // from whence the runtime can memcpy() the data pointer
863a48e4168Speter klausler // component initialization.
864a48e4168Speter klausler // Creates and interconnects the symbols, scopes, and types for
865a48e4168Speter klausler //   TYPE :: ptrDt
866a48e4168Speter klausler //     type, POINTER :: name
867a48e4168Speter klausler //   END TYPE
868a48e4168Speter klausler //   TYPE(ptrDt), TARGET, SAVE :: ptrInit = ptrDt(designator)
869a48e4168Speter klausler // and then initializes the original component by setting
870a48e4168Speter klausler //   initialization = ptrInit
871a48e4168Speter klausler // which takes the address of ptrInit because the type is C_PTR.
872a48e4168Speter klausler // This technique of wrapping the data pointer component into
873a48e4168Speter klausler // a derived type instance disables any reason for lowering to
874a48e4168Speter klausler // attempt to dereference the RHS of an initializer, thereby
875a48e4168Speter klausler // allowing the runtime to actually perform the initialization
876a48e4168Speter klausler // by means of a simple memcpy() of the wrapped descriptor in
877a48e4168Speter klausler // ptrInit to the data pointer component being initialized.
InitializeDataPointer(evaluate::StructureConstructorValues & values,const Symbol & symbol,const ObjectEntityDetails & object,Scope & scope,Scope & dtScope,const std::string & distinctName)878a48e4168Speter klausler bool RuntimeTableBuilder::InitializeDataPointer(
879a48e4168Speter klausler     evaluate::StructureConstructorValues &values, const Symbol &symbol,
880a48e4168Speter klausler     const ObjectEntityDetails &object, Scope &scope, Scope &dtScope,
881a48e4168Speter klausler     const std::string &distinctName) {
882a48e4168Speter klausler   if (object.init().has_value()) {
883a48e4168Speter klausler     SourceName ptrDtName{SaveObjectName(
884a48e4168Speter klausler         ".dp."s + distinctName + "."s + symbol.name().ToString())};
885a48e4168Speter klausler     Symbol &ptrDtSym{
886a48e4168Speter klausler         *scope.try_emplace(ptrDtName, Attrs{}, UnknownDetails{}).first->second};
8877dd7ccd2SJean Perier     SetReadOnlyCompilerCreatedFlags(ptrDtSym);
888a48e4168Speter klausler     Scope &ptrDtScope{scope.MakeScope(Scope::Kind::DerivedType, &ptrDtSym)};
889a48e4168Speter klausler     ignoreScopes_.insert(&ptrDtScope);
890a48e4168Speter klausler     ObjectEntityDetails ptrDtObj;
891a48e4168Speter klausler     ptrDtObj.set_type(DEREF(object.type()));
892a48e4168Speter klausler     ptrDtObj.set_shape(object.shape());
893a48e4168Speter klausler     Symbol &ptrDtComp{*ptrDtScope
894a48e4168Speter klausler                            .try_emplace(symbol.name(), Attrs{Attr::POINTER},
895a48e4168Speter klausler                                std::move(ptrDtObj))
896a48e4168Speter klausler                            .first->second};
897a48e4168Speter klausler     DerivedTypeDetails ptrDtDetails;
898a48e4168Speter klausler     ptrDtDetails.add_component(ptrDtComp);
899a48e4168Speter klausler     ptrDtSym.set_details(std::move(ptrDtDetails));
900a48e4168Speter klausler     ptrDtSym.set_scope(&ptrDtScope);
901a48e4168Speter klausler     DeclTypeSpec &ptrDtDeclType{
902a48e4168Speter klausler         scope.MakeDerivedType(DeclTypeSpec::Category::TypeDerived,
903a48e4168Speter klausler             DerivedTypeSpec{ptrDtName, ptrDtSym})};
904a48e4168Speter klausler     DerivedTypeSpec &ptrDtDerived{DEREF(ptrDtDeclType.AsDerived())};
905a48e4168Speter klausler     ptrDtDerived.set_scope(ptrDtScope);
906a48e4168Speter klausler     ptrDtDerived.CookParameters(context_.foldingContext());
907a48e4168Speter klausler     ptrDtDerived.Instantiate(scope);
908a48e4168Speter klausler     ObjectEntityDetails ptrInitObj;
909a48e4168Speter klausler     ptrInitObj.set_type(ptrDtDeclType);
910a48e4168Speter klausler     evaluate::StructureConstructorValues ptrInitValues;
911a48e4168Speter klausler     AddValue(
912a48e4168Speter klausler         ptrInitValues, ptrDtDeclType, symbol.name().ToString(), *object.init());
913a48e4168Speter klausler     ptrInitObj.set_init(evaluate::AsGenericExpr(
914a48e4168Speter klausler         Structure(ptrDtDeclType, std::move(ptrInitValues))));
915a48e4168Speter klausler     AddValue(values, componentSchema_, "initialization"s,
916a48e4168Speter klausler         SaveObjectInit(scope,
917a48e4168Speter klausler             SaveObjectName(
918a48e4168Speter klausler                 ".di."s + distinctName + "."s + symbol.name().ToString()),
919a48e4168Speter klausler             ptrInitObj));
920a48e4168Speter klausler     return true;
921a48e4168Speter klausler   } else {
922a48e4168Speter klausler     return false;
923a48e4168Speter klausler   }
924a48e4168Speter klausler }
925a48e4168Speter klausler 
PackageIntValue(const SomeExpr & genre,std::int64_t n) const9264fede8bcSpeter klausler evaluate::StructureConstructor RuntimeTableBuilder::PackageIntValue(
9274fede8bcSpeter klausler     const SomeExpr &genre, std::int64_t n) const {
9284fede8bcSpeter klausler   evaluate::StructureConstructorValues xs;
9294fede8bcSpeter klausler   AddValue(xs, valueSchema_, "genre"s, genre);
9304fede8bcSpeter klausler   AddValue(xs, valueSchema_, "value"s, IntToExpr(n));
9314fede8bcSpeter klausler   return Structure(valueSchema_, std::move(xs));
9324fede8bcSpeter klausler }
9334fede8bcSpeter klausler 
PackageIntValueExpr(const SomeExpr & genre,std::int64_t n) const9344fede8bcSpeter klausler SomeExpr RuntimeTableBuilder::PackageIntValueExpr(
9354fede8bcSpeter klausler     const SomeExpr &genre, std::int64_t n) const {
9364fede8bcSpeter klausler   return StructureExpr(PackageIntValue(genre, n));
9374fede8bcSpeter klausler }
9384fede8bcSpeter klausler 
CollectBindings(const Scope & dtScope) const9394fede8bcSpeter klausler std::vector<const Symbol *> RuntimeTableBuilder::CollectBindings(
9404fede8bcSpeter klausler     const Scope &dtScope) const {
9414fede8bcSpeter klausler   std::vector<const Symbol *> result;
9424fede8bcSpeter klausler   std::map<SourceName, const Symbol *> localBindings;
9434fede8bcSpeter klausler   // Collect local bindings
9444fede8bcSpeter klausler   for (auto pair : dtScope) {
9454fede8bcSpeter klausler     const Symbol &symbol{*pair.second};
9464fede8bcSpeter klausler     if (symbol.has<ProcBindingDetails>()) {
9474fede8bcSpeter klausler       localBindings.emplace(symbol.name(), &symbol);
9484fede8bcSpeter klausler     }
9494fede8bcSpeter klausler   }
9504fede8bcSpeter klausler   if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) {
9514fede8bcSpeter klausler     result = CollectBindings(*parentScope);
9524fede8bcSpeter klausler     // Apply overrides from the local bindings of the extended type
9534fede8bcSpeter klausler     for (auto iter{result.begin()}; iter != result.end(); ++iter) {
9544fede8bcSpeter klausler       const Symbol &symbol{**iter};
9554fede8bcSpeter klausler       auto overridden{localBindings.find(symbol.name())};
9564fede8bcSpeter klausler       if (overridden != localBindings.end()) {
9574fede8bcSpeter klausler         *iter = overridden->second;
9584fede8bcSpeter klausler         localBindings.erase(overridden);
9594fede8bcSpeter klausler       }
9604fede8bcSpeter klausler     }
9614fede8bcSpeter klausler   }
9624fede8bcSpeter klausler   // Add remaining (non-overriding) local bindings in name order to the result
9634fede8bcSpeter klausler   for (auto pair : localBindings) {
9644fede8bcSpeter klausler     result.push_back(pair.second);
9654fede8bcSpeter klausler   }
9664fede8bcSpeter klausler   return result;
9674fede8bcSpeter klausler }
9684fede8bcSpeter klausler 
9694fede8bcSpeter klausler std::vector<evaluate::StructureConstructor>
DescribeBindings(const Scope & dtScope,Scope & scope)9704fede8bcSpeter klausler RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) {
9714fede8bcSpeter klausler   std::vector<evaluate::StructureConstructor> result;
9724fede8bcSpeter klausler   for (const Symbol *symbol : CollectBindings(dtScope)) {
9734fede8bcSpeter klausler     evaluate::StructureConstructorValues values;
9744fede8bcSpeter klausler     AddValue(values, bindingSchema_, "proc"s,
9754fede8bcSpeter klausler         SomeExpr{evaluate::ProcedureDesignator{
9764fede8bcSpeter klausler             symbol->get<ProcBindingDetails>().symbol()}});
9774fede8bcSpeter klausler     AddValue(values, bindingSchema_, "name"s,
9784fede8bcSpeter klausler         SaveNameAsPointerTarget(scope, symbol->name().ToString()));
9794fede8bcSpeter klausler     result.emplace_back(DEREF(bindingSchema_.AsDerived()), std::move(values));
9804fede8bcSpeter klausler   }
9814fede8bcSpeter klausler   return result;
9824fede8bcSpeter klausler }
9834fede8bcSpeter klausler 
DescribeGeneric(const GenericDetails & generic,std::map<int,evaluate::StructureConstructor> & specials)9844fede8bcSpeter klausler void RuntimeTableBuilder::DescribeGeneric(const GenericDetails &generic,
98565f52904Speter klausler     std::map<int, evaluate::StructureConstructor> &specials) {
986cd03e96fSPeter Klausler   common::visit(common::visitors{
9874fede8bcSpeter klausler                     [&](const GenericKind::OtherKind &k) {
9884fede8bcSpeter klausler                       if (k == GenericKind::OtherKind::Assignment) {
9894fede8bcSpeter klausler                         for (auto ref : generic.specificProcs()) {
9904fede8bcSpeter klausler                           DescribeSpecialProc(specials, *ref, true,
9914fede8bcSpeter klausler                               false /*!final*/, std::nullopt);
9924fede8bcSpeter klausler                         }
9934fede8bcSpeter klausler                       }
9944fede8bcSpeter klausler                     },
9954fede8bcSpeter klausler                     [&](const GenericKind::DefinedIo &io) {
9964fede8bcSpeter klausler                       switch (io) {
9974fede8bcSpeter klausler                       case GenericKind::DefinedIo::ReadFormatted:
9984fede8bcSpeter klausler                       case GenericKind::DefinedIo::ReadUnformatted:
9994fede8bcSpeter klausler                       case GenericKind::DefinedIo::WriteFormatted:
10004fede8bcSpeter klausler                       case GenericKind::DefinedIo::WriteUnformatted:
10014fede8bcSpeter klausler                         for (auto ref : generic.specificProcs()) {
10024fede8bcSpeter klausler                           DescribeSpecialProc(
10034fede8bcSpeter klausler                               specials, *ref, false, false /*!final*/, io);
10044fede8bcSpeter klausler                         }
10054fede8bcSpeter klausler                         break;
10064fede8bcSpeter klausler                       }
10074fede8bcSpeter klausler                     },
10084fede8bcSpeter klausler                     [](const auto &) {},
10094fede8bcSpeter klausler                 },
10104fede8bcSpeter klausler       generic.kind().u);
10114fede8bcSpeter klausler }
10124fede8bcSpeter klausler 
DescribeSpecialProc(std::map<int,evaluate::StructureConstructor> & specials,const Symbol & specificOrBinding,bool isAssignment,bool isFinal,std::optional<GenericKind::DefinedIo> io)10134fede8bcSpeter klausler void RuntimeTableBuilder::DescribeSpecialProc(
101465f52904Speter klausler     std::map<int, evaluate::StructureConstructor> &specials,
10154fede8bcSpeter klausler     const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
10164fede8bcSpeter klausler     std::optional<GenericKind::DefinedIo> io) {
10174fede8bcSpeter klausler   const auto *binding{specificOrBinding.detailsIf<ProcBindingDetails>()};
10184fede8bcSpeter klausler   const Symbol &specific{*(binding ? &binding->symbol() : &specificOrBinding)};
10194fede8bcSpeter klausler   if (auto proc{evaluate::characteristics::Procedure::Characterize(
10204fede8bcSpeter klausler           specific, context_.foldingContext())}) {
10214fede8bcSpeter klausler     std::uint8_t isArgDescriptorSet{0};
10224fede8bcSpeter klausler     int argThatMightBeDescriptor{0};
10234fede8bcSpeter klausler     MaybeExpr which;
1024467525bdSpeter klausler     if (isAssignment) {
1025467525bdSpeter klausler       // Only type-bound asst's with the same type on both dummy arguments
1026467525bdSpeter klausler       // are germane to the runtime, which needs only these to implement
1027467525bdSpeter klausler       // component assignment as part of intrinsic assignment.
1028467525bdSpeter klausler       // Non-type-bound generic INTERFACEs and assignments from distinct
1029467525bdSpeter klausler       // types must not be used for component intrinsic assignment.
10304fede8bcSpeter klausler       CHECK(proc->dummyArguments.size() == 2);
1031467525bdSpeter klausler       const auto t1{
1032467525bdSpeter klausler           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1033467525bdSpeter klausler                     &proc->dummyArguments[0].u))
1034467525bdSpeter klausler               .type.type()};
1035467525bdSpeter klausler       const auto t2{
1036467525bdSpeter klausler           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1037467525bdSpeter klausler                     &proc->dummyArguments[1].u))
1038467525bdSpeter klausler               .type.type()};
1039467525bdSpeter klausler       if (!binding || t1.category() != TypeCategory::Derived ||
1040467525bdSpeter klausler           t2.category() != TypeCategory::Derived ||
1041467525bdSpeter klausler           t1.IsUnlimitedPolymorphic() || t2.IsUnlimitedPolymorphic() ||
1042467525bdSpeter klausler           t1.GetDerivedTypeSpec() != t2.GetDerivedTypeSpec()) {
1043467525bdSpeter klausler         return;
1044467525bdSpeter klausler       }
104565f52904Speter klausler       which = proc->IsElemental() ? elementalAssignmentEnum_
104665f52904Speter klausler                                   : scalarAssignmentEnum_;
10474fede8bcSpeter klausler       if (binding && binding->passName() &&
10484fede8bcSpeter klausler           *binding->passName() == proc->dummyArguments[1].name) {
10494fede8bcSpeter klausler         argThatMightBeDescriptor = 1;
10504fede8bcSpeter klausler         isArgDescriptorSet |= 2;
10514fede8bcSpeter klausler       } else {
10524fede8bcSpeter klausler         argThatMightBeDescriptor = 2; // the non-passed-object argument
10534fede8bcSpeter klausler         isArgDescriptorSet |= 1;
10544fede8bcSpeter klausler       }
10554fede8bcSpeter klausler     } else if (isFinal) {
10564fede8bcSpeter klausler       CHECK(binding == nullptr); // FINALs are not bindings
10574fede8bcSpeter klausler       CHECK(proc->dummyArguments.size() == 1);
10584fede8bcSpeter klausler       if (proc->IsElemental()) {
10594fede8bcSpeter klausler         which = elementalFinalEnum_;
10604fede8bcSpeter klausler       } else {
10614fede8bcSpeter klausler         const auto &typeAndShape{
10624fede8bcSpeter klausler             std::get<evaluate::characteristics::DummyDataObject>(
10634fede8bcSpeter klausler                 proc->dummyArguments.at(0).u)
10644fede8bcSpeter klausler                 .type};
10654fede8bcSpeter klausler         if (typeAndShape.attrs().test(
10664fede8bcSpeter klausler                 evaluate::characteristics::TypeAndShape::Attr::AssumedRank)) {
10674fede8bcSpeter klausler           which = assumedRankFinalEnum_;
10684fede8bcSpeter klausler           isArgDescriptorSet |= 1;
10694fede8bcSpeter klausler         } else {
107065f52904Speter klausler           which = scalarFinalEnum_;
107165f52904Speter klausler           if (int rank{evaluate::GetRank(typeAndShape.shape())}; rank > 0) {
10724fede8bcSpeter klausler             argThatMightBeDescriptor = 1;
107365f52904Speter klausler             which = IntExpr<1>(ToInt64(which).value() + rank);
10744fede8bcSpeter klausler           }
10754fede8bcSpeter klausler         }
10764fede8bcSpeter klausler       }
10774fede8bcSpeter klausler     } else { // user defined derived type I/O
10784fede8bcSpeter klausler       CHECK(proc->dummyArguments.size() >= 4);
10794fede8bcSpeter klausler       if (binding) {
10804fede8bcSpeter klausler         isArgDescriptorSet |= 1;
10814fede8bcSpeter klausler       }
10824fede8bcSpeter klausler       switch (io.value()) {
10834fede8bcSpeter klausler       case GenericKind::DefinedIo::ReadFormatted:
10844fede8bcSpeter klausler         which = readFormattedEnum_;
10854fede8bcSpeter klausler         break;
10864fede8bcSpeter klausler       case GenericKind::DefinedIo::ReadUnformatted:
10874fede8bcSpeter klausler         which = readUnformattedEnum_;
10884fede8bcSpeter klausler         break;
10894fede8bcSpeter klausler       case GenericKind::DefinedIo::WriteFormatted:
10904fede8bcSpeter klausler         which = writeFormattedEnum_;
10914fede8bcSpeter klausler         break;
10924fede8bcSpeter klausler       case GenericKind::DefinedIo::WriteUnformatted:
10934fede8bcSpeter klausler         which = writeUnformattedEnum_;
10944fede8bcSpeter klausler         break;
10954fede8bcSpeter klausler       }
10964fede8bcSpeter klausler     }
10974fede8bcSpeter klausler     if (argThatMightBeDescriptor != 0 &&
10984fede8bcSpeter klausler         !proc->dummyArguments.at(argThatMightBeDescriptor - 1)
10994fede8bcSpeter klausler              .CanBePassedViaImplicitInterface()) {
11004fede8bcSpeter klausler       isArgDescriptorSet |= 1 << (argThatMightBeDescriptor - 1);
11014fede8bcSpeter klausler     }
11024fede8bcSpeter klausler     evaluate::StructureConstructorValues values;
110365f52904Speter klausler     auto index{evaluate::ToInt64(which)};
110465f52904Speter klausler     CHECK(index.has_value());
11054fede8bcSpeter klausler     AddValue(
11064fede8bcSpeter klausler         values, specialSchema_, "which"s, SomeExpr{std::move(which.value())});
11074fede8bcSpeter klausler     AddValue(values, specialSchema_, "isargdescriptorset"s,
11084fede8bcSpeter klausler         IntExpr<1>(isArgDescriptorSet));
11094fede8bcSpeter klausler     AddValue(values, specialSchema_, "proc"s,
11104fede8bcSpeter klausler         SomeExpr{evaluate::ProcedureDesignator{specific}});
111165f52904Speter klausler     auto pair{specials.try_emplace(
111265f52904Speter klausler         *index, DEREF(specialSchema_.AsDerived()), std::move(values))};
111365f52904Speter klausler     CHECK(pair.second); // ensure not already present
11144fede8bcSpeter klausler   }
11154fede8bcSpeter klausler }
11164fede8bcSpeter klausler 
IncorporateDefinedIoGenericInterfaces(std::map<int,evaluate::StructureConstructor> & specials,GenericKind::DefinedIo definedIo,const Scope * scope)11174fede8bcSpeter klausler void RuntimeTableBuilder::IncorporateDefinedIoGenericInterfaces(
111819d86426SPeter Klausler     std::map<int, evaluate::StructureConstructor> &specials,
11194fede8bcSpeter klausler     GenericKind::DefinedIo definedIo, const Scope *scope) {
112019d86426SPeter Klausler   SourceName name{GenericKind::AsFortran(definedIo)};
11214fede8bcSpeter klausler   for (; !scope->IsGlobal(); scope = &scope->parent()) {
11224fede8bcSpeter klausler     if (auto asst{scope->find(name)}; asst != scope->end()) {
11233726626aSPeter Klausler       const Symbol &generic{asst->second->GetUltimate()};
11244fede8bcSpeter klausler       const auto &genericDetails{generic.get<GenericDetails>()};
11254fede8bcSpeter klausler       CHECK(std::holds_alternative<GenericKind::DefinedIo>(
11264fede8bcSpeter klausler           genericDetails.kind().u));
11274fede8bcSpeter klausler       CHECK(std::get<GenericKind::DefinedIo>(genericDetails.kind().u) ==
11284fede8bcSpeter klausler           definedIo);
11294fede8bcSpeter klausler       for (auto ref : genericDetails.specificProcs()) {
11304fede8bcSpeter klausler         DescribeSpecialProc(specials, *ref, false, false, definedIo);
11314fede8bcSpeter klausler       }
11324fede8bcSpeter klausler     }
11334fede8bcSpeter klausler   }
11344fede8bcSpeter klausler }
11354fede8bcSpeter klausler 
BuildRuntimeDerivedTypeTables(SemanticsContext & context)11364fede8bcSpeter klausler RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(
11374fede8bcSpeter klausler     SemanticsContext &context) {
11384fede8bcSpeter klausler   RuntimeDerivedTypeTables result;
11397dd7ccd2SJean Perier   result.schemata = context.GetBuiltinModule(typeInfoBuiltinModule);
11404fede8bcSpeter klausler   if (result.schemata) {
11414fede8bcSpeter klausler     RuntimeTableBuilder builder{context, result};
1142a48e4168Speter klausler     builder.DescribeTypes(context.globalScope(), false);
11434fede8bcSpeter klausler   }
11444fede8bcSpeter klausler   return result;
11454fede8bcSpeter klausler }
11464fede8bcSpeter klausler } // namespace Fortran::semantics
1147