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