xref: /llvm-project/flang/lib/Semantics/runtime-type-info.cpp (revision 050f785e2c57ce4ad4d788660c898b985a25ffe7)
1 //===-- lib/Semantics/runtime-type-info.cpp ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Semantics/runtime-type-info.h"
10 #include "mod-file.h"
11 #include "flang/Evaluate/fold-designator.h"
12 #include "flang/Evaluate/fold.h"
13 #include "flang/Evaluate/tools.h"
14 #include "flang/Evaluate/type.h"
15 #include "flang/Optimizer/Support/InternalNames.h"
16 #include "flang/Semantics/scope.h"
17 #include "flang/Semantics/tools.h"
18 #include <functional>
19 #include <list>
20 #include <map>
21 #include <string>
22 
23 // The symbols added by this code to various scopes in the program include:
24 //   .b.TYPE.NAME  - Bounds values for an array component
25 //   .c.TYPE       - TYPE(Component) descriptions for TYPE
26 //   .di.TYPE.NAME - Data initialization for a component
27 //   .dp.TYPE.NAME - Data pointer initialization for a component
28 //   .dt.TYPE      - TYPE(DerivedType) description for TYPE
29 //   .kp.TYPE      - KIND type parameter values for TYPE
30 //   .lpk.TYPE     - Integer kinds of LEN type parameter values
31 //   .lv.TYPE.NAME - LEN type parameter values for a component's type
32 //   .n.NAME       - Character representation of a name
33 //   .p.TYPE       - TYPE(ProcPtrComponent) descriptions for TYPE
34 //   .s.TYPE       - TYPE(SpecialBinding) bindings for TYPE
35 //   .v.TYPE       - TYPE(Binding) bindings for TYPE
36 
37 namespace Fortran::semantics {
38 
39 static int FindLenParameterIndex(
40     const SymbolVector &parameters, const Symbol &symbol) {
41   int lenIndex{0};
42   for (SymbolRef ref : parameters) {
43     if (&*ref == &symbol) {
44       return lenIndex;
45     }
46     if (auto attr{ref->get<TypeParamDetails>().attr()};
47         attr && *attr == common::TypeParamAttr::Len) {
48       ++lenIndex;
49     }
50   }
51   DIE("Length type parameter not found in parameter order");
52   return -1;
53 }
54 
55 class RuntimeTableBuilder {
56 public:
57   RuntimeTableBuilder(SemanticsContext &, RuntimeDerivedTypeTables &);
58   void DescribeTypes(Scope &scope, bool inSchemata);
59 
60 private:
61   const Symbol *DescribeType(Scope &);
62   const Symbol &GetSchemaSymbol(const char *) const;
63   const DeclTypeSpec &GetSchema(const char *) const;
64   SomeExpr GetEnumValue(const char *) const;
65   Symbol &CreateObject(const std::string &, const DeclTypeSpec &, Scope &);
66   // The names of created symbols are saved in and owned by the
67   // RuntimeDerivedTypeTables instance returned by
68   // BuildRuntimeDerivedTypeTables() so that references to those names remain
69   // valid for lowering.
70   SourceName SaveObjectName(const std::string &);
71   SomeExpr SaveNameAsPointerTarget(Scope &, const std::string &);
72   const SymbolVector *GetTypeParameters(const Symbol &);
73   evaluate::StructureConstructor DescribeComponent(const Symbol &,
74       const ObjectEntityDetails &, Scope &, Scope &,
75       const std::string &distinctName, const SymbolVector *parameters);
76   evaluate::StructureConstructor DescribeComponent(
77       const Symbol &, const ProcEntityDetails &, Scope &);
78   bool InitializeDataPointer(evaluate::StructureConstructorValues &,
79       const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
80       Scope &dtScope, const std::string &distinctName);
81   evaluate::StructureConstructor PackageIntValue(
82       const SomeExpr &genre, std::int64_t = 0) const;
83   SomeExpr PackageIntValueExpr(const SomeExpr &genre, std::int64_t = 0) const;
84   std::vector<evaluate::StructureConstructor> DescribeBindings(
85       const Scope &dtScope, Scope &);
86   std::map<int, evaluate::StructureConstructor> DescribeSpecialGenerics(
87       const Scope &dtScope, const Scope &thisScope,
88       const DerivedTypeSpec *) const;
89   void DescribeSpecialGeneric(const GenericDetails &,
90       std::map<int, evaluate::StructureConstructor> &, const Scope &,
91       const DerivedTypeSpec *) const;
92   void DescribeSpecialProc(std::map<int, evaluate::StructureConstructor> &,
93       const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
94       std::optional<common::DefinedIo>, const Scope *, const DerivedTypeSpec *,
95       bool isTypeBound) const;
96   void IncorporateDefinedIoGenericInterfaces(
97       std::map<int, evaluate::StructureConstructor> &, common::DefinedIo,
98       const Scope *, const DerivedTypeSpec *);
99 
100   // Instantiated for ParamValue and Bound
101   template <typename A>
102   evaluate::StructureConstructor GetValue(
103       const A &x, const SymbolVector *parameters) {
104     if (x.isExplicit()) {
105       return GetValue(x.GetExplicit(), parameters);
106     } else {
107       return PackageIntValue(deferredEnum_);
108     }
109   }
110 
111   // Specialization for optional<Expr<SomeInteger and SubscriptInteger>>
112   template <typename T>
113   evaluate::StructureConstructor GetValue(
114       const std::optional<evaluate::Expr<T>> &expr,
115       const SymbolVector *parameters) {
116     if (auto constValue{evaluate::ToInt64(expr)}) {
117       return PackageIntValue(explicitEnum_, *constValue);
118     }
119     if (expr) {
120       if (parameters) {
121         if (const Symbol * lenParam{evaluate::ExtractBareLenParameter(*expr)}) {
122           return PackageIntValue(
123               lenParameterEnum_, FindLenParameterIndex(*parameters, *lenParam));
124         }
125       }
126       // TODO: Replace a specification expression requiring actual operations
127       // with a reference to a new anonymous LEN type parameter whose default
128       // value captures the expression.  This replacement must take place when
129       // the type is declared so that the new LEN type parameters appear in
130       // all instantiations and structure constructors.
131       context_.Say(location_,
132           "derived type specification expression '%s' that is neither constant nor a length type parameter"_todo_en_US,
133           expr->AsFortran());
134     }
135     return PackageIntValue(deferredEnum_);
136   }
137 
138   SemanticsContext &context_;
139   RuntimeDerivedTypeTables &tables_;
140   std::map<const Symbol *, SymbolVector> orderedTypeParameters_;
141 
142   const DeclTypeSpec &derivedTypeSchema_; // TYPE(DerivedType)
143   const DeclTypeSpec &componentSchema_; // TYPE(Component)
144   const DeclTypeSpec &procPtrSchema_; // TYPE(ProcPtrComponent)
145   const DeclTypeSpec &valueSchema_; // TYPE(Value)
146   const DeclTypeSpec &bindingSchema_; // TYPE(Binding)
147   const DeclTypeSpec &specialSchema_; // TYPE(SpecialBinding)
148   SomeExpr deferredEnum_; // Value::Genre::Deferred
149   SomeExpr explicitEnum_; // Value::Genre::Explicit
150   SomeExpr lenParameterEnum_; // Value::Genre::LenParameter
151   SomeExpr scalarAssignmentEnum_; // SpecialBinding::Which::ScalarAssignment
152   SomeExpr
153       elementalAssignmentEnum_; // SpecialBinding::Which::ElementalAssignment
154   SomeExpr readFormattedEnum_; // SpecialBinding::Which::ReadFormatted
155   SomeExpr readUnformattedEnum_; // SpecialBinding::Which::ReadUnformatted
156   SomeExpr writeFormattedEnum_; // SpecialBinding::Which::WriteFormatted
157   SomeExpr writeUnformattedEnum_; // SpecialBinding::Which::WriteUnformatted
158   SomeExpr elementalFinalEnum_; // SpecialBinding::Which::ElementalFinal
159   SomeExpr assumedRankFinalEnum_; // SpecialBinding::Which::AssumedRankFinal
160   SomeExpr scalarFinalEnum_; // SpecialBinding::Which::ScalarFinal
161   parser::CharBlock location_;
162   std::set<const Scope *> ignoreScopes_;
163 };
164 
165 RuntimeTableBuilder::RuntimeTableBuilder(
166     SemanticsContext &c, RuntimeDerivedTypeTables &t)
167     : context_{c}, tables_{t}, derivedTypeSchema_{GetSchema("derivedtype")},
168       componentSchema_{GetSchema("component")},
169       procPtrSchema_{GetSchema("procptrcomponent")},
170       valueSchema_{GetSchema("value")},
171       bindingSchema_{GetSchema(bindingDescCompName)},
172       specialSchema_{GetSchema("specialbinding")},
173       deferredEnum_{GetEnumValue("deferred")},
174       explicitEnum_{GetEnumValue("explicit")},
175       lenParameterEnum_{GetEnumValue("lenparameter")},
176       scalarAssignmentEnum_{GetEnumValue("scalarassignment")},
177       elementalAssignmentEnum_{GetEnumValue("elementalassignment")},
178       readFormattedEnum_{GetEnumValue("readformatted")},
179       readUnformattedEnum_{GetEnumValue("readunformatted")},
180       writeFormattedEnum_{GetEnumValue("writeformatted")},
181       writeUnformattedEnum_{GetEnumValue("writeunformatted")},
182       elementalFinalEnum_{GetEnumValue("elementalfinal")},
183       assumedRankFinalEnum_{GetEnumValue("assumedrankfinal")},
184       scalarFinalEnum_{GetEnumValue("scalarfinal")} {
185   ignoreScopes_.insert(tables_.schemata);
186 }
187 
188 static void SetReadOnlyCompilerCreatedFlags(Symbol &symbol) {
189   symbol.set(Symbol::Flag::CompilerCreated);
190   // Runtime type info symbols may have types that are incompatible with the
191   // PARAMETER attribute (the main issue is that they may be TARGET, and normal
192   // Fortran parameters cannot be TARGETs).
193   if (symbol.has<semantics::ObjectEntityDetails>() ||
194       symbol.has<semantics::ProcEntityDetails>()) {
195     symbol.set(Symbol::Flag::ReadOnly);
196   }
197 }
198 
199 // Save an arbitrarily shaped array constant of some derived type
200 // as an initialized data object in a scope.
201 static SomeExpr SaveDerivedPointerTarget(Scope &scope, SourceName name,
202     std::vector<evaluate::StructureConstructor> &&x,
203     evaluate::ConstantSubscripts &&shape) {
204   if (x.empty()) {
205     return SomeExpr{evaluate::NullPointer{}};
206   } else {
207     auto dyType{x.front().GetType()};
208     const auto &derivedType{dyType.GetDerivedTypeSpec()};
209     ObjectEntityDetails object;
210     DeclTypeSpec typeSpec{DeclTypeSpec::TypeDerived, derivedType};
211     if (const DeclTypeSpec * spec{scope.FindType(typeSpec)}) {
212       object.set_type(*spec);
213     } else {
214       object.set_type(scope.MakeDerivedType(
215           DeclTypeSpec::TypeDerived, common::Clone(derivedType)));
216     }
217     if (!shape.empty()) {
218       ArraySpec arraySpec;
219       for (auto n : shape) {
220         arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{n - 1}));
221       }
222       object.set_shape(arraySpec);
223     }
224     object.set_init(
225         evaluate::AsGenericExpr(evaluate::Constant<evaluate::SomeDerived>{
226             derivedType, std::move(x), std::move(shape)}));
227     Symbol &symbol{*scope
228                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
229                             std::move(object))
230                         .first->second};
231     SetReadOnlyCompilerCreatedFlags(symbol);
232     return evaluate::AsGenericExpr(
233         evaluate::Designator<evaluate::SomeDerived>{symbol});
234   }
235 }
236 
237 void RuntimeTableBuilder::DescribeTypes(Scope &scope, bool inSchemata) {
238   inSchemata |= ignoreScopes_.find(&scope) != ignoreScopes_.end();
239   if (scope.IsDerivedType()) {
240     if (!inSchemata) { // don't loop trying to describe a schema
241       DescribeType(scope);
242     }
243   } else {
244     scope.InstantiateDerivedTypes();
245   }
246   for (Scope &child : scope.children()) {
247     DescribeTypes(child, inSchemata);
248   }
249 }
250 
251 // Returns derived type instantiation's parameters in declaration order
252 const SymbolVector *RuntimeTableBuilder::GetTypeParameters(
253     const Symbol &symbol) {
254   auto iter{orderedTypeParameters_.find(&symbol)};
255   if (iter != orderedTypeParameters_.end()) {
256     return &iter->second;
257   } else {
258     return &orderedTypeParameters_
259                 .emplace(&symbol, OrderParameterDeclarations(symbol))
260                 .first->second;
261   }
262 }
263 
264 static Scope &GetContainingNonDerivedScope(Scope &scope) {
265   Scope *p{&scope};
266   while (p->IsDerivedType()) {
267     p = &p->parent();
268   }
269   return *p;
270 }
271 
272 static const Symbol &GetSchemaField(
273     const DerivedTypeSpec &derived, const std::string &name) {
274   const Scope &scope{
275       DEREF(derived.scope() ? derived.scope() : derived.typeSymbol().scope())};
276   auto iter{scope.find(SourceName(name))};
277   CHECK(iter != scope.end());
278   return *iter->second;
279 }
280 
281 static const Symbol &GetSchemaField(
282     const DeclTypeSpec &derived, const std::string &name) {
283   return GetSchemaField(DEREF(derived.AsDerived()), name);
284 }
285 
286 static evaluate::StructureConstructorValues &AddValue(
287     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
288     const std::string &name, SomeExpr &&x) {
289   values.emplace(GetSchemaField(spec, name), std::move(x));
290   return values;
291 }
292 
293 static evaluate::StructureConstructorValues &AddValue(
294     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
295     const std::string &name, const SomeExpr &x) {
296   values.emplace(GetSchemaField(spec, name), x);
297   return values;
298 }
299 
300 static SomeExpr IntToExpr(std::int64_t n) {
301   return evaluate::AsGenericExpr(evaluate::ExtentExpr{n});
302 }
303 
304 static evaluate::StructureConstructor Structure(
305     const DeclTypeSpec &spec, evaluate::StructureConstructorValues &&values) {
306   return {DEREF(spec.AsDerived()), std::move(values)};
307 }
308 
309 static SomeExpr StructureExpr(evaluate::StructureConstructor &&x) {
310   return SomeExpr{evaluate::Expr<evaluate::SomeDerived>{std::move(x)}};
311 }
312 
313 static int GetIntegerKind(const Symbol &symbol) {
314   auto dyType{evaluate::DynamicType::From(symbol)};
315   CHECK((dyType && dyType->category() == TypeCategory::Integer) ||
316       symbol.owner().context().HasError(symbol));
317   return dyType && dyType->category() == TypeCategory::Integer
318       ? dyType->kind()
319       : symbol.owner().context().GetDefaultKind(TypeCategory::Integer);
320 }
321 
322 // Save a rank-1 array constant of some numeric type as an
323 // initialized data object in a scope.
324 template <typename T>
325 static SomeExpr SaveNumericPointerTarget(
326     Scope &scope, SourceName name, std::vector<typename T::Scalar> &&x) {
327   if (x.empty()) {
328     return SomeExpr{evaluate::NullPointer{}};
329   } else {
330     ObjectEntityDetails object;
331     if (const auto *spec{scope.FindType(
332             DeclTypeSpec{NumericTypeSpec{T::category, KindExpr{T::kind}}})}) {
333       object.set_type(*spec);
334     } else {
335       object.set_type(scope.MakeNumericType(T::category, KindExpr{T::kind}));
336     }
337     auto elements{static_cast<evaluate::ConstantSubscript>(x.size())};
338     ArraySpec arraySpec;
339     arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{elements - 1}));
340     object.set_shape(arraySpec);
341     object.set_init(evaluate::AsGenericExpr(evaluate::Constant<T>{
342         std::move(x), evaluate::ConstantSubscripts{elements}}));
343     Symbol &symbol{*scope
344                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
345                             std::move(object))
346                         .first->second};
347     SetReadOnlyCompilerCreatedFlags(symbol);
348     return evaluate::AsGenericExpr(
349         evaluate::Expr<T>{evaluate::Designator<T>{symbol}});
350   }
351 }
352 
353 static SomeExpr SaveObjectInit(
354     Scope &scope, SourceName name, const ObjectEntityDetails &object) {
355   Symbol &symbol{*scope
356                       .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
357                           ObjectEntityDetails{object})
358                       .first->second};
359   CHECK(symbol.get<ObjectEntityDetails>().init().has_value());
360   SetReadOnlyCompilerCreatedFlags(symbol);
361   return evaluate::AsGenericExpr(
362       evaluate::Designator<evaluate::SomeDerived>{symbol});
363 }
364 
365 template <int KIND> static SomeExpr IntExpr(std::int64_t n) {
366   return evaluate::AsGenericExpr(
367       evaluate::Constant<evaluate::Type<TypeCategory::Integer, KIND>>{n});
368 }
369 
370 static std::optional<std::string> GetSuffixIfTypeKindParameters(
371     const DerivedTypeSpec &derivedTypeSpec, const SymbolVector *parameters) {
372   if (parameters) {
373     std::optional<std::string> suffix;
374     for (SymbolRef ref : *parameters) {
375       const auto &tpd{ref->get<TypeParamDetails>()};
376       if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Kind) {
377         if (const auto *pv{derivedTypeSpec.FindParameter(ref->name())}) {
378           if (pv->GetExplicit()) {
379             if (auto instantiatedValue{evaluate::ToInt64(*pv->GetExplicit())}) {
380               if (suffix.has_value()) {
381                 *suffix +=
382                     (fir::kNameSeparator + llvm::Twine(*instantiatedValue))
383                         .str();
384               } else {
385                 suffix = (fir::kNameSeparator + llvm::Twine(*instantiatedValue))
386                              .str();
387               }
388             }
389           }
390         }
391       }
392     }
393     return suffix;
394   }
395   return std::nullopt;
396 }
397 
398 const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
399   if (const Symbol * info{dtScope.runtimeDerivedTypeDescription()}) {
400     return info;
401   }
402   const DerivedTypeSpec *derivedTypeSpec{dtScope.derivedTypeSpec()};
403   if (!derivedTypeSpec && !dtScope.IsDerivedTypeWithKindParameter() &&
404       dtScope.symbol()) {
405     // This derived type was declared (obviously, there's a Scope) but never
406     // used in this compilation (no instantiated DerivedTypeSpec points here).
407     // Create a DerivedTypeSpec now for it so that ComponentIterator
408     // will work. This covers the case of a derived type that's declared in
409     // a module but used only by clients and submodules, enabling the
410     // run-time "no initialization needed here" flag to work.
411     DerivedTypeSpec derived{dtScope.symbol()->name(), *dtScope.symbol()};
412     if (const SymbolVector *
413         lenParameters{GetTypeParameters(*dtScope.symbol())}) {
414       // Create dummy deferred values for the length parameters so that the
415       // DerivedTypeSpec is complete and can be used in helpers.
416       for (SymbolRef lenParam : *lenParameters) {
417         (void)lenParam;
418         derived.AddRawParamValue(
419             nullptr, ParamValue::Deferred(common::TypeParamAttr::Len));
420       }
421       derived.CookParameters(context_.foldingContext());
422     }
423     DeclTypeSpec &decl{
424         dtScope.MakeDerivedType(DeclTypeSpec::TypeDerived, std::move(derived))};
425     derivedTypeSpec = &decl.derivedTypeSpec();
426   }
427   const Symbol *dtSymbol{
428       derivedTypeSpec ? &derivedTypeSpec->typeSymbol() : dtScope.symbol()};
429   if (!dtSymbol) {
430     return nullptr;
431   }
432   auto locationRestorer{common::ScopedSet(location_, dtSymbol->name())};
433   // Check for an existing description that can be imported from a USE'd module
434   std::string typeName{dtSymbol->name().ToString()};
435   if (typeName.empty() ||
436       (typeName.front() == '.' && !context_.IsTempName(typeName))) {
437     return nullptr;
438   }
439   bool isPDTDefinitionWithKindParameters{
440       !derivedTypeSpec && dtScope.IsDerivedTypeWithKindParameter()};
441   bool isPDTInstantiation{derivedTypeSpec && &dtScope != dtSymbol->scope()};
442   const SymbolVector *parameters{GetTypeParameters(*dtSymbol)};
443   std::string distinctName{typeName};
444   if (isPDTInstantiation) {
445     // Only create new type descriptions for different kind parameter values.
446     // Type with different length parameters/same kind parameters can all
447     // share the same type description available in the current scope.
448     if (auto suffix{
449             GetSuffixIfTypeKindParameters(*derivedTypeSpec, parameters)}) {
450       distinctName += *suffix;
451     }
452   } else if (isPDTDefinitionWithKindParameters) {
453     return nullptr;
454   }
455   std::string dtDescName{(fir::kTypeDescriptorSeparator + distinctName).str()};
456   Scope *dtSymbolScope{const_cast<Scope *>(dtSymbol->scope())};
457   Scope &scope{
458       GetContainingNonDerivedScope(dtSymbolScope ? *dtSymbolScope : dtScope)};
459   if (const auto it{scope.find(SourceName{dtDescName})}; it != scope.end()) {
460     dtScope.set_runtimeDerivedTypeDescription(*it->second);
461     return &*it->second;
462   }
463 
464   // Create a new description object before populating it so that mutual
465   // references will work as pointer targets.
466   Symbol &dtObject{CreateObject(dtDescName, derivedTypeSchema_, scope)};
467   dtScope.set_runtimeDerivedTypeDescription(dtObject);
468   evaluate::StructureConstructorValues dtValues;
469   AddValue(dtValues, derivedTypeSchema_, "name"s,
470       SaveNameAsPointerTarget(scope, typeName));
471   if (!isPDTDefinitionWithKindParameters) {
472     auto sizeInBytes{static_cast<common::ConstantSubscript>(dtScope.size())};
473     if (auto alignment{dtScope.alignment().value_or(0)}) {
474       sizeInBytes += alignment - 1;
475       sizeInBytes /= alignment;
476       sizeInBytes *= alignment;
477     }
478     AddValue(
479         dtValues, derivedTypeSchema_, "sizeinbytes"s, IntToExpr(sizeInBytes));
480   }
481   if (const Symbol *
482       uninstDescObject{isPDTInstantiation
483               ? DescribeType(DEREF(const_cast<Scope *>(dtSymbol->scope())))
484               : nullptr}) {
485     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
486         evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
487             evaluate::Designator<evaluate::SomeDerived>{
488                 DEREF(uninstDescObject)}}));
489   } else {
490     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
491         SomeExpr{evaluate::NullPointer{}});
492   }
493   using Int8 = evaluate::Type<TypeCategory::Integer, 8>;
494   using Int1 = evaluate::Type<TypeCategory::Integer, 1>;
495   std::vector<Int8::Scalar> kinds;
496   std::vector<Int1::Scalar> lenKinds;
497   if (parameters) {
498     // Package the derived type's parameters in declaration order for
499     // each category of parameter.  KIND= type parameters are described
500     // by their instantiated (or default) values, while LEN= type
501     // parameters are described by their INTEGER kinds.
502     for (SymbolRef ref : *parameters) {
503       if (const auto *inst{dtScope.FindComponent(ref->name())}) {
504         const auto &tpd{inst->get<TypeParamDetails>()};
505         if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Kind) {
506           auto value{evaluate::ToInt64(tpd.init()).value_or(0)};
507           if (derivedTypeSpec) {
508             if (const auto *pv{derivedTypeSpec->FindParameter(inst->name())}) {
509               if (pv->GetExplicit()) {
510                 if (auto instantiatedValue{
511                         evaluate::ToInt64(*pv->GetExplicit())}) {
512                   value = *instantiatedValue;
513                 }
514               }
515             }
516           }
517           kinds.emplace_back(value);
518         } else { // LEN= parameter
519           lenKinds.emplace_back(GetIntegerKind(*inst));
520         }
521       }
522     }
523   }
524   AddValue(dtValues, derivedTypeSchema_, "kindparameter"s,
525       SaveNumericPointerTarget<Int8>(scope,
526           SaveObjectName((fir::kKindParameterSeparator + distinctName).str()),
527           std::move(kinds)));
528   AddValue(dtValues, derivedTypeSchema_, "lenparameterkind"s,
529       SaveNumericPointerTarget<Int1>(scope,
530           SaveObjectName((fir::kLenKindSeparator + distinctName).str()),
531           std::move(lenKinds)));
532   // Traverse the components of the derived type
533   if (!isPDTDefinitionWithKindParameters) {
534     std::vector<const Symbol *> dataComponentSymbols;
535     std::vector<evaluate::StructureConstructor> procPtrComponents;
536     for (const auto &pair : dtScope) {
537       const Symbol &symbol{*pair.second};
538       auto locationRestorer{common::ScopedSet(location_, symbol.name())};
539       common::visit(
540           common::visitors{
541               [&](const TypeParamDetails &) {
542                 // already handled above in declaration order
543               },
544               [&](const ObjectEntityDetails &) {
545                 dataComponentSymbols.push_back(&symbol);
546               },
547               [&](const ProcEntityDetails &proc) {
548                 if (IsProcedurePointer(symbol)) {
549                   procPtrComponents.emplace_back(
550                       DescribeComponent(symbol, proc, scope));
551                 }
552               },
553               [&](const ProcBindingDetails &) { // handled in a later pass
554               },
555               [&](const GenericDetails &) { // ditto
556               },
557               [&](const auto &) {
558                 common::die(
559                     "unexpected details on symbol '%s' in derived type scope",
560                     symbol.name().ToString().c_str());
561               },
562           },
563           symbol.details());
564     }
565     // Sort the data component symbols by offset before emitting them, placing
566     // the parent component first if any.
567     std::sort(dataComponentSymbols.begin(), dataComponentSymbols.end(),
568         [](const Symbol *x, const Symbol *y) {
569           return x->test(Symbol::Flag::ParentComp) || x->offset() < y->offset();
570         });
571     std::vector<evaluate::StructureConstructor> dataComponents;
572     for (const Symbol *symbol : dataComponentSymbols) {
573       auto locationRestorer{common::ScopedSet(location_, symbol->name())};
574       dataComponents.emplace_back(
575           DescribeComponent(*symbol, symbol->get<ObjectEntityDetails>(), scope,
576               dtScope, distinctName, parameters));
577     }
578     AddValue(dtValues, derivedTypeSchema_, "component"s,
579         SaveDerivedPointerTarget(scope,
580             SaveObjectName((fir::kComponentSeparator + distinctName).str()),
581             std::move(dataComponents),
582             evaluate::ConstantSubscripts{
583                 static_cast<evaluate::ConstantSubscript>(
584                     dataComponents.size())}));
585     AddValue(dtValues, derivedTypeSchema_, "procptr"s,
586         SaveDerivedPointerTarget(scope,
587             SaveObjectName((fir::kProcPtrSeparator + distinctName).str()),
588             std::move(procPtrComponents),
589             evaluate::ConstantSubscripts{
590                 static_cast<evaluate::ConstantSubscript>(
591                     procPtrComponents.size())}));
592     // Compile the "vtable" of type-bound procedure bindings
593     std::uint32_t specialBitSet{0};
594     if (!dtSymbol->attrs().test(Attr::ABSTRACT)) {
595       std::vector<evaluate::StructureConstructor> bindings{
596           DescribeBindings(dtScope, scope)};
597       AddValue(dtValues, derivedTypeSchema_, bindingDescCompName,
598           SaveDerivedPointerTarget(scope,
599               SaveObjectName(
600                   (fir::kBindingTableSeparator + distinctName).str()),
601               std::move(bindings),
602               evaluate::ConstantSubscripts{
603                   static_cast<evaluate::ConstantSubscript>(bindings.size())}));
604       // Describe "special" bindings to defined assignments, FINAL subroutines,
605       // and defined derived type I/O subroutines.  Defined assignments and I/O
606       // subroutines override any parent bindings, but FINAL subroutines do not
607       // (the runtime will call all of them).
608       std::map<int, evaluate::StructureConstructor> specials{
609           DescribeSpecialGenerics(dtScope, dtScope, derivedTypeSpec)};
610       if (derivedTypeSpec) {
611         for (auto &ref : FinalsForDerivedTypeInstantiation(*derivedTypeSpec)) {
612           DescribeSpecialProc(specials, *ref, /*isAssignment-*/ false,
613               /*isFinal=*/true, std::nullopt, nullptr, derivedTypeSpec,
614               /*isTypeBound=*/true);
615         }
616         IncorporateDefinedIoGenericInterfaces(specials,
617             common::DefinedIo::ReadFormatted, &scope, derivedTypeSpec);
618         IncorporateDefinedIoGenericInterfaces(specials,
619             common::DefinedIo::ReadUnformatted, &scope, derivedTypeSpec);
620         IncorporateDefinedIoGenericInterfaces(specials,
621             common::DefinedIo::WriteFormatted, &scope, derivedTypeSpec);
622         IncorporateDefinedIoGenericInterfaces(specials,
623             common::DefinedIo::WriteUnformatted, &scope, derivedTypeSpec);
624       }
625       // Pack the special procedure bindings in ascending order of their "which"
626       // code values, and compile a little-endian bit-set of those codes for
627       // use in O(1) look-up at run time.
628       std::vector<evaluate::StructureConstructor> sortedSpecials;
629       for (auto &pair : specials) {
630         auto bit{std::uint32_t{1} << pair.first};
631         CHECK(!(specialBitSet & bit));
632         specialBitSet |= bit;
633         sortedSpecials.emplace_back(std::move(pair.second));
634       }
635       AddValue(dtValues, derivedTypeSchema_, "special"s,
636           SaveDerivedPointerTarget(scope,
637               SaveObjectName(
638                   (fir::kSpecialBindingSeparator + distinctName).str()),
639               std::move(sortedSpecials),
640               evaluate::ConstantSubscripts{
641                   static_cast<evaluate::ConstantSubscript>(specials.size())}));
642     }
643     AddValue(dtValues, derivedTypeSchema_, "specialbitset"s,
644         IntExpr<4>(specialBitSet));
645     // Note the presence/absence of a parent component
646     AddValue(dtValues, derivedTypeSchema_, "hasparent"s,
647         IntExpr<1>(dtScope.GetDerivedTypeParent() != nullptr));
648     // To avoid wasting run time attempting to initialize derived type
649     // instances without any initialized components, analyze the type
650     // and set a flag if there's nothing to do for it at run time.
651     AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s,
652         IntExpr<1>(derivedTypeSpec &&
653             !derivedTypeSpec->HasDefaultInitialization(false, false)));
654     // Similarly, a flag to short-circuit destruction when not needed.
655     AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s,
656         IntExpr<1>(derivedTypeSpec && !derivedTypeSpec->HasDestruction()));
657     // Similarly, a flag to short-circuit finalization when not needed.
658     AddValue(dtValues, derivedTypeSchema_, "nofinalizationneeded"s,
659         IntExpr<1>(
660             derivedTypeSpec && !MayRequireFinalization(*derivedTypeSpec)));
661   }
662   dtObject.get<ObjectEntityDetails>().set_init(MaybeExpr{
663       StructureExpr(Structure(derivedTypeSchema_, std::move(dtValues)))});
664   return &dtObject;
665 }
666 
667 static const Symbol &GetSymbol(const Scope &schemata, SourceName name) {
668   auto iter{schemata.find(name)};
669   CHECK(iter != schemata.end());
670   const Symbol &symbol{*iter->second};
671   return symbol;
672 }
673 
674 const Symbol &RuntimeTableBuilder::GetSchemaSymbol(const char *name) const {
675   return GetSymbol(
676       DEREF(tables_.schemata), SourceName{name, std::strlen(name)});
677 }
678 
679 const DeclTypeSpec &RuntimeTableBuilder::GetSchema(
680     const char *schemaName) const {
681   Scope &schemata{DEREF(tables_.schemata)};
682   SourceName name{schemaName, std::strlen(schemaName)};
683   const Symbol &symbol{GetSymbol(schemata, name)};
684   CHECK(symbol.has<DerivedTypeDetails>());
685   CHECK(symbol.scope());
686   CHECK(symbol.scope()->IsDerivedType());
687   const DeclTypeSpec *spec{nullptr};
688   if (symbol.scope()->derivedTypeSpec()) {
689     DeclTypeSpec typeSpec{
690         DeclTypeSpec::TypeDerived, *symbol.scope()->derivedTypeSpec()};
691     spec = schemata.FindType(typeSpec);
692   }
693   if (!spec) {
694     DeclTypeSpec typeSpec{
695         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol}};
696     spec = schemata.FindType(typeSpec);
697   }
698   if (!spec) {
699     spec = &schemata.MakeDerivedType(
700         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol});
701   }
702   CHECK(spec->AsDerived());
703   return *spec;
704 }
705 
706 SomeExpr RuntimeTableBuilder::GetEnumValue(const char *name) const {
707   const Symbol &symbol{GetSchemaSymbol(name)};
708   auto value{evaluate::ToInt64(symbol.get<ObjectEntityDetails>().init())};
709   CHECK(value.has_value());
710   return IntExpr<1>(*value);
711 }
712 
713 Symbol &RuntimeTableBuilder::CreateObject(
714     const std::string &name, const DeclTypeSpec &type, Scope &scope) {
715   ObjectEntityDetails object;
716   object.set_type(type);
717   auto pair{scope.try_emplace(SaveObjectName(name),
718       Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))};
719   CHECK(pair.second);
720   Symbol &result{*pair.first->second};
721   SetReadOnlyCompilerCreatedFlags(result);
722   return result;
723 }
724 
725 SourceName RuntimeTableBuilder::SaveObjectName(const std::string &name) {
726   return *tables_.names.insert(name).first;
727 }
728 
729 SomeExpr RuntimeTableBuilder::SaveNameAsPointerTarget(
730     Scope &scope, const std::string &name) {
731   CHECK(!name.empty());
732   CHECK(name.front() != '.' || context_.IsTempName(name));
733   ObjectEntityDetails object;
734   auto len{static_cast<common::ConstantSubscript>(name.size())};
735   if (const auto *spec{scope.FindType(DeclTypeSpec{CharacterTypeSpec{
736           ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}}})}) {
737     object.set_type(*spec);
738   } else {
739     object.set_type(scope.MakeCharacterType(
740         ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}));
741   }
742   using evaluate::Ascii;
743   using AsciiExpr = evaluate::Expr<Ascii>;
744   object.set_init(evaluate::AsGenericExpr(AsciiExpr{name}));
745   Symbol &symbol{
746       *scope
747            .try_emplace(
748                SaveObjectName((fir::kNameStringSeparator + name).str()),
749                Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
750            .first->second};
751   SetReadOnlyCompilerCreatedFlags(symbol);
752   return evaluate::AsGenericExpr(
753       AsciiExpr{evaluate::Designator<Ascii>{symbol}});
754 }
755 
756 evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
757     const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
758     Scope &dtScope, const std::string &distinctName,
759     const SymbolVector *parameters) {
760   evaluate::StructureConstructorValues values;
761   auto &foldingContext{context_.foldingContext()};
762   auto typeAndShape{evaluate::characteristics::TypeAndShape::Characterize(
763       symbol, foldingContext)};
764   CHECK(typeAndShape.has_value());
765   auto dyType{typeAndShape->type()};
766   int rank{typeAndShape->Rank()};
767   AddValue(values, componentSchema_, "name"s,
768       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
769   AddValue(values, componentSchema_, "category"s,
770       IntExpr<1>(static_cast<int>(dyType.category())));
771   if (dyType.IsUnlimitedPolymorphic() ||
772       dyType.category() == TypeCategory::Derived) {
773     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(0));
774   } else {
775     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(dyType.kind()));
776   }
777   AddValue(values, componentSchema_, "offset"s, IntExpr<8>(symbol.offset()));
778   // CHARACTER length
779   auto len{typeAndShape->LEN()};
780   if (const semantics::DerivedTypeSpec *
781       pdtInstance{dtScope.derivedTypeSpec()}) {
782     auto restorer{foldingContext.WithPDTInstance(*pdtInstance)};
783     len = Fold(foldingContext, std::move(len));
784   }
785   if (dyType.category() == TypeCategory::Character && len) {
786     // Ignore IDIM(x) (represented as MAX(0, x))
787     if (const auto *clamped{evaluate::UnwrapExpr<
788             evaluate::Extremum<evaluate::SubscriptInteger>>(*len)}) {
789       if (clamped->ordering == evaluate::Ordering::Greater &&
790           clamped->left() == evaluate::Expr<evaluate::SubscriptInteger>{0}) {
791         len = common::Clone(clamped->right());
792       }
793     }
794     AddValue(values, componentSchema_, "characterlen"s,
795         evaluate::AsGenericExpr(GetValue(len, parameters)));
796   } else {
797     AddValue(values, componentSchema_, "characterlen"s,
798         PackageIntValueExpr(deferredEnum_));
799   }
800   // Describe component's derived type
801   std::vector<evaluate::StructureConstructor> lenParams;
802   if (dyType.category() == TypeCategory::Derived &&
803       !dyType.IsUnlimitedPolymorphic()) {
804     const DerivedTypeSpec &spec{dyType.GetDerivedTypeSpec()};
805     Scope *derivedScope{const_cast<Scope *>(
806         spec.scope() ? spec.scope() : spec.typeSymbol().scope())};
807     if (const Symbol * derivedDescription{DescribeType(DEREF(derivedScope))}) {
808       AddValue(values, componentSchema_, "derived"s,
809           evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
810               evaluate::Designator<evaluate::SomeDerived>{
811                   DEREF(derivedDescription)}}));
812       // Package values of LEN parameters, if any
813       if (const SymbolVector *
814           specParams{GetTypeParameters(spec.typeSymbol())}) {
815         for (SymbolRef ref : *specParams) {
816           const auto &tpd{ref->get<TypeParamDetails>()};
817           if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Len) {
818             if (const ParamValue *
819                 paramValue{spec.FindParameter(ref->name())}) {
820               lenParams.emplace_back(GetValue(*paramValue, parameters));
821             } else {
822               lenParams.emplace_back(GetValue(tpd.init(), parameters));
823             }
824           }
825         }
826       }
827     }
828   } else {
829     // Subtle: a category of Derived with a null derived type pointer
830     // signifies CLASS(*)
831     AddValue(values, componentSchema_, "derived"s,
832         SomeExpr{evaluate::NullPointer{}});
833   }
834   // LEN type parameter values for the component's type
835   if (!lenParams.empty()) {
836     AddValue(values, componentSchema_, "lenvalue"s,
837         SaveDerivedPointerTarget(scope,
838             SaveObjectName((fir::kLenParameterSeparator + distinctName +
839                 fir::kNameSeparator + symbol.name().ToString())
840                                .str()),
841             std::move(lenParams),
842             evaluate::ConstantSubscripts{
843                 static_cast<evaluate::ConstantSubscript>(lenParams.size())}));
844   } else {
845     AddValue(values, componentSchema_, "lenvalue"s,
846         SomeExpr{evaluate::NullPointer{}});
847   }
848   // Shape information
849   AddValue(values, componentSchema_, "rank"s, IntExpr<1>(rank));
850   if (rank > 0 && !IsAllocatable(symbol) && !IsPointer(symbol)) {
851     std::vector<evaluate::StructureConstructor> bounds;
852     evaluate::NamedEntity entity{symbol};
853     for (int j{0}; j < rank; ++j) {
854       bounds.emplace_back(
855           GetValue(std::make_optional(
856                        evaluate::GetRawLowerBound(foldingContext, entity, j)),
857               parameters));
858       bounds.emplace_back(GetValue(
859           evaluate::GetRawUpperBound(foldingContext, entity, j), parameters));
860     }
861     AddValue(values, componentSchema_, "bounds"s,
862         SaveDerivedPointerTarget(scope,
863             SaveObjectName((fir::kBoundsSeparator + distinctName +
864                 fir::kNameSeparator + symbol.name().ToString())
865                                .str()),
866             std::move(bounds), evaluate::ConstantSubscripts{2, rank}));
867   } else {
868     AddValue(
869         values, componentSchema_, "bounds"s, SomeExpr{evaluate::NullPointer{}});
870   }
871   // Default component initialization
872   bool hasDataInit{false};
873   if (IsAllocatable(symbol)) {
874     AddValue(values, componentSchema_, "genre"s, GetEnumValue("allocatable"));
875   } else if (IsPointer(symbol)) {
876     AddValue(values, componentSchema_, "genre"s, GetEnumValue("pointer"));
877     hasDataInit = InitializeDataPointer(
878         values, symbol, object, scope, dtScope, distinctName);
879   } else if (IsAutomatic(symbol)) {
880     AddValue(values, componentSchema_, "genre"s, GetEnumValue("automatic"));
881   } else {
882     AddValue(values, componentSchema_, "genre"s, GetEnumValue("data"));
883     hasDataInit = object.init().has_value();
884     if (hasDataInit) {
885       AddValue(values, componentSchema_, "initialization"s,
886           SaveObjectInit(scope,
887               SaveObjectName((fir::kComponentInitSeparator + distinctName +
888                   fir::kNameSeparator + symbol.name().ToString())
889                                  .str()),
890               object));
891     }
892   }
893   if (!hasDataInit) {
894     AddValue(values, componentSchema_, "initialization"s,
895         SomeExpr{evaluate::NullPointer{}});
896   }
897   return {DEREF(componentSchema_.AsDerived()), std::move(values)};
898 }
899 
900 evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
901     const Symbol &symbol, const ProcEntityDetails &proc, Scope &scope) {
902   evaluate::StructureConstructorValues values;
903   AddValue(values, procPtrSchema_, "name"s,
904       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
905   AddValue(values, procPtrSchema_, "offset"s, IntExpr<8>(symbol.offset()));
906   if (auto init{proc.init()}; init && *init) {
907     AddValue(values, procPtrSchema_, "initialization"s,
908         SomeExpr{evaluate::ProcedureDesignator{**init}});
909   } else {
910     AddValue(values, procPtrSchema_, "initialization"s,
911         SomeExpr{evaluate::NullPointer{}});
912   }
913   return {DEREF(procPtrSchema_.AsDerived()), std::move(values)};
914 }
915 
916 // Create a static pointer object with the same initialization
917 // from whence the runtime can memcpy() the data pointer
918 // component initialization.
919 // Creates and interconnects the symbols, scopes, and types for
920 //   TYPE :: ptrDt
921 //     type, POINTER :: name
922 //   END TYPE
923 //   TYPE(ptrDt), TARGET, SAVE :: ptrInit = ptrDt(designator)
924 // and then initializes the original component by setting
925 //   initialization = ptrInit
926 // which takes the address of ptrInit because the type is C_PTR.
927 // This technique of wrapping the data pointer component into
928 // a derived type instance disables any reason for lowering to
929 // attempt to dereference the RHS of an initializer, thereby
930 // allowing the runtime to actually perform the initialization
931 // by means of a simple memcpy() of the wrapped descriptor in
932 // ptrInit to the data pointer component being initialized.
933 bool RuntimeTableBuilder::InitializeDataPointer(
934     evaluate::StructureConstructorValues &values, const Symbol &symbol,
935     const ObjectEntityDetails &object, Scope &scope, Scope &dtScope,
936     const std::string &distinctName) {
937   if (object.init().has_value()) {
938     SourceName ptrDtName{SaveObjectName((fir::kDataPtrInitSeparator +
939         distinctName + fir::kNameSeparator + symbol.name().ToString())
940                                             .str())};
941     Symbol &ptrDtSym{
942         *scope.try_emplace(ptrDtName, Attrs{}, UnknownDetails{}).first->second};
943     SetReadOnlyCompilerCreatedFlags(ptrDtSym);
944     Scope &ptrDtScope{scope.MakeScope(Scope::Kind::DerivedType, &ptrDtSym)};
945     ignoreScopes_.insert(&ptrDtScope);
946     ObjectEntityDetails ptrDtObj;
947     ptrDtObj.set_type(DEREF(object.type()));
948     ptrDtObj.set_shape(object.shape());
949     Symbol &ptrDtComp{*ptrDtScope
950                            .try_emplace(symbol.name(), Attrs{Attr::POINTER},
951                                std::move(ptrDtObj))
952                            .first->second};
953     DerivedTypeDetails ptrDtDetails;
954     ptrDtDetails.add_component(ptrDtComp);
955     ptrDtSym.set_details(std::move(ptrDtDetails));
956     ptrDtSym.set_scope(&ptrDtScope);
957     DeclTypeSpec &ptrDtDeclType{
958         scope.MakeDerivedType(DeclTypeSpec::Category::TypeDerived,
959             DerivedTypeSpec{ptrDtName, ptrDtSym})};
960     DerivedTypeSpec &ptrDtDerived{DEREF(ptrDtDeclType.AsDerived())};
961     ptrDtDerived.set_scope(ptrDtScope);
962     ptrDtDerived.CookParameters(context_.foldingContext());
963     ptrDtDerived.Instantiate(scope);
964     ObjectEntityDetails ptrInitObj;
965     ptrInitObj.set_type(ptrDtDeclType);
966     evaluate::StructureConstructorValues ptrInitValues;
967     AddValue(
968         ptrInitValues, ptrDtDeclType, symbol.name().ToString(), *object.init());
969     ptrInitObj.set_init(evaluate::AsGenericExpr(
970         Structure(ptrDtDeclType, std::move(ptrInitValues))));
971     AddValue(values, componentSchema_, "initialization"s,
972         SaveObjectInit(scope,
973             SaveObjectName((fir::kComponentInitSeparator + distinctName +
974                 fir::kNameSeparator + symbol.name().ToString())
975                                .str()),
976             ptrInitObj));
977     return true;
978   } else {
979     return false;
980   }
981 }
982 
983 evaluate::StructureConstructor RuntimeTableBuilder::PackageIntValue(
984     const SomeExpr &genre, std::int64_t n) const {
985   evaluate::StructureConstructorValues xs;
986   AddValue(xs, valueSchema_, "genre"s, genre);
987   AddValue(xs, valueSchema_, "value"s, IntToExpr(n));
988   return Structure(valueSchema_, std::move(xs));
989 }
990 
991 SomeExpr RuntimeTableBuilder::PackageIntValueExpr(
992     const SomeExpr &genre, std::int64_t n) const {
993   return StructureExpr(PackageIntValue(genre, n));
994 }
995 
996 SymbolVector CollectBindings(const Scope &dtScope) {
997   SymbolVector result;
998   std::map<SourceName, Symbol *> localBindings;
999   // Collect local bindings
1000   for (auto pair : dtScope) {
1001     Symbol &symbol{const_cast<Symbol &>(*pair.second)};
1002     if (auto *binding{symbol.detailsIf<ProcBindingDetails>()}) {
1003       localBindings.emplace(symbol.name(), &symbol);
1004       binding->set_numPrivatesNotOverridden(0);
1005     }
1006   }
1007   if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) {
1008     result = CollectBindings(*parentScope);
1009     // Apply overrides from the local bindings of the extended type
1010     for (auto iter{result.begin()}; iter != result.end(); ++iter) {
1011       const Symbol &symbol{**iter};
1012       auto overriderIter{localBindings.find(symbol.name())};
1013       if (overriderIter != localBindings.end()) {
1014         Symbol &overrider{*overriderIter->second};
1015         if (symbol.attrs().test(Attr::PRIVATE) &&
1016             FindModuleContaining(symbol.owner()) !=
1017                 FindModuleContaining(dtScope)) {
1018           // Don't override inaccessible PRIVATE bindings
1019           auto &binding{overrider.get<ProcBindingDetails>()};
1020           binding.set_numPrivatesNotOverridden(
1021               binding.numPrivatesNotOverridden() + 1);
1022         } else {
1023           *iter = overrider;
1024           localBindings.erase(overriderIter);
1025         }
1026       }
1027     }
1028   }
1029   // Add remaining (non-overriding) local bindings in name order to the result
1030   for (auto pair : localBindings) {
1031     result.push_back(*pair.second);
1032   }
1033   return result;
1034 }
1035 
1036 std::vector<evaluate::StructureConstructor>
1037 RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) {
1038   std::vector<evaluate::StructureConstructor> result;
1039   for (const SymbolRef &ref : CollectBindings(dtScope)) {
1040     evaluate::StructureConstructorValues values;
1041     AddValue(values, bindingSchema_, procCompName,
1042         SomeExpr{evaluate::ProcedureDesignator{
1043             ref.get().get<ProcBindingDetails>().symbol()}});
1044     AddValue(values, bindingSchema_, "name"s,
1045         SaveNameAsPointerTarget(scope, ref.get().name().ToString()));
1046     result.emplace_back(DEREF(bindingSchema_.AsDerived()), std::move(values));
1047   }
1048   return result;
1049 }
1050 
1051 std::map<int, evaluate::StructureConstructor>
1052 RuntimeTableBuilder::DescribeSpecialGenerics(const Scope &dtScope,
1053     const Scope &thisScope, const DerivedTypeSpec *derivedTypeSpec) const {
1054   std::map<int, evaluate::StructureConstructor> specials;
1055   if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) {
1056     specials =
1057         DescribeSpecialGenerics(*parentScope, thisScope, derivedTypeSpec);
1058   }
1059   for (auto pair : dtScope) {
1060     const Symbol &symbol{*pair.second};
1061     if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
1062       DescribeSpecialGeneric(*generic, specials, thisScope, derivedTypeSpec);
1063     }
1064   }
1065   return specials;
1066 }
1067 
1068 void RuntimeTableBuilder::DescribeSpecialGeneric(const GenericDetails &generic,
1069     std::map<int, evaluate::StructureConstructor> &specials,
1070     const Scope &dtScope, const DerivedTypeSpec *derivedTypeSpec) const {
1071   common::visit(
1072       common::visitors{
1073           [&](const GenericKind::OtherKind &k) {
1074             if (k == GenericKind::OtherKind::Assignment) {
1075               for (auto ref : generic.specificProcs()) {
1076                 DescribeSpecialProc(specials, *ref, /*isAssignment=*/true,
1077                     /*isFinal=*/false, std::nullopt, &dtScope, derivedTypeSpec,
1078                     /*isTypeBound=*/true);
1079               }
1080             }
1081           },
1082           [&](const common::DefinedIo &io) {
1083             switch (io) {
1084             case common::DefinedIo::ReadFormatted:
1085             case common::DefinedIo::ReadUnformatted:
1086             case common::DefinedIo::WriteFormatted:
1087             case common::DefinedIo::WriteUnformatted:
1088               for (auto ref : generic.specificProcs()) {
1089                 DescribeSpecialProc(specials, *ref, /*isAssignment=*/false,
1090                     /*isFinal=*/false, io, &dtScope, derivedTypeSpec,
1091                     /*isTypeBound=*/true);
1092               }
1093               break;
1094             }
1095           },
1096           [](const auto &) {},
1097       },
1098       generic.kind().u);
1099 }
1100 
1101 void RuntimeTableBuilder::DescribeSpecialProc(
1102     std::map<int, evaluate::StructureConstructor> &specials,
1103     const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
1104     std::optional<common::DefinedIo> io, const Scope *dtScope,
1105     const DerivedTypeSpec *derivedTypeSpec, bool isTypeBound) const {
1106   const auto *binding{specificOrBinding.detailsIf<ProcBindingDetails>()};
1107   if (binding && dtScope) { // use most recent override
1108     binding = &DEREF(dtScope->FindComponent(specificOrBinding.name()))
1109                    .get<ProcBindingDetails>();
1110   }
1111   const Symbol &specific{*(binding ? &binding->symbol() : &specificOrBinding)};
1112   if (auto proc{evaluate::characteristics::Procedure::Characterize(
1113           specific, context_.foldingContext())}) {
1114     std::uint8_t isArgDescriptorSet{0};
1115     std::uint8_t isArgContiguousSet{0};
1116     int argThatMightBeDescriptor{0};
1117     MaybeExpr which;
1118     if (isAssignment) {
1119       // Only type-bound asst's with the same type on both dummy arguments
1120       // are germane to the runtime, which needs only these to implement
1121       // component assignment as part of intrinsic assignment.
1122       // Non-type-bound generic INTERFACEs and assignments from distinct
1123       // types must not be used for component intrinsic assignment.
1124       CHECK(proc->dummyArguments.size() == 2);
1125       const auto t1{
1126           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1127                     &proc->dummyArguments[0].u))
1128               .type.type()};
1129       const auto t2{
1130           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1131                     &proc->dummyArguments[1].u))
1132               .type.type()};
1133       if (!binding || t1.category() != TypeCategory::Derived ||
1134           t2.category() != TypeCategory::Derived ||
1135           t1.IsUnlimitedPolymorphic() || t2.IsUnlimitedPolymorphic() ||
1136           t1.GetDerivedTypeSpec() != t2.GetDerivedTypeSpec()) {
1137         return;
1138       }
1139       which = proc->IsElemental() ? elementalAssignmentEnum_
1140                                   : scalarAssignmentEnum_;
1141       if (binding && binding->passName() &&
1142           *binding->passName() == proc->dummyArguments[1].name) {
1143         argThatMightBeDescriptor = 1;
1144         isArgDescriptorSet |= 2;
1145       } else {
1146         argThatMightBeDescriptor = 2; // the non-passed-object argument
1147         isArgDescriptorSet |= 1;
1148       }
1149     } else if (isFinal) {
1150       CHECK(binding == nullptr); // FINALs are not bindings
1151       CHECK(proc->dummyArguments.size() == 1);
1152       if (proc->IsElemental()) {
1153         which = elementalFinalEnum_;
1154       } else {
1155         const auto &dummyData{
1156             std::get<evaluate::characteristics::DummyDataObject>(
1157                 proc->dummyArguments.at(0).u)};
1158         const auto &typeAndShape{dummyData.type};
1159         if (typeAndShape.attrs().test(
1160                 evaluate::characteristics::TypeAndShape::Attr::AssumedRank)) {
1161           which = assumedRankFinalEnum_;
1162           isArgDescriptorSet |= 1;
1163         } else {
1164           which = scalarFinalEnum_;
1165           if (int rank{typeAndShape.Rank()}; rank > 0) {
1166             which = IntExpr<1>(ToInt64(which).value() + rank);
1167             if (dummyData.IsPassedByDescriptor(proc->IsBindC())) {
1168               argThatMightBeDescriptor = 1;
1169             }
1170             if (!typeAndShape.attrs().test(evaluate::characteristics::
1171                         TypeAndShape::Attr::AssumedShape) ||
1172                 dummyData.attrs.test(evaluate::characteristics::
1173                         DummyDataObject::Attr::Contiguous)) {
1174               isArgContiguousSet |= 1;
1175             }
1176           }
1177         }
1178       }
1179     } else { // defined derived type I/O
1180       CHECK(proc->dummyArguments.size() >= 4);
1181       const auto *ddo{std::get_if<evaluate::characteristics::DummyDataObject>(
1182           &proc->dummyArguments[0].u)};
1183       if (!ddo) {
1184         return;
1185       }
1186       if (derivedTypeSpec &&
1187           !ddo->type.type().IsTkCompatibleWith(
1188               evaluate::DynamicType{*derivedTypeSpec})) {
1189         // Defined I/O specific procedure is not for this derived type.
1190         return;
1191       }
1192       if (ddo->type.type().IsPolymorphic()) {
1193         isArgDescriptorSet |= 1;
1194       }
1195       switch (io.value()) {
1196       case common::DefinedIo::ReadFormatted:
1197         which = readFormattedEnum_;
1198         break;
1199       case common::DefinedIo::ReadUnformatted:
1200         which = readUnformattedEnum_;
1201         break;
1202       case common::DefinedIo::WriteFormatted:
1203         which = writeFormattedEnum_;
1204         break;
1205       case common::DefinedIo::WriteUnformatted:
1206         which = writeUnformattedEnum_;
1207         break;
1208       }
1209     }
1210     if (argThatMightBeDescriptor != 0) {
1211       if (const auto *dummyData{
1212               std::get_if<evaluate::characteristics::DummyDataObject>(
1213                   &proc->dummyArguments.at(argThatMightBeDescriptor - 1).u)}) {
1214         if (dummyData->IsPassedByDescriptor(proc->IsBindC())) {
1215           isArgDescriptorSet |= 1 << (argThatMightBeDescriptor - 1);
1216         }
1217       }
1218     }
1219     evaluate::StructureConstructorValues values;
1220     auto index{evaluate::ToInt64(which)};
1221     CHECK(index.has_value());
1222     AddValue(
1223         values, specialSchema_, "which"s, SomeExpr{std::move(which.value())});
1224     AddValue(values, specialSchema_, "isargdescriptorset"s,
1225         IntExpr<1>(isArgDescriptorSet));
1226     AddValue(values, specialSchema_, "istypebound"s,
1227         IntExpr<1>(isTypeBound ? 1 : 0));
1228     AddValue(values, specialSchema_, "isargcontiguousset"s,
1229         IntExpr<1>(isArgContiguousSet));
1230     AddValue(values, specialSchema_, procCompName,
1231         SomeExpr{evaluate::ProcedureDesignator{specific}});
1232     // index might already be present in the case of an override
1233     specials.emplace(*index,
1234         evaluate::StructureConstructor{
1235             DEREF(specialSchema_.AsDerived()), std::move(values)});
1236   }
1237 }
1238 
1239 void RuntimeTableBuilder::IncorporateDefinedIoGenericInterfaces(
1240     std::map<int, evaluate::StructureConstructor> &specials,
1241     common::DefinedIo definedIo, const Scope *scope,
1242     const DerivedTypeSpec *derivedTypeSpec) {
1243   SourceName name{GenericKind::AsFortran(definedIo)};
1244   for (; !scope->IsGlobal(); scope = &scope->parent()) {
1245     if (auto asst{scope->find(name)}; asst != scope->end()) {
1246       const Symbol &generic{asst->second->GetUltimate()};
1247       const auto &genericDetails{generic.get<GenericDetails>()};
1248       CHECK(std::holds_alternative<common::DefinedIo>(genericDetails.kind().u));
1249       CHECK(std::get<common::DefinedIo>(genericDetails.kind().u) == definedIo);
1250       for (auto ref : genericDetails.specificProcs()) {
1251         DescribeSpecialProc(specials, *ref, false, false, definedIo, nullptr,
1252             derivedTypeSpec, false);
1253       }
1254     }
1255   }
1256 }
1257 
1258 RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(
1259     SemanticsContext &context) {
1260   RuntimeDerivedTypeTables result;
1261   // Do not attempt to read __fortran_type_info.mod when compiling
1262   // the module on which it depends.
1263   const auto &allSources{context.allCookedSources().allSources()};
1264   if (auto firstProv{allSources.GetFirstFileProvenance()}) {
1265     if (const auto *srcFile{allSources.GetSourceFile(firstProv->start())}) {
1266       if (srcFile->path().find("__fortran_builtins.f90") != std::string::npos) {
1267         return result;
1268       }
1269     }
1270   }
1271   result.schemata = context.GetBuiltinModule(typeInfoBuiltinModule);
1272   if (result.schemata) {
1273     RuntimeTableBuilder builder{context, result};
1274     builder.DescribeTypes(context.globalScope(), false);
1275   }
1276   return result;
1277 }
1278 
1279 // Find the type of a defined I/O procedure's interface's initial "dtv"
1280 // dummy argument.  Returns a non-null DeclTypeSpec pointer only if that
1281 // dtv argument exists and is a derived type.
1282 static const DeclTypeSpec *GetDefinedIoSpecificArgType(const Symbol &specific) {
1283   const Symbol *interface{&specific.GetUltimate()};
1284   if (const auto *procEntity{specific.detailsIf<ProcEntityDetails>()}) {
1285     interface = procEntity->procInterface();
1286   }
1287   if (interface) {
1288     if (const SubprogramDetails *
1289             subprogram{interface->detailsIf<SubprogramDetails>()};
1290         subprogram && !subprogram->dummyArgs().empty()) {
1291       if (const Symbol * dtvArg{subprogram->dummyArgs().at(0)}) {
1292         if (const DeclTypeSpec * declType{dtvArg->GetType()}) {
1293           return declType->AsDerived() ? declType : nullptr;
1294         }
1295       }
1296     }
1297   }
1298   return nullptr;
1299 }
1300 
1301 // Locate a particular scope's generic interface for a specific kind of
1302 // defined I/O.
1303 static const Symbol *FindGenericDefinedIo(
1304     const Scope &scope, common::DefinedIo which) {
1305   if (const Symbol * symbol{scope.FindSymbol(GenericKind::AsFortran(which))}) {
1306     const Symbol &generic{symbol->GetUltimate()};
1307     const auto &genericDetails{generic.get<GenericDetails>()};
1308     CHECK(std::holds_alternative<common::DefinedIo>(genericDetails.kind().u));
1309     CHECK(std::get<common::DefinedIo>(genericDetails.kind().u) == which);
1310     return &generic;
1311   } else {
1312     return nullptr;
1313   }
1314 }
1315 
1316 std::multimap<const Symbol *, NonTbpDefinedIo>
1317 CollectNonTbpDefinedIoGenericInterfaces(
1318     const Scope &scope, bool useRuntimeTypeInfoEntries) {
1319   std::multimap<const Symbol *, NonTbpDefinedIo> result;
1320   if (!scope.IsTopLevel() &&
1321       (scope.GetImportKind() == Scope::ImportKind::All ||
1322           scope.GetImportKind() == Scope::ImportKind::Default)) {
1323     result = CollectNonTbpDefinedIoGenericInterfaces(
1324         scope.parent(), useRuntimeTypeInfoEntries);
1325   }
1326   if (scope.kind() != Scope::Kind::DerivedType) {
1327     for (common::DefinedIo which :
1328         {common::DefinedIo::ReadFormatted, common::DefinedIo::ReadUnformatted,
1329             common::DefinedIo::WriteFormatted,
1330             common::DefinedIo::WriteUnformatted}) {
1331       if (const Symbol * generic{FindGenericDefinedIo(scope, which)}) {
1332         for (auto specific : generic->get<GenericDetails>().specificProcs()) {
1333           if (const DeclTypeSpec *
1334               declType{GetDefinedIoSpecificArgType(*specific)}) {
1335             const DerivedTypeSpec &derived{DEREF(declType->AsDerived())};
1336             if (const Symbol *
1337                 dtDesc{derived.scope()
1338                         ? derived.scope()->runtimeDerivedTypeDescription()
1339                         : nullptr}) {
1340               if (useRuntimeTypeInfoEntries &&
1341                   &derived.scope()->parent() == &generic->owner()) {
1342                 // This non-TBP defined I/O generic was defined in the
1343                 // same scope as the derived type, and it will be
1344                 // included in the derived type's special bindings
1345                 // by IncorporateDefinedIoGenericInterfaces().
1346               } else {
1347                 // Local scope's specific overrides host's for this type
1348                 bool updated{false};
1349                 for (auto [iter, end]{result.equal_range(dtDesc)}; iter != end;
1350                      ++iter) {
1351                   NonTbpDefinedIo &nonTbp{iter->second};
1352                   if (nonTbp.definedIo == which) {
1353                     nonTbp.subroutine = &*specific;
1354                     nonTbp.isDtvArgPolymorphic = declType->IsPolymorphic();
1355                     updated = true;
1356                   }
1357                 }
1358                 if (!updated) {
1359                   result.emplace(dtDesc,
1360                       NonTbpDefinedIo{
1361                           &*specific, which, declType->IsPolymorphic()});
1362                 }
1363               }
1364             }
1365           }
1366         }
1367       }
1368     }
1369   }
1370   return result;
1371 }
1372 
1373 // ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces()
1374 //
1375 // Returns a true result when a kind of defined I/O generic procedure
1376 // has a type (from a symbol or a NAMELIST) such that
1377 // (1) there is a specific procedure matching that type for a non-type-bound
1378 //     generic defined in the scope of the type, and
1379 // (2) that specific procedure is unavailable or overridden in a particular
1380 //     local scope.
1381 // Specific procedures of non-type-bound defined I/O generic interfaces
1382 // declared in the scope of a derived type are identified as special bindings
1383 // in the derived type's runtime type information, as if they had been
1384 // type-bound.  This predicate is meant to determine local situations in
1385 // which those special bindings are not to be used.  Its result is intended
1386 // to be put into the "ignoreNonTbpEntries" flag of
1387 // runtime::NonTbpDefinedIoTable and passed (negated) as the
1388 // "useRuntimeTypeInfoEntries" argument of
1389 // CollectNonTbpDefinedIoGenericInterfaces() above.
1390 
1391 static const Symbol *FindSpecificDefinedIo(const Scope &scope,
1392     const evaluate::DynamicType &derived, common::DefinedIo which) {
1393   if (const Symbol * generic{FindGenericDefinedIo(scope, which)}) {
1394     for (auto ref : generic->get<GenericDetails>().specificProcs()) {
1395       const Symbol &specific{*ref};
1396       if (const DeclTypeSpec *
1397           thisType{GetDefinedIoSpecificArgType(specific)}) {
1398         if (evaluate::DynamicType{DEREF(thisType->AsDerived()), true}
1399                 .IsTkCompatibleWith(derived)) {
1400           return &specific.GetUltimate();
1401         }
1402       }
1403     }
1404   }
1405   return nullptr;
1406 }
1407 
1408 bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
1409     const Scope &scope, const DerivedTypeSpec *derived) {
1410   if (!derived) {
1411     return false;
1412   }
1413   const Symbol &typeSymbol{derived->typeSymbol()};
1414   const Scope &typeScope{typeSymbol.GetUltimate().owner()};
1415   evaluate::DynamicType dyType{*derived};
1416   for (common::DefinedIo which :
1417       {common::DefinedIo::ReadFormatted, common::DefinedIo::ReadUnformatted,
1418           common::DefinedIo::WriteFormatted,
1419           common::DefinedIo::WriteUnformatted}) {
1420     if (const Symbol *
1421         specific{FindSpecificDefinedIo(typeScope, dyType, which)}) {
1422       // There's a non-TBP defined I/O procedure in the scope of the type's
1423       // definition that applies to this type.  It will appear in the type's
1424       // runtime information.  Determine whether it still applies in the
1425       // scope of interest.
1426       if (FindSpecificDefinedIo(scope, dyType, which) != specific) {
1427         return true;
1428       }
1429     }
1430   }
1431   return false;
1432 }
1433 
1434 bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
1435     const Scope &scope, const DeclTypeSpec *type) {
1436   return type &&
1437       ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
1438           scope, type->AsDerived());
1439 }
1440 
1441 bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
1442     const Scope &scope, const Symbol *symbol) {
1443   if (!symbol) {
1444     return false;
1445   }
1446   return common::visit(
1447       common::visitors{
1448           [&](const NamelistDetails &x) {
1449             for (auto ref : x.objects()) {
1450               if (ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
1451                       scope, &*ref)) {
1452                 return true;
1453               }
1454             }
1455             return false;
1456           },
1457           [&](const auto &) {
1458             return ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces(
1459                 scope, symbol->GetType());
1460           },
1461       },
1462       symbol->GetUltimate().details());
1463 }
1464 
1465 } // namespace Fortran::semantics
1466