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