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