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