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/Semantics/scope.h"
16 #include "flang/Semantics/tools.h"
17 #include <functional>
18 #include <list>
19 #include <map>
20 #include <string>
21 
22 namespace Fortran::semantics {
23 
FindLenParameterIndex(const SymbolVector & parameters,const Symbol & symbol)24 static int FindLenParameterIndex(
25     const SymbolVector &parameters, const Symbol &symbol) {
26   int lenIndex{0};
27   for (SymbolRef ref : parameters) {
28     if (&*ref == &symbol) {
29       return lenIndex;
30     }
31     if (ref->get<TypeParamDetails>().attr() == common::TypeParamAttr::Len) {
32       ++lenIndex;
33     }
34   }
35   DIE("Length type parameter not found in parameter order");
36   return -1;
37 }
38 
39 class RuntimeTableBuilder {
40 public:
41   RuntimeTableBuilder(SemanticsContext &, RuntimeDerivedTypeTables &);
42   void DescribeTypes(Scope &scope, bool inSchemata);
43 
44 private:
45   const Symbol *DescribeType(Scope &);
46   const Symbol &GetSchemaSymbol(const char *) const;
47   const DeclTypeSpec &GetSchema(const char *) const;
48   SomeExpr GetEnumValue(const char *) const;
49   Symbol &CreateObject(const std::string &, const DeclTypeSpec &, Scope &);
50   // The names of created symbols are saved in and owned by the
51   // RuntimeDerivedTypeTables instance returned by
52   // BuildRuntimeDerivedTypeTables() so that references to those names remain
53   // valid for lowering.
54   SourceName SaveObjectName(const std::string &);
55   SomeExpr SaveNameAsPointerTarget(Scope &, const std::string &);
56   const SymbolVector *GetTypeParameters(const Symbol &);
57   evaluate::StructureConstructor DescribeComponent(const Symbol &,
58       const ObjectEntityDetails &, Scope &, Scope &,
59       const std::string &distinctName, const SymbolVector *parameters);
60   evaluate::StructureConstructor DescribeComponent(
61       const Symbol &, const ProcEntityDetails &, Scope &);
62   bool InitializeDataPointer(evaluate::StructureConstructorValues &,
63       const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
64       Scope &dtScope, const std::string &distinctName);
65   evaluate::StructureConstructor PackageIntValue(
66       const SomeExpr &genre, std::int64_t = 0) const;
67   SomeExpr PackageIntValueExpr(const SomeExpr &genre, std::int64_t = 0) const;
68   std::vector<const Symbol *> CollectBindings(const Scope &dtScope) const;
69   std::vector<evaluate::StructureConstructor> DescribeBindings(
70       const Scope &dtScope, Scope &);
71   void DescribeGeneric(
72       const GenericDetails &, std::map<int, evaluate::StructureConstructor> &);
73   void DescribeSpecialProc(std::map<int, evaluate::StructureConstructor> &,
74       const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
75       std::optional<GenericKind::DefinedIo>);
76   void IncorporateDefinedIoGenericInterfaces(
77       std::map<int, evaluate::StructureConstructor> &, GenericKind::DefinedIo,
78       const Scope *);
79 
80   // Instantiated for ParamValue and Bound
81   template <typename A>
GetValue(const A & x,const SymbolVector * parameters)82   evaluate::StructureConstructor GetValue(
83       const A &x, const SymbolVector *parameters) {
84     if (x.isExplicit()) {
85       return GetValue(x.GetExplicit(), parameters);
86     } else {
87       return PackageIntValue(deferredEnum_);
88     }
89   }
90 
91   // Specialization for optional<Expr<SomeInteger and SubscriptInteger>>
92   template <typename T>
GetValue(const std::optional<evaluate::Expr<T>> & expr,const SymbolVector * parameters)93   evaluate::StructureConstructor GetValue(
94       const std::optional<evaluate::Expr<T>> &expr,
95       const SymbolVector *parameters) {
96     if (auto constValue{evaluate::ToInt64(expr)}) {
97       return PackageIntValue(explicitEnum_, *constValue);
98     }
99     if (expr) {
100       if (parameters) {
101         if (const Symbol * lenParam{evaluate::ExtractBareLenParameter(*expr)}) {
102           return PackageIntValue(
103               lenParameterEnum_, FindLenParameterIndex(*parameters, *lenParam));
104         }
105       }
106       // TODO: Replace a specification expression requiring actual operations
107       // with a reference to a new anonymous LEN type parameter whose default
108       // value captures the expression.  This replacement must take place when
109       // the type is declared so that the new LEN type parameters appear in
110       // all instantiations and structure constructors.
111       context_.Say(location_,
112           "derived type specification expression '%s' that is neither constant nor a length type parameter"_todo_en_US,
113           expr->AsFortran());
114     }
115     return PackageIntValue(deferredEnum_);
116   }
117 
118   SemanticsContext &context_;
119   RuntimeDerivedTypeTables &tables_;
120   std::map<const Symbol *, SymbolVector> orderedTypeParameters_;
121 
122   const DeclTypeSpec &derivedTypeSchema_; // TYPE(DerivedType)
123   const DeclTypeSpec &componentSchema_; // TYPE(Component)
124   const DeclTypeSpec &procPtrSchema_; // TYPE(ProcPtrComponent)
125   const DeclTypeSpec &valueSchema_; // TYPE(Value)
126   const DeclTypeSpec &bindingSchema_; // TYPE(Binding)
127   const DeclTypeSpec &specialSchema_; // TYPE(SpecialBinding)
128   SomeExpr deferredEnum_; // Value::Genre::Deferred
129   SomeExpr explicitEnum_; // Value::Genre::Explicit
130   SomeExpr lenParameterEnum_; // Value::Genre::LenParameter
131   SomeExpr scalarAssignmentEnum_; // SpecialBinding::Which::ScalarAssignment
132   SomeExpr
133       elementalAssignmentEnum_; // SpecialBinding::Which::ElementalAssignment
134   SomeExpr readFormattedEnum_; // SpecialBinding::Which::ReadFormatted
135   SomeExpr readUnformattedEnum_; // SpecialBinding::Which::ReadUnformatted
136   SomeExpr writeFormattedEnum_; // SpecialBinding::Which::WriteFormatted
137   SomeExpr writeUnformattedEnum_; // SpecialBinding::Which::WriteUnformatted
138   SomeExpr elementalFinalEnum_; // SpecialBinding::Which::ElementalFinal
139   SomeExpr assumedRankFinalEnum_; // SpecialBinding::Which::AssumedRankFinal
140   SomeExpr scalarFinalEnum_; // SpecialBinding::Which::ScalarFinal
141   parser::CharBlock location_;
142   std::set<const Scope *> ignoreScopes_;
143 };
144 
RuntimeTableBuilder(SemanticsContext & c,RuntimeDerivedTypeTables & t)145 RuntimeTableBuilder::RuntimeTableBuilder(
146     SemanticsContext &c, RuntimeDerivedTypeTables &t)
147     : context_{c}, tables_{t}, derivedTypeSchema_{GetSchema("derivedtype")},
148       componentSchema_{GetSchema("component")}, procPtrSchema_{GetSchema(
149                                                     "procptrcomponent")},
150       valueSchema_{GetSchema("value")}, bindingSchema_{GetSchema("binding")},
151       specialSchema_{GetSchema("specialbinding")}, deferredEnum_{GetEnumValue(
152                                                        "deferred")},
153       explicitEnum_{GetEnumValue("explicit")}, lenParameterEnum_{GetEnumValue(
154                                                    "lenparameter")},
155       scalarAssignmentEnum_{GetEnumValue("scalarassignment")},
156       elementalAssignmentEnum_{GetEnumValue("elementalassignment")},
157       readFormattedEnum_{GetEnumValue("readformatted")},
158       readUnformattedEnum_{GetEnumValue("readunformatted")},
159       writeFormattedEnum_{GetEnumValue("writeformatted")},
160       writeUnformattedEnum_{GetEnumValue("writeunformatted")},
161       elementalFinalEnum_{GetEnumValue("elementalfinal")},
162       assumedRankFinalEnum_{GetEnumValue("assumedrankfinal")},
163       scalarFinalEnum_{GetEnumValue("scalarfinal")} {
164   ignoreScopes_.insert(tables_.schemata);
165 }
166 
DescribeTypes(Scope & scope,bool inSchemata)167 void RuntimeTableBuilder::DescribeTypes(Scope &scope, bool inSchemata) {
168   inSchemata |= ignoreScopes_.find(&scope) != ignoreScopes_.end();
169   if (scope.IsDerivedType()) {
170     if (!inSchemata) { // don't loop trying to describe a schema
171       DescribeType(scope);
172     }
173   } else {
174     scope.InstantiateDerivedTypes();
175   }
176   for (Scope &child : scope.children()) {
177     DescribeTypes(child, inSchemata);
178   }
179 }
180 
181 // Returns derived type instantiation's parameters in declaration order
GetTypeParameters(const Symbol & symbol)182 const SymbolVector *RuntimeTableBuilder::GetTypeParameters(
183     const Symbol &symbol) {
184   auto iter{orderedTypeParameters_.find(&symbol)};
185   if (iter != orderedTypeParameters_.end()) {
186     return &iter->second;
187   } else {
188     return &orderedTypeParameters_
189                 .emplace(&symbol, OrderParameterDeclarations(symbol))
190                 .first->second;
191   }
192 }
193 
GetContainingNonDerivedScope(Scope & scope)194 static Scope &GetContainingNonDerivedScope(Scope &scope) {
195   Scope *p{&scope};
196   while (p->IsDerivedType()) {
197     p = &p->parent();
198   }
199   return *p;
200 }
201 
GetSchemaField(const DerivedTypeSpec & derived,const std::string & name)202 static const Symbol &GetSchemaField(
203     const DerivedTypeSpec &derived, const std::string &name) {
204   const Scope &scope{
205       DEREF(derived.scope() ? derived.scope() : derived.typeSymbol().scope())};
206   auto iter{scope.find(SourceName(name))};
207   CHECK(iter != scope.end());
208   return *iter->second;
209 }
210 
GetSchemaField(const DeclTypeSpec & derived,const std::string & name)211 static const Symbol &GetSchemaField(
212     const DeclTypeSpec &derived, const std::string &name) {
213   return GetSchemaField(DEREF(derived.AsDerived()), name);
214 }
215 
AddValue(evaluate::StructureConstructorValues & values,const DeclTypeSpec & spec,const std::string & name,SomeExpr && x)216 static evaluate::StructureConstructorValues &AddValue(
217     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
218     const std::string &name, SomeExpr &&x) {
219   values.emplace(GetSchemaField(spec, name), std::move(x));
220   return values;
221 }
222 
AddValue(evaluate::StructureConstructorValues & values,const DeclTypeSpec & spec,const std::string & name,const SomeExpr & x)223 static evaluate::StructureConstructorValues &AddValue(
224     evaluate::StructureConstructorValues &values, const DeclTypeSpec &spec,
225     const std::string &name, const SomeExpr &x) {
226   values.emplace(GetSchemaField(spec, name), x);
227   return values;
228 }
229 
IntToExpr(std::int64_t n)230 static SomeExpr IntToExpr(std::int64_t n) {
231   return evaluate::AsGenericExpr(evaluate::ExtentExpr{n});
232 }
233 
Structure(const DeclTypeSpec & spec,evaluate::StructureConstructorValues && values)234 static evaluate::StructureConstructor Structure(
235     const DeclTypeSpec &spec, evaluate::StructureConstructorValues &&values) {
236   return {DEREF(spec.AsDerived()), std::move(values)};
237 }
238 
StructureExpr(evaluate::StructureConstructor && x)239 static SomeExpr StructureExpr(evaluate::StructureConstructor &&x) {
240   return SomeExpr{evaluate::Expr<evaluate::SomeDerived>{std::move(x)}};
241 }
242 
GetIntegerKind(const Symbol & symbol)243 static int GetIntegerKind(const Symbol &symbol) {
244   auto dyType{evaluate::DynamicType::From(symbol)};
245   CHECK(dyType && dyType->category() == TypeCategory::Integer);
246   return dyType->kind();
247 }
248 
SetReadOnlyCompilerCreatedFlags(Symbol & symbol)249 static void SetReadOnlyCompilerCreatedFlags(Symbol &symbol) {
250   symbol.set(Symbol::Flag::CompilerCreated);
251   // Runtime type info symbols may have types that are incompatible with the
252   // PARAMETER attribute (the main issue is that they may be TARGET, and normal
253   // Fortran parameters cannot be TARGETs).
254   if (symbol.has<semantics::ObjectEntityDetails>() ||
255       symbol.has<semantics::ProcEntityDetails>()) {
256     symbol.set(Symbol::Flag::ReadOnly);
257   }
258 }
259 
260 // Save a rank-1 array constant of some numeric type as an
261 // initialized data object in a scope.
262 template <typename T>
SaveNumericPointerTarget(Scope & scope,SourceName name,std::vector<typename T::Scalar> && x)263 static SomeExpr SaveNumericPointerTarget(
264     Scope &scope, SourceName name, std::vector<typename T::Scalar> &&x) {
265   if (x.empty()) {
266     return SomeExpr{evaluate::NullPointer{}};
267   } else {
268     ObjectEntityDetails object;
269     if (const auto *spec{scope.FindType(
270             DeclTypeSpec{NumericTypeSpec{T::category, KindExpr{T::kind}}})}) {
271       object.set_type(*spec);
272     } else {
273       object.set_type(scope.MakeNumericType(T::category, KindExpr{T::kind}));
274     }
275     auto elements{static_cast<evaluate::ConstantSubscript>(x.size())};
276     ArraySpec arraySpec;
277     arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{elements - 1}));
278     object.set_shape(arraySpec);
279     object.set_init(evaluate::AsGenericExpr(evaluate::Constant<T>{
280         std::move(x), evaluate::ConstantSubscripts{elements}}));
281     Symbol &symbol{*scope
282                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
283                             std::move(object))
284                         .first->second};
285     SetReadOnlyCompilerCreatedFlags(symbol);
286     return evaluate::AsGenericExpr(
287         evaluate::Expr<T>{evaluate::Designator<T>{symbol}});
288   }
289 }
290 
291 // Save an arbitrarily shaped array constant of some derived type
292 // as an initialized data object in a scope.
SaveDerivedPointerTarget(Scope & scope,SourceName name,std::vector<evaluate::StructureConstructor> && x,evaluate::ConstantSubscripts && shape)293 static SomeExpr SaveDerivedPointerTarget(Scope &scope, SourceName name,
294     std::vector<evaluate::StructureConstructor> &&x,
295     evaluate::ConstantSubscripts &&shape) {
296   if (x.empty()) {
297     return SomeExpr{evaluate::NullPointer{}};
298   } else {
299     const auto &derivedType{x.front().GetType().GetDerivedTypeSpec()};
300     ObjectEntityDetails object;
301     DeclTypeSpec typeSpec{DeclTypeSpec::TypeDerived, derivedType};
302     if (const DeclTypeSpec * spec{scope.FindType(typeSpec)}) {
303       object.set_type(*spec);
304     } else {
305       object.set_type(scope.MakeDerivedType(
306           DeclTypeSpec::TypeDerived, common::Clone(derivedType)));
307     }
308     if (!shape.empty()) {
309       ArraySpec arraySpec;
310       for (auto n : shape) {
311         arraySpec.push_back(ShapeSpec::MakeExplicit(Bound{0}, Bound{n - 1}));
312       }
313       object.set_shape(arraySpec);
314     }
315     object.set_init(
316         evaluate::AsGenericExpr(evaluate::Constant<evaluate::SomeDerived>{
317             derivedType, std::move(x), std::move(shape)}));
318     Symbol &symbol{*scope
319                         .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
320                             std::move(object))
321                         .first->second};
322     SetReadOnlyCompilerCreatedFlags(symbol);
323     return evaluate::AsGenericExpr(
324         evaluate::Designator<evaluate::SomeDerived>{symbol});
325   }
326 }
327 
SaveObjectInit(Scope & scope,SourceName name,const ObjectEntityDetails & object)328 static SomeExpr SaveObjectInit(
329     Scope &scope, SourceName name, const ObjectEntityDetails &object) {
330   Symbol &symbol{*scope
331                       .try_emplace(name, Attrs{Attr::TARGET, Attr::SAVE},
332                           ObjectEntityDetails{object})
333                       .first->second};
334   CHECK(symbol.get<ObjectEntityDetails>().init().has_value());
335   SetReadOnlyCompilerCreatedFlags(symbol);
336   return evaluate::AsGenericExpr(
337       evaluate::Designator<evaluate::SomeDerived>{symbol});
338 }
339 
IntExpr(std::int64_t n)340 template <int KIND> static SomeExpr IntExpr(std::int64_t n) {
341   return evaluate::AsGenericExpr(
342       evaluate::Constant<evaluate::Type<TypeCategory::Integer, KIND>>{n});
343 }
344 
GetSuffixIfTypeKindParameters(const DerivedTypeSpec & derivedTypeSpec,const SymbolVector * parameters)345 static std::optional<std::string> GetSuffixIfTypeKindParameters(
346     const DerivedTypeSpec &derivedTypeSpec, const SymbolVector *parameters) {
347   if (parameters) {
348     std::optional<std::string> suffix;
349     for (SymbolRef ref : *parameters) {
350       const auto &tpd{ref->get<TypeParamDetails>()};
351       if (tpd.attr() == common::TypeParamAttr::Kind) {
352         if (const auto *pv{derivedTypeSpec.FindParameter(ref->name())}) {
353           if (pv->GetExplicit()) {
354             if (auto instantiatedValue{evaluate::ToInt64(*pv->GetExplicit())}) {
355               if (suffix.has_value()) {
356                 *suffix += "."s + std::to_string(*instantiatedValue);
357               } else {
358                 suffix = "."s + std::to_string(*instantiatedValue);
359               }
360             }
361           }
362         }
363       }
364     }
365     return suffix;
366   }
367   return std::nullopt;
368 }
369 
DescribeType(Scope & dtScope)370 const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
371   if (const Symbol * info{dtScope.runtimeDerivedTypeDescription()}) {
372     return info;
373   }
374   const DerivedTypeSpec *derivedTypeSpec{dtScope.derivedTypeSpec()};
375   if (!derivedTypeSpec && !dtScope.IsDerivedTypeWithKindParameter() &&
376       dtScope.symbol()) {
377     // This derived type was declared (obviously, there's a Scope) but never
378     // used in this compilation (no instantiated DerivedTypeSpec points here).
379     // Create a DerivedTypeSpec now for it so that ComponentIterator
380     // will work. This covers the case of a derived type that's declared in
381     // a module but used only by clients and submodules, enabling the
382     // run-time "no initialization needed here" flag to work.
383     DerivedTypeSpec derived{dtScope.symbol()->name(), *dtScope.symbol()};
384     if (const SymbolVector *
385         lenParameters{GetTypeParameters(*dtScope.symbol())}) {
386       // Create dummy deferred values for the length parameters so that the
387       // DerivedTypeSpec is complete and can be used in helpers.
388       for (SymbolRef lenParam : *lenParameters) {
389         (void)lenParam;
390         derived.AddRawParamValue(
391             std::nullopt, ParamValue::Deferred(common::TypeParamAttr::Len));
392       }
393       derived.CookParameters(context_.foldingContext());
394     }
395     DeclTypeSpec &decl{
396         dtScope.MakeDerivedType(DeclTypeSpec::TypeDerived, std::move(derived))};
397     derivedTypeSpec = &decl.derivedTypeSpec();
398   }
399   const Symbol *dtSymbol{
400       derivedTypeSpec ? &derivedTypeSpec->typeSymbol() : dtScope.symbol()};
401   if (!dtSymbol) {
402     return nullptr;
403   }
404   auto locationRestorer{common::ScopedSet(location_, dtSymbol->name())};
405   // Check for an existing description that can be imported from a USE'd module
406   std::string typeName{dtSymbol->name().ToString()};
407   if (typeName.empty() ||
408       (typeName.front() == '.' && !context_.IsTempName(typeName))) {
409     return nullptr;
410   }
411   const SymbolVector *parameters{GetTypeParameters(*dtSymbol)};
412   std::string distinctName{typeName};
413   if (&dtScope != dtSymbol->scope() && derivedTypeSpec) {
414     // Only create new type descriptions for different kind parameter values.
415     // Type with different length parameters/same kind parameters can all
416     // share the same type description available in the current scope.
417     if (auto suffix{
418             GetSuffixIfTypeKindParameters(*derivedTypeSpec, parameters)}) {
419       distinctName += *suffix;
420     }
421   }
422   std::string dtDescName{".dt."s + distinctName};
423   Scope *dtSymbolScope{const_cast<Scope *>(dtSymbol->scope())};
424   Scope &scope{
425       GetContainingNonDerivedScope(dtSymbolScope ? *dtSymbolScope : dtScope)};
426   if (const auto it{scope.find(SourceName{dtDescName})}; it != scope.end()) {
427     dtScope.set_runtimeDerivedTypeDescription(*it->second);
428     return &*it->second;
429   }
430 
431   // Create a new description object before populating it so that mutual
432   // references will work as pointer targets.
433   Symbol &dtObject{CreateObject(dtDescName, derivedTypeSchema_, scope)};
434   dtScope.set_runtimeDerivedTypeDescription(dtObject);
435   evaluate::StructureConstructorValues dtValues;
436   AddValue(dtValues, derivedTypeSchema_, "name"s,
437       SaveNameAsPointerTarget(scope, typeName));
438   bool isPDTdefinitionWithKindParameters{
439       !derivedTypeSpec && dtScope.IsDerivedTypeWithKindParameter()};
440   if (!isPDTdefinitionWithKindParameters) {
441     auto sizeInBytes{static_cast<common::ConstantSubscript>(dtScope.size())};
442     if (auto alignment{dtScope.alignment().value_or(0)}) {
443       sizeInBytes += alignment - 1;
444       sizeInBytes /= alignment;
445       sizeInBytes *= alignment;
446     }
447     AddValue(
448         dtValues, derivedTypeSchema_, "sizeinbytes"s, IntToExpr(sizeInBytes));
449   }
450   bool isPDTinstantiation{derivedTypeSpec && &dtScope != dtSymbol->scope()};
451   if (isPDTinstantiation) {
452     // is PDT instantiation
453     const Symbol *uninstDescObject{
454         DescribeType(DEREF(const_cast<Scope *>(dtSymbol->scope())))};
455     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
456         evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
457             evaluate::Designator<evaluate::SomeDerived>{
458                 DEREF(uninstDescObject)}}));
459   } else {
460     AddValue(dtValues, derivedTypeSchema_, "uninstantiated"s,
461         SomeExpr{evaluate::NullPointer{}});
462   }
463   using Int8 = evaluate::Type<TypeCategory::Integer, 8>;
464   using Int1 = evaluate::Type<TypeCategory::Integer, 1>;
465   std::vector<Int8::Scalar> kinds;
466   std::vector<Int1::Scalar> lenKinds;
467   if (parameters) {
468     // Package the derived type's parameters in declaration order for
469     // each category of parameter.  KIND= type parameters are described
470     // by their instantiated (or default) values, while LEN= type
471     // parameters are described by their INTEGER kinds.
472     for (SymbolRef ref : *parameters) {
473       const auto &tpd{ref->get<TypeParamDetails>()};
474       if (tpd.attr() == common::TypeParamAttr::Kind) {
475         auto value{evaluate::ToInt64(tpd.init()).value_or(0)};
476         if (derivedTypeSpec) {
477           if (const auto *pv{derivedTypeSpec->FindParameter(ref->name())}) {
478             if (pv->GetExplicit()) {
479               if (auto instantiatedValue{
480                       evaluate::ToInt64(*pv->GetExplicit())}) {
481                 value = *instantiatedValue;
482               }
483             }
484           }
485         }
486         kinds.emplace_back(value);
487       } else { // LEN= parameter
488         lenKinds.emplace_back(GetIntegerKind(*ref));
489       }
490     }
491   }
492   AddValue(dtValues, derivedTypeSchema_, "kindparameter"s,
493       SaveNumericPointerTarget<Int8>(
494           scope, SaveObjectName(".kp."s + distinctName), std::move(kinds)));
495   AddValue(dtValues, derivedTypeSchema_, "lenparameterkind"s,
496       SaveNumericPointerTarget<Int1>(
497           scope, SaveObjectName(".lpk."s + distinctName), std::move(lenKinds)));
498   // Traverse the components of the derived type
499   if (!isPDTdefinitionWithKindParameters) {
500     std::vector<const Symbol *> dataComponentSymbols;
501     std::vector<evaluate::StructureConstructor> procPtrComponents;
502     std::map<int, evaluate::StructureConstructor> specials;
503     for (const auto &pair : dtScope) {
504       const Symbol &symbol{*pair.second};
505       auto locationRestorer{common::ScopedSet(location_, symbol.name())};
506       common::visit(
507           common::visitors{
508               [&](const TypeParamDetails &) {
509                 // already handled above in declaration order
510               },
511               [&](const ObjectEntityDetails &) {
512                 dataComponentSymbols.push_back(&symbol);
513               },
514               [&](const ProcEntityDetails &proc) {
515                 if (IsProcedurePointer(symbol)) {
516                   procPtrComponents.emplace_back(
517                       DescribeComponent(symbol, proc, scope));
518                 }
519               },
520               [&](const ProcBindingDetails &) { // handled in a later pass
521               },
522               [&](const GenericDetails &generic) {
523                 DescribeGeneric(generic, specials);
524               },
525               [&](const auto &) {
526                 common::die(
527                     "unexpected details on symbol '%s' in derived type scope",
528                     symbol.name().ToString().c_str());
529               },
530           },
531           symbol.details());
532     }
533     // Sort the data component symbols by offset before emitting them
534     std::sort(dataComponentSymbols.begin(), dataComponentSymbols.end(),
535         [](const Symbol *x, const Symbol *y) {
536           return x->offset() < y->offset();
537         });
538     std::vector<evaluate::StructureConstructor> dataComponents;
539     for (const Symbol *symbol : dataComponentSymbols) {
540       auto locationRestorer{common::ScopedSet(location_, symbol->name())};
541       dataComponents.emplace_back(
542           DescribeComponent(*symbol, symbol->get<ObjectEntityDetails>(), scope,
543               dtScope, distinctName, parameters));
544     }
545     AddValue(dtValues, derivedTypeSchema_, "component"s,
546         SaveDerivedPointerTarget(scope, SaveObjectName(".c."s + distinctName),
547             std::move(dataComponents),
548             evaluate::ConstantSubscripts{
549                 static_cast<evaluate::ConstantSubscript>(
550                     dataComponents.size())}));
551     AddValue(dtValues, derivedTypeSchema_, "procptr"s,
552         SaveDerivedPointerTarget(scope, SaveObjectName(".p."s + distinctName),
553             std::move(procPtrComponents),
554             evaluate::ConstantSubscripts{
555                 static_cast<evaluate::ConstantSubscript>(
556                     procPtrComponents.size())}));
557     // Compile the "vtable" of type-bound procedure bindings
558     std::vector<evaluate::StructureConstructor> bindings{
559         DescribeBindings(dtScope, scope)};
560     AddValue(dtValues, derivedTypeSchema_, "binding"s,
561         SaveDerivedPointerTarget(scope, SaveObjectName(".v."s + distinctName),
562             std::move(bindings),
563             evaluate::ConstantSubscripts{
564                 static_cast<evaluate::ConstantSubscript>(bindings.size())}));
565     // Describe "special" bindings to defined assignments, FINAL subroutines,
566     // and user-defined derived type I/O subroutines.
567     const DerivedTypeDetails &dtDetails{dtSymbol->get<DerivedTypeDetails>()};
568     for (const auto &pair : dtDetails.finals()) {
569       DescribeSpecialProc(
570           specials, *pair.second, false /*!isAssignment*/, true, std::nullopt);
571     }
572     IncorporateDefinedIoGenericInterfaces(
573         specials, GenericKind::DefinedIo::ReadFormatted, &scope);
574     IncorporateDefinedIoGenericInterfaces(
575         specials, GenericKind::DefinedIo::ReadUnformatted, &scope);
576     IncorporateDefinedIoGenericInterfaces(
577         specials, GenericKind::DefinedIo::WriteFormatted, &scope);
578     IncorporateDefinedIoGenericInterfaces(
579         specials, GenericKind::DefinedIo::WriteUnformatted, &scope);
580     // Pack the special procedure bindings in ascending order of their "which"
581     // code values, and compile a little-endian bit-set of those codes for
582     // use in O(1) look-up at run time.
583     std::vector<evaluate::StructureConstructor> sortedSpecials;
584     std::uint32_t specialBitSet{0};
585     for (auto &pair : specials) {
586       auto bit{std::uint32_t{1} << pair.first};
587       CHECK(!(specialBitSet & bit));
588       specialBitSet |= bit;
589       sortedSpecials.emplace_back(std::move(pair.second));
590     }
591     AddValue(dtValues, derivedTypeSchema_, "special"s,
592         SaveDerivedPointerTarget(scope, SaveObjectName(".s."s + distinctName),
593             std::move(sortedSpecials),
594             evaluate::ConstantSubscripts{
595                 static_cast<evaluate::ConstantSubscript>(specials.size())}));
596     AddValue(dtValues, derivedTypeSchema_, "specialbitset"s,
597         IntExpr<4>(specialBitSet));
598     // Note the presence/absence of a parent component
599     AddValue(dtValues, derivedTypeSchema_, "hasparent"s,
600         IntExpr<1>(dtScope.GetDerivedTypeParent() != nullptr));
601     // To avoid wasting run time attempting to initialize derived type
602     // instances without any initialized components, analyze the type
603     // and set a flag if there's nothing to do for it at run time.
604     AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s,
605         IntExpr<1>(
606             derivedTypeSpec && !derivedTypeSpec->HasDefaultInitialization()));
607     // Similarly, a flag to short-circuit destruction when not needed.
608     AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s,
609         IntExpr<1>(derivedTypeSpec && !derivedTypeSpec->HasDestruction()));
610     // Similarly, a flag to short-circuit finalization when not needed.
611     AddValue(dtValues, derivedTypeSchema_, "nofinalizationneeded"s,
612         IntExpr<1>(derivedTypeSpec && !IsFinalizable(*derivedTypeSpec)));
613   }
614   dtObject.get<ObjectEntityDetails>().set_init(MaybeExpr{
615       StructureExpr(Structure(derivedTypeSchema_, std::move(dtValues)))});
616   return &dtObject;
617 }
618 
GetSymbol(const Scope & schemata,SourceName name)619 static const Symbol &GetSymbol(const Scope &schemata, SourceName name) {
620   auto iter{schemata.find(name)};
621   CHECK(iter != schemata.end());
622   const Symbol &symbol{*iter->second};
623   return symbol;
624 }
625 
GetSchemaSymbol(const char * name) const626 const Symbol &RuntimeTableBuilder::GetSchemaSymbol(const char *name) const {
627   return GetSymbol(
628       DEREF(tables_.schemata), SourceName{name, std::strlen(name)});
629 }
630 
GetSchema(const char * schemaName) const631 const DeclTypeSpec &RuntimeTableBuilder::GetSchema(
632     const char *schemaName) const {
633   Scope &schemata{DEREF(tables_.schemata)};
634   SourceName name{schemaName, std::strlen(schemaName)};
635   const Symbol &symbol{GetSymbol(schemata, name)};
636   CHECK(symbol.has<DerivedTypeDetails>());
637   CHECK(symbol.scope());
638   CHECK(symbol.scope()->IsDerivedType());
639   const DeclTypeSpec *spec{nullptr};
640   if (symbol.scope()->derivedTypeSpec()) {
641     DeclTypeSpec typeSpec{
642         DeclTypeSpec::TypeDerived, *symbol.scope()->derivedTypeSpec()};
643     spec = schemata.FindType(typeSpec);
644   }
645   if (!spec) {
646     DeclTypeSpec typeSpec{
647         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol}};
648     spec = schemata.FindType(typeSpec);
649   }
650   if (!spec) {
651     spec = &schemata.MakeDerivedType(
652         DeclTypeSpec::TypeDerived, DerivedTypeSpec{name, symbol});
653   }
654   CHECK(spec->AsDerived());
655   return *spec;
656 }
657 
GetEnumValue(const char * name) const658 SomeExpr RuntimeTableBuilder::GetEnumValue(const char *name) const {
659   const Symbol &symbol{GetSchemaSymbol(name)};
660   auto value{evaluate::ToInt64(symbol.get<ObjectEntityDetails>().init())};
661   CHECK(value.has_value());
662   return IntExpr<1>(*value);
663 }
664 
CreateObject(const std::string & name,const DeclTypeSpec & type,Scope & scope)665 Symbol &RuntimeTableBuilder::CreateObject(
666     const std::string &name, const DeclTypeSpec &type, Scope &scope) {
667   ObjectEntityDetails object;
668   object.set_type(type);
669   auto pair{scope.try_emplace(SaveObjectName(name),
670       Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))};
671   CHECK(pair.second);
672   Symbol &result{*pair.first->second};
673   SetReadOnlyCompilerCreatedFlags(result);
674   return result;
675 }
676 
SaveObjectName(const std::string & name)677 SourceName RuntimeTableBuilder::SaveObjectName(const std::string &name) {
678   return *tables_.names.insert(name).first;
679 }
680 
SaveNameAsPointerTarget(Scope & scope,const std::string & name)681 SomeExpr RuntimeTableBuilder::SaveNameAsPointerTarget(
682     Scope &scope, const std::string &name) {
683   CHECK(!name.empty());
684   CHECK(name.front() != '.' || context_.IsTempName(name));
685   ObjectEntityDetails object;
686   auto len{static_cast<common::ConstantSubscript>(name.size())};
687   if (const auto *spec{scope.FindType(DeclTypeSpec{CharacterTypeSpec{
688           ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}}})}) {
689     object.set_type(*spec);
690   } else {
691     object.set_type(scope.MakeCharacterType(
692         ParamValue{len, common::TypeParamAttr::Len}, KindExpr{1}));
693   }
694   using evaluate::Ascii;
695   using AsciiExpr = evaluate::Expr<Ascii>;
696   object.set_init(evaluate::AsGenericExpr(AsciiExpr{name}));
697   Symbol &symbol{*scope
698                       .try_emplace(SaveObjectName(".n."s + name),
699                           Attrs{Attr::TARGET, Attr::SAVE}, std::move(object))
700                       .first->second};
701   SetReadOnlyCompilerCreatedFlags(symbol);
702   return evaluate::AsGenericExpr(
703       AsciiExpr{evaluate::Designator<Ascii>{symbol}});
704 }
705 
DescribeComponent(const Symbol & symbol,const ObjectEntityDetails & object,Scope & scope,Scope & dtScope,const std::string & distinctName,const SymbolVector * parameters)706 evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
707     const Symbol &symbol, const ObjectEntityDetails &object, Scope &scope,
708     Scope &dtScope, const std::string &distinctName,
709     const SymbolVector *parameters) {
710   evaluate::StructureConstructorValues values;
711   auto &foldingContext{context_.foldingContext()};
712   auto typeAndShape{evaluate::characteristics::TypeAndShape::Characterize(
713       symbol, foldingContext)};
714   CHECK(typeAndShape.has_value());
715   auto dyType{typeAndShape->type()};
716   const auto &shape{typeAndShape->shape()};
717   AddValue(values, componentSchema_, "name"s,
718       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
719   AddValue(values, componentSchema_, "category"s,
720       IntExpr<1>(static_cast<int>(dyType.category())));
721   if (dyType.IsUnlimitedPolymorphic() ||
722       dyType.category() == TypeCategory::Derived) {
723     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(0));
724   } else {
725     AddValue(values, componentSchema_, "kind"s, IntExpr<1>(dyType.kind()));
726   }
727   AddValue(values, componentSchema_, "offset"s, IntExpr<8>(symbol.offset()));
728   // CHARACTER length
729   auto len{typeAndShape->LEN()};
730   if (const semantics::DerivedTypeSpec *
731       pdtInstance{dtScope.derivedTypeSpec()}) {
732     auto restorer{foldingContext.WithPDTInstance(*pdtInstance)};
733     len = Fold(foldingContext, std::move(len));
734   }
735   if (dyType.category() == TypeCategory::Character && len) {
736     // Ignore IDIM(x) (represented as MAX(0, x))
737     if (const auto *clamped{evaluate::UnwrapExpr<
738             evaluate::Extremum<evaluate::SubscriptInteger>>(*len)}) {
739       if (clamped->ordering == evaluate::Ordering::Greater &&
740           clamped->left() == evaluate::Expr<evaluate::SubscriptInteger>{0}) {
741         len = common::Clone(clamped->right());
742       }
743     }
744     AddValue(values, componentSchema_, "characterlen"s,
745         evaluate::AsGenericExpr(GetValue(len, parameters)));
746   } else {
747     AddValue(values, componentSchema_, "characterlen"s,
748         PackageIntValueExpr(deferredEnum_));
749   }
750   // Describe component's derived type
751   std::vector<evaluate::StructureConstructor> lenParams;
752   if (dyType.category() == TypeCategory::Derived &&
753       !dyType.IsUnlimitedPolymorphic()) {
754     const DerivedTypeSpec &spec{dyType.GetDerivedTypeSpec()};
755     Scope *derivedScope{const_cast<Scope *>(
756         spec.scope() ? spec.scope() : spec.typeSymbol().scope())};
757     const Symbol *derivedDescription{DescribeType(DEREF(derivedScope))};
758     AddValue(values, componentSchema_, "derived"s,
759         evaluate::AsGenericExpr(evaluate::Expr<evaluate::SomeDerived>{
760             evaluate::Designator<evaluate::SomeDerived>{
761                 DEREF(derivedDescription)}}));
762     // Package values of LEN parameters, if any
763     if (const SymbolVector * specParams{GetTypeParameters(spec.typeSymbol())}) {
764       for (SymbolRef ref : *specParams) {
765         const auto &tpd{ref->get<TypeParamDetails>()};
766         if (tpd.attr() == common::TypeParamAttr::Len) {
767           if (const ParamValue * paramValue{spec.FindParameter(ref->name())}) {
768             lenParams.emplace_back(GetValue(*paramValue, parameters));
769           } else {
770             lenParams.emplace_back(GetValue(tpd.init(), parameters));
771           }
772         }
773       }
774     }
775   } else {
776     // Subtle: a category of Derived with a null derived type pointer
777     // signifies CLASS(*)
778     AddValue(values, componentSchema_, "derived"s,
779         SomeExpr{evaluate::NullPointer{}});
780   }
781   // LEN type parameter values for the component's type
782   if (!lenParams.empty()) {
783     AddValue(values, componentSchema_, "lenvalue"s,
784         SaveDerivedPointerTarget(scope,
785             SaveObjectName(
786                 ".lv."s + distinctName + "."s + symbol.name().ToString()),
787             std::move(lenParams),
788             evaluate::ConstantSubscripts{
789                 static_cast<evaluate::ConstantSubscript>(lenParams.size())}));
790   } else {
791     AddValue(values, componentSchema_, "lenvalue"s,
792         SomeExpr{evaluate::NullPointer{}});
793   }
794   // Shape information
795   int rank{evaluate::GetRank(shape)};
796   AddValue(values, componentSchema_, "rank"s, IntExpr<1>(rank));
797   if (rank > 0 && !IsAllocatable(symbol) && !IsPointer(symbol)) {
798     std::vector<evaluate::StructureConstructor> bounds;
799     evaluate::NamedEntity entity{symbol};
800     for (int j{0}; j < rank; ++j) {
801       bounds.emplace_back(
802           GetValue(std::make_optional(
803                        evaluate::GetRawLowerBound(foldingContext, entity, j)),
804               parameters));
805       bounds.emplace_back(GetValue(
806           evaluate::GetRawUpperBound(foldingContext, entity, j), parameters));
807     }
808     AddValue(values, componentSchema_, "bounds"s,
809         SaveDerivedPointerTarget(scope,
810             SaveObjectName(
811                 ".b."s + distinctName + "."s + symbol.name().ToString()),
812             std::move(bounds), evaluate::ConstantSubscripts{2, rank}));
813   } else {
814     AddValue(
815         values, componentSchema_, "bounds"s, SomeExpr{evaluate::NullPointer{}});
816   }
817   // Default component initialization
818   bool hasDataInit{false};
819   if (IsAllocatable(symbol)) {
820     AddValue(values, componentSchema_, "genre"s, GetEnumValue("allocatable"));
821   } else if (IsPointer(symbol)) {
822     AddValue(values, componentSchema_, "genre"s, GetEnumValue("pointer"));
823     hasDataInit = InitializeDataPointer(
824         values, symbol, object, scope, dtScope, distinctName);
825   } else if (IsAutomatic(symbol)) {
826     AddValue(values, componentSchema_, "genre"s, GetEnumValue("automatic"));
827   } else {
828     AddValue(values, componentSchema_, "genre"s, GetEnumValue("data"));
829     hasDataInit = object.init().has_value();
830     if (hasDataInit) {
831       AddValue(values, componentSchema_, "initialization"s,
832           SaveObjectInit(scope,
833               SaveObjectName(
834                   ".di."s + distinctName + "."s + symbol.name().ToString()),
835               object));
836     }
837   }
838   if (!hasDataInit) {
839     AddValue(values, componentSchema_, "initialization"s,
840         SomeExpr{evaluate::NullPointer{}});
841   }
842   return {DEREF(componentSchema_.AsDerived()), std::move(values)};
843 }
844 
DescribeComponent(const Symbol & symbol,const ProcEntityDetails & proc,Scope & scope)845 evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
846     const Symbol &symbol, const ProcEntityDetails &proc, Scope &scope) {
847   evaluate::StructureConstructorValues values;
848   AddValue(values, procPtrSchema_, "name"s,
849       SaveNameAsPointerTarget(scope, symbol.name().ToString()));
850   AddValue(values, procPtrSchema_, "offset"s, IntExpr<8>(symbol.offset()));
851   if (auto init{proc.init()}; init && *init) {
852     AddValue(values, procPtrSchema_, "initialization"s,
853         SomeExpr{evaluate::ProcedureDesignator{**init}});
854   } else {
855     AddValue(values, procPtrSchema_, "initialization"s,
856         SomeExpr{evaluate::NullPointer{}});
857   }
858   return {DEREF(procPtrSchema_.AsDerived()), std::move(values)};
859 }
860 
861 // Create a static pointer object with the same initialization
862 // from whence the runtime can memcpy() the data pointer
863 // component initialization.
864 // Creates and interconnects the symbols, scopes, and types for
865 //   TYPE :: ptrDt
866 //     type, POINTER :: name
867 //   END TYPE
868 //   TYPE(ptrDt), TARGET, SAVE :: ptrInit = ptrDt(designator)
869 // and then initializes the original component by setting
870 //   initialization = ptrInit
871 // which takes the address of ptrInit because the type is C_PTR.
872 // This technique of wrapping the data pointer component into
873 // a derived type instance disables any reason for lowering to
874 // attempt to dereference the RHS of an initializer, thereby
875 // allowing the runtime to actually perform the initialization
876 // by means of a simple memcpy() of the wrapped descriptor in
877 // 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)878 bool RuntimeTableBuilder::InitializeDataPointer(
879     evaluate::StructureConstructorValues &values, const Symbol &symbol,
880     const ObjectEntityDetails &object, Scope &scope, Scope &dtScope,
881     const std::string &distinctName) {
882   if (object.init().has_value()) {
883     SourceName ptrDtName{SaveObjectName(
884         ".dp."s + distinctName + "."s + symbol.name().ToString())};
885     Symbol &ptrDtSym{
886         *scope.try_emplace(ptrDtName, Attrs{}, UnknownDetails{}).first->second};
887     SetReadOnlyCompilerCreatedFlags(ptrDtSym);
888     Scope &ptrDtScope{scope.MakeScope(Scope::Kind::DerivedType, &ptrDtSym)};
889     ignoreScopes_.insert(&ptrDtScope);
890     ObjectEntityDetails ptrDtObj;
891     ptrDtObj.set_type(DEREF(object.type()));
892     ptrDtObj.set_shape(object.shape());
893     Symbol &ptrDtComp{*ptrDtScope
894                            .try_emplace(symbol.name(), Attrs{Attr::POINTER},
895                                std::move(ptrDtObj))
896                            .first->second};
897     DerivedTypeDetails ptrDtDetails;
898     ptrDtDetails.add_component(ptrDtComp);
899     ptrDtSym.set_details(std::move(ptrDtDetails));
900     ptrDtSym.set_scope(&ptrDtScope);
901     DeclTypeSpec &ptrDtDeclType{
902         scope.MakeDerivedType(DeclTypeSpec::Category::TypeDerived,
903             DerivedTypeSpec{ptrDtName, ptrDtSym})};
904     DerivedTypeSpec &ptrDtDerived{DEREF(ptrDtDeclType.AsDerived())};
905     ptrDtDerived.set_scope(ptrDtScope);
906     ptrDtDerived.CookParameters(context_.foldingContext());
907     ptrDtDerived.Instantiate(scope);
908     ObjectEntityDetails ptrInitObj;
909     ptrInitObj.set_type(ptrDtDeclType);
910     evaluate::StructureConstructorValues ptrInitValues;
911     AddValue(
912         ptrInitValues, ptrDtDeclType, symbol.name().ToString(), *object.init());
913     ptrInitObj.set_init(evaluate::AsGenericExpr(
914         Structure(ptrDtDeclType, std::move(ptrInitValues))));
915     AddValue(values, componentSchema_, "initialization"s,
916         SaveObjectInit(scope,
917             SaveObjectName(
918                 ".di."s + distinctName + "."s + symbol.name().ToString()),
919             ptrInitObj));
920     return true;
921   } else {
922     return false;
923   }
924 }
925 
PackageIntValue(const SomeExpr & genre,std::int64_t n) const926 evaluate::StructureConstructor RuntimeTableBuilder::PackageIntValue(
927     const SomeExpr &genre, std::int64_t n) const {
928   evaluate::StructureConstructorValues xs;
929   AddValue(xs, valueSchema_, "genre"s, genre);
930   AddValue(xs, valueSchema_, "value"s, IntToExpr(n));
931   return Structure(valueSchema_, std::move(xs));
932 }
933 
PackageIntValueExpr(const SomeExpr & genre,std::int64_t n) const934 SomeExpr RuntimeTableBuilder::PackageIntValueExpr(
935     const SomeExpr &genre, std::int64_t n) const {
936   return StructureExpr(PackageIntValue(genre, n));
937 }
938 
CollectBindings(const Scope & dtScope) const939 std::vector<const Symbol *> RuntimeTableBuilder::CollectBindings(
940     const Scope &dtScope) const {
941   std::vector<const Symbol *> result;
942   std::map<SourceName, const Symbol *> localBindings;
943   // Collect local bindings
944   for (auto pair : dtScope) {
945     const Symbol &symbol{*pair.second};
946     if (symbol.has<ProcBindingDetails>()) {
947       localBindings.emplace(symbol.name(), &symbol);
948     }
949   }
950   if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) {
951     result = CollectBindings(*parentScope);
952     // Apply overrides from the local bindings of the extended type
953     for (auto iter{result.begin()}; iter != result.end(); ++iter) {
954       const Symbol &symbol{**iter};
955       auto overridden{localBindings.find(symbol.name())};
956       if (overridden != localBindings.end()) {
957         *iter = overridden->second;
958         localBindings.erase(overridden);
959       }
960     }
961   }
962   // Add remaining (non-overriding) local bindings in name order to the result
963   for (auto pair : localBindings) {
964     result.push_back(pair.second);
965   }
966   return result;
967 }
968 
969 std::vector<evaluate::StructureConstructor>
DescribeBindings(const Scope & dtScope,Scope & scope)970 RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) {
971   std::vector<evaluate::StructureConstructor> result;
972   for (const Symbol *symbol : CollectBindings(dtScope)) {
973     evaluate::StructureConstructorValues values;
974     AddValue(values, bindingSchema_, "proc"s,
975         SomeExpr{evaluate::ProcedureDesignator{
976             symbol->get<ProcBindingDetails>().symbol()}});
977     AddValue(values, bindingSchema_, "name"s,
978         SaveNameAsPointerTarget(scope, symbol->name().ToString()));
979     result.emplace_back(DEREF(bindingSchema_.AsDerived()), std::move(values));
980   }
981   return result;
982 }
983 
DescribeGeneric(const GenericDetails & generic,std::map<int,evaluate::StructureConstructor> & specials)984 void RuntimeTableBuilder::DescribeGeneric(const GenericDetails &generic,
985     std::map<int, evaluate::StructureConstructor> &specials) {
986   common::visit(common::visitors{
987                     [&](const GenericKind::OtherKind &k) {
988                       if (k == GenericKind::OtherKind::Assignment) {
989                         for (auto ref : generic.specificProcs()) {
990                           DescribeSpecialProc(specials, *ref, true,
991                               false /*!final*/, std::nullopt);
992                         }
993                       }
994                     },
995                     [&](const GenericKind::DefinedIo &io) {
996                       switch (io) {
997                       case GenericKind::DefinedIo::ReadFormatted:
998                       case GenericKind::DefinedIo::ReadUnformatted:
999                       case GenericKind::DefinedIo::WriteFormatted:
1000                       case GenericKind::DefinedIo::WriteUnformatted:
1001                         for (auto ref : generic.specificProcs()) {
1002                           DescribeSpecialProc(
1003                               specials, *ref, false, false /*!final*/, io);
1004                         }
1005                         break;
1006                       }
1007                     },
1008                     [](const auto &) {},
1009                 },
1010       generic.kind().u);
1011 }
1012 
DescribeSpecialProc(std::map<int,evaluate::StructureConstructor> & specials,const Symbol & specificOrBinding,bool isAssignment,bool isFinal,std::optional<GenericKind::DefinedIo> io)1013 void RuntimeTableBuilder::DescribeSpecialProc(
1014     std::map<int, evaluate::StructureConstructor> &specials,
1015     const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
1016     std::optional<GenericKind::DefinedIo> io) {
1017   const auto *binding{specificOrBinding.detailsIf<ProcBindingDetails>()};
1018   const Symbol &specific{*(binding ? &binding->symbol() : &specificOrBinding)};
1019   if (auto proc{evaluate::characteristics::Procedure::Characterize(
1020           specific, context_.foldingContext())}) {
1021     std::uint8_t isArgDescriptorSet{0};
1022     int argThatMightBeDescriptor{0};
1023     MaybeExpr which;
1024     if (isAssignment) {
1025       // Only type-bound asst's with the same type on both dummy arguments
1026       // are germane to the runtime, which needs only these to implement
1027       // component assignment as part of intrinsic assignment.
1028       // Non-type-bound generic INTERFACEs and assignments from distinct
1029       // types must not be used for component intrinsic assignment.
1030       CHECK(proc->dummyArguments.size() == 2);
1031       const auto t1{
1032           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1033                     &proc->dummyArguments[0].u))
1034               .type.type()};
1035       const auto t2{
1036           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
1037                     &proc->dummyArguments[1].u))
1038               .type.type()};
1039       if (!binding || t1.category() != TypeCategory::Derived ||
1040           t2.category() != TypeCategory::Derived ||
1041           t1.IsUnlimitedPolymorphic() || t2.IsUnlimitedPolymorphic() ||
1042           t1.GetDerivedTypeSpec() != t2.GetDerivedTypeSpec()) {
1043         return;
1044       }
1045       which = proc->IsElemental() ? elementalAssignmentEnum_
1046                                   : scalarAssignmentEnum_;
1047       if (binding && binding->passName() &&
1048           *binding->passName() == proc->dummyArguments[1].name) {
1049         argThatMightBeDescriptor = 1;
1050         isArgDescriptorSet |= 2;
1051       } else {
1052         argThatMightBeDescriptor = 2; // the non-passed-object argument
1053         isArgDescriptorSet |= 1;
1054       }
1055     } else if (isFinal) {
1056       CHECK(binding == nullptr); // FINALs are not bindings
1057       CHECK(proc->dummyArguments.size() == 1);
1058       if (proc->IsElemental()) {
1059         which = elementalFinalEnum_;
1060       } else {
1061         const auto &typeAndShape{
1062             std::get<evaluate::characteristics::DummyDataObject>(
1063                 proc->dummyArguments.at(0).u)
1064                 .type};
1065         if (typeAndShape.attrs().test(
1066                 evaluate::characteristics::TypeAndShape::Attr::AssumedRank)) {
1067           which = assumedRankFinalEnum_;
1068           isArgDescriptorSet |= 1;
1069         } else {
1070           which = scalarFinalEnum_;
1071           if (int rank{evaluate::GetRank(typeAndShape.shape())}; rank > 0) {
1072             argThatMightBeDescriptor = 1;
1073             which = IntExpr<1>(ToInt64(which).value() + rank);
1074           }
1075         }
1076       }
1077     } else { // user defined derived type I/O
1078       CHECK(proc->dummyArguments.size() >= 4);
1079       if (binding) {
1080         isArgDescriptorSet |= 1;
1081       }
1082       switch (io.value()) {
1083       case GenericKind::DefinedIo::ReadFormatted:
1084         which = readFormattedEnum_;
1085         break;
1086       case GenericKind::DefinedIo::ReadUnformatted:
1087         which = readUnformattedEnum_;
1088         break;
1089       case GenericKind::DefinedIo::WriteFormatted:
1090         which = writeFormattedEnum_;
1091         break;
1092       case GenericKind::DefinedIo::WriteUnformatted:
1093         which = writeUnformattedEnum_;
1094         break;
1095       }
1096     }
1097     if (argThatMightBeDescriptor != 0 &&
1098         !proc->dummyArguments.at(argThatMightBeDescriptor - 1)
1099              .CanBePassedViaImplicitInterface()) {
1100       isArgDescriptorSet |= 1 << (argThatMightBeDescriptor - 1);
1101     }
1102     evaluate::StructureConstructorValues values;
1103     auto index{evaluate::ToInt64(which)};
1104     CHECK(index.has_value());
1105     AddValue(
1106         values, specialSchema_, "which"s, SomeExpr{std::move(which.value())});
1107     AddValue(values, specialSchema_, "isargdescriptorset"s,
1108         IntExpr<1>(isArgDescriptorSet));
1109     AddValue(values, specialSchema_, "proc"s,
1110         SomeExpr{evaluate::ProcedureDesignator{specific}});
1111     auto pair{specials.try_emplace(
1112         *index, DEREF(specialSchema_.AsDerived()), std::move(values))};
1113     CHECK(pair.second); // ensure not already present
1114   }
1115 }
1116 
IncorporateDefinedIoGenericInterfaces(std::map<int,evaluate::StructureConstructor> & specials,GenericKind::DefinedIo definedIo,const Scope * scope)1117 void RuntimeTableBuilder::IncorporateDefinedIoGenericInterfaces(
1118     std::map<int, evaluate::StructureConstructor> &specials,
1119     GenericKind::DefinedIo definedIo, const Scope *scope) {
1120   SourceName name{GenericKind::AsFortran(definedIo)};
1121   for (; !scope->IsGlobal(); scope = &scope->parent()) {
1122     if (auto asst{scope->find(name)}; asst != scope->end()) {
1123       const Symbol &generic{asst->second->GetUltimate()};
1124       const auto &genericDetails{generic.get<GenericDetails>()};
1125       CHECK(std::holds_alternative<GenericKind::DefinedIo>(
1126           genericDetails.kind().u));
1127       CHECK(std::get<GenericKind::DefinedIo>(genericDetails.kind().u) ==
1128           definedIo);
1129       for (auto ref : genericDetails.specificProcs()) {
1130         DescribeSpecialProc(specials, *ref, false, false, definedIo);
1131       }
1132     }
1133   }
1134 }
1135 
BuildRuntimeDerivedTypeTables(SemanticsContext & context)1136 RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(
1137     SemanticsContext &context) {
1138   RuntimeDerivedTypeTables result;
1139   result.schemata = context.GetBuiltinModule(typeInfoBuiltinModule);
1140   if (result.schemata) {
1141     RuntimeTableBuilder builder{context, result};
1142     builder.DescribeTypes(context.globalScope(), false);
1143   }
1144   return result;
1145 }
1146 } // namespace Fortran::semantics
1147