1 //===-- lib/Semantics/symbol.cpp ------------------------------------------===// 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/symbol.h" 10 #include "flang/Common/idioms.h" 11 #include "flang/Evaluate/expression.h" 12 #include "flang/Semantics/scope.h" 13 #include "flang/Semantics/semantics.h" 14 #include "flang/Semantics/tools.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include <cstring> 17 #include <string> 18 #include <type_traits> 19 20 namespace Fortran::semantics { 21 22 template <typename T> 23 static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) { 24 if (x) { 25 os << ' ' << label << ':' << *x; 26 } 27 } 28 template <typename T> 29 static void DumpExpr(llvm::raw_ostream &os, const char *label, 30 const std::optional<evaluate::Expr<T>> &x) { 31 if (x) { 32 x->AsFortran(os << ' ' << label << ':'); 33 } 34 } 35 36 static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) { 37 if (x) { 38 os << ' ' << label; 39 } 40 } 41 42 static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) { 43 char sep{' '}; 44 for (const Symbol &elem : list) { 45 os << sep << elem.name(); 46 sep = ','; 47 } 48 } 49 50 static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) { 51 if (const auto *type{symbol.GetType()}) { 52 os << *type << ' '; 53 } 54 } 55 static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) { 56 if (type) { 57 os << ' ' << *type; 58 } 59 } 60 61 template <typename T> 62 static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) { 63 if (!list.empty()) { 64 os << ' ' << label << ':'; 65 char sep{' '}; 66 for (const auto &elem : list) { 67 os << sep << elem; 68 sep = ','; 69 } 70 } 71 } 72 73 void SubprogramDetails::set_moduleInterface(Symbol &symbol) { 74 CHECK(!moduleInterface_); 75 moduleInterface_ = &symbol; 76 } 77 78 const Scope *ModuleDetails::parent() const { 79 return isSubmodule_ && scope_ ? &scope_->parent() : nullptr; 80 } 81 const Scope *ModuleDetails::ancestor() const { 82 return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr; 83 } 84 void ModuleDetails::set_scope(const Scope *scope) { 85 CHECK(!scope_); 86 bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module}; 87 CHECK(isSubmodule_ == scopeIsSubmodule); 88 scope_ = scope; 89 } 90 91 llvm::raw_ostream &operator<<( 92 llvm::raw_ostream &os, const SubprogramDetails &x) { 93 DumpBool(os, "isInterface", x.isInterface_); 94 DumpBool(os, "dummy", x.isDummy_); 95 DumpOptional(os, "bindName", x.bindName()); 96 if (x.result_) { 97 DumpType(os << " result:", x.result()); 98 os << x.result_->name(); 99 if (!x.result_->attrs().empty()) { 100 os << ", " << x.result_->attrs(); 101 } 102 } 103 if (x.entryScope_) { 104 os << " entry"; 105 if (x.entryScope_->symbol()) { 106 os << " in " << x.entryScope_->symbol()->name(); 107 } 108 } 109 char sep{'('}; 110 os << ' '; 111 for (const Symbol *arg : x.dummyArgs_) { 112 os << sep; 113 sep = ','; 114 if (arg) { 115 DumpType(os, *arg); 116 os << arg->name(); 117 } else { 118 os << '*'; 119 } 120 } 121 os << (sep == '(' ? "()" : ")"); 122 if (x.stmtFunction_) { 123 os << " -> " << x.stmtFunction_->AsFortran(); 124 } 125 if (x.moduleInterface_) { 126 os << " moduleInterface: " << *x.moduleInterface_; 127 } 128 if (x.defaultIgnoreTKR_) { 129 os << " defaultIgnoreTKR"; 130 } 131 if (x.cudaSubprogramAttrs_) { 132 os << " cudaSubprogramAttrs: " 133 << common::EnumToString(*x.cudaSubprogramAttrs_); 134 } 135 if (!x.cudaLaunchBounds_.empty()) { 136 os << " cudaLaunchBounds:"; 137 for (auto x : x.cudaLaunchBounds_) { 138 os << ' ' << x; 139 } 140 } 141 if (!x.cudaClusterDims_.empty()) { 142 os << " cudaClusterDims:"; 143 for (auto x : x.cudaClusterDims_) { 144 os << ' ' << x; 145 } 146 } 147 return os; 148 } 149 150 void EntityDetails::set_type(const DeclTypeSpec &type) { 151 CHECK(!type_); 152 type_ = &type; 153 } 154 155 void AssocEntityDetails::set_rank(int rank) { rank_ = rank; } 156 void AssocEntityDetails::set_IsAssumedSize() { rank_ = isAssumedSize; } 157 void AssocEntityDetails::set_IsAssumedRank() { rank_ = isAssumedRank; } 158 void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; } 159 160 ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d) 161 : EntityDetails(std::move(d)) {} 162 163 void ObjectEntityDetails::set_shape(const ArraySpec &shape) { 164 CHECK(shape_.empty()); 165 for (const auto &shapeSpec : shape) { 166 shape_.push_back(shapeSpec); 167 } 168 } 169 void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) { 170 CHECK(coshape_.empty()); 171 for (const auto &shapeSpec : coshape) { 172 coshape_.push_back(shapeSpec); 173 } 174 } 175 176 ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) 177 : EntityDetails(std::move(d)) {} 178 179 UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) { 180 add_occurrence(useDetails.location(), useDetails.symbol()); 181 } 182 UseErrorDetails &UseErrorDetails::add_occurrence( 183 const SourceName &location, const Symbol &used) { 184 occurrences_.push_back(std::make_pair(location, &used)); 185 return *this; 186 } 187 188 void GenericDetails::AddSpecificProc( 189 const Symbol &proc, SourceName bindingName) { 190 specificProcs_.push_back(proc); 191 bindingNames_.push_back(bindingName); 192 } 193 void GenericDetails::set_specific(Symbol &specific) { 194 CHECK(!specific_); 195 specific_ = &specific; 196 } 197 void GenericDetails::clear_specific() { specific_ = nullptr; } 198 void GenericDetails::set_derivedType(Symbol &derivedType) { 199 CHECK(!derivedType_); 200 derivedType_ = &derivedType; 201 } 202 void GenericDetails::clear_derivedType() { derivedType_ = nullptr; } 203 void GenericDetails::AddUse(const Symbol &use) { 204 CHECK(use.has<UseDetails>()); 205 uses_.push_back(use); 206 } 207 208 const Symbol *GenericDetails::CheckSpecific() const { 209 return const_cast<GenericDetails *>(this)->CheckSpecific(); 210 } 211 Symbol *GenericDetails::CheckSpecific() { 212 if (specific_ && !specific_->has<UseErrorDetails>()) { 213 const Symbol &ultimate{specific_->GetUltimate()}; 214 for (const Symbol &proc : specificProcs_) { 215 if (&proc.GetUltimate() == &ultimate) { 216 return nullptr; 217 } 218 } 219 return specific_; 220 } else { 221 return nullptr; 222 } 223 } 224 225 void GenericDetails::CopyFrom(const GenericDetails &from) { 226 CHECK(specificProcs_.size() == bindingNames_.size()); 227 CHECK(from.specificProcs_.size() == from.bindingNames_.size()); 228 kind_ = from.kind_; 229 if (from.derivedType_) { 230 CHECK(!derivedType_ || derivedType_ == from.derivedType_); 231 derivedType_ = from.derivedType_; 232 } 233 for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) { 234 if (llvm::none_of(specificProcs_, [&](const Symbol &mySymbol) { 235 return &mySymbol.GetUltimate() == 236 &from.specificProcs_[i]->GetUltimate(); 237 })) { 238 specificProcs_.push_back(from.specificProcs_[i]); 239 bindingNames_.push_back(from.bindingNames_[i]); 240 } 241 } 242 } 243 244 // The name of the kind of details for this symbol. 245 // This is primarily for debugging. 246 std::string DetailsToString(const Details &details) { 247 return common::visit( 248 common::visitors{ 249 [](const UnknownDetails &) { return "Unknown"; }, 250 [](const MainProgramDetails &) { return "MainProgram"; }, 251 [](const ModuleDetails &) { return "Module"; }, 252 [](const SubprogramDetails &) { return "Subprogram"; }, 253 [](const SubprogramNameDetails &) { return "SubprogramName"; }, 254 [](const EntityDetails &) { return "Entity"; }, 255 [](const ObjectEntityDetails &) { return "ObjectEntity"; }, 256 [](const ProcEntityDetails &) { return "ProcEntity"; }, 257 [](const DerivedTypeDetails &) { return "DerivedType"; }, 258 [](const UseDetails &) { return "Use"; }, 259 [](const UseErrorDetails &) { return "UseError"; }, 260 [](const HostAssocDetails &) { return "HostAssoc"; }, 261 [](const GenericDetails &) { return "Generic"; }, 262 [](const ProcBindingDetails &) { return "ProcBinding"; }, 263 [](const NamelistDetails &) { return "Namelist"; }, 264 [](const CommonBlockDetails &) { return "CommonBlockDetails"; }, 265 [](const TypeParamDetails &) { return "TypeParam"; }, 266 [](const MiscDetails &) { return "Misc"; }, 267 [](const AssocEntityDetails &) { return "AssocEntity"; }, 268 }, 269 details); 270 } 271 272 std::string Symbol::GetDetailsName() const { return DetailsToString(details_); } 273 274 void Symbol::set_details(Details &&details) { 275 CHECK(CanReplaceDetails(details)); 276 details_ = std::move(details); 277 } 278 279 bool Symbol::CanReplaceDetails(const Details &details) const { 280 if (has<UnknownDetails>()) { 281 return true; // can always replace UnknownDetails 282 } else { 283 return common::visit( 284 common::visitors{ 285 [](const UseErrorDetails &) { return true; }, 286 [&](const ObjectEntityDetails &) { return has<EntityDetails>(); }, 287 [&](const ProcEntityDetails &) { return has<EntityDetails>(); }, 288 [&](const SubprogramDetails &) { 289 return has<SubprogramNameDetails>() || has<EntityDetails>(); 290 }, 291 [&](const DerivedTypeDetails &) { 292 const auto *derived{this->detailsIf<DerivedTypeDetails>()}; 293 return derived && derived->isForwardReferenced(); 294 }, 295 [&](const UseDetails &x) { 296 const auto *use{this->detailsIf<UseDetails>()}; 297 return use && use->symbol() == x.symbol(); 298 }, 299 [&](const HostAssocDetails &) { 300 return this->has<HostAssocDetails>(); 301 }, 302 [](const auto &) { return false; }, 303 }, 304 details); 305 } 306 } 307 308 // Usually a symbol's name is the first occurrence in the source, but sometimes 309 // we want to replace it with one at a different location (but same characters). 310 void Symbol::ReplaceName(const SourceName &name) { 311 CHECK(name == name_); 312 name_ = name; 313 } 314 315 void Symbol::SetType(const DeclTypeSpec &type) { 316 common::visit(common::visitors{ 317 [&](EntityDetails &x) { x.set_type(type); }, 318 [&](ObjectEntityDetails &x) { x.set_type(type); }, 319 [&](AssocEntityDetails &x) { x.set_type(type); }, 320 [&](ProcEntityDetails &x) { x.set_type(type); }, 321 [&](TypeParamDetails &x) { x.set_type(type); }, 322 [](auto &) {}, 323 }, 324 details_); 325 } 326 327 template <typename T> 328 constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>}; 329 330 const std::string *Symbol::GetBindName() const { 331 return common::visit( 332 [&](auto &x) -> const std::string * { 333 if constexpr (HasBindName<decltype(&x)>) { 334 return x.bindName(); 335 } else { 336 return nullptr; 337 } 338 }, 339 details_); 340 } 341 342 void Symbol::SetBindName(std::string &&name) { 343 common::visit( 344 [&](auto &x) { 345 if constexpr (HasBindName<decltype(&x)>) { 346 x.set_bindName(std::move(name)); 347 } else { 348 DIE("bind name not allowed on this kind of symbol"); 349 } 350 }, 351 details_); 352 } 353 354 bool Symbol::GetIsExplicitBindName() const { 355 return common::visit( 356 [&](auto &x) -> bool { 357 if constexpr (HasBindName<decltype(&x)>) { 358 return x.isExplicitBindName(); 359 } else { 360 return false; 361 } 362 }, 363 details_); 364 } 365 366 void Symbol::SetIsExplicitBindName(bool yes) { 367 common::visit( 368 [&](auto &x) { 369 if constexpr (HasBindName<decltype(&x)>) { 370 x.set_isExplicitBindName(yes); 371 } else { 372 DIE("bind name not allowed on this kind of symbol"); 373 } 374 }, 375 details_); 376 } 377 378 void Symbol::SetIsCDefined(bool yes) { 379 common::visit( 380 [&](auto &x) { 381 if constexpr (HasBindName<decltype(&x)>) { 382 x.set_isCDefined(yes); 383 } else { 384 DIE("CDEFINED not allowed on this kind of symbol"); 385 } 386 }, 387 details_); 388 } 389 390 bool Symbol::IsFuncResult() const { 391 return common::visit( 392 common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); }, 393 [](const ObjectEntityDetails &x) { return x.isFuncResult(); }, 394 [](const ProcEntityDetails &x) { return x.isFuncResult(); }, 395 [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); }, 396 [](const auto &) { return false; }}, 397 details_); 398 } 399 400 const ArraySpec *Symbol::GetShape() const { 401 if (const auto *details{std::get_if<ObjectEntityDetails>(&details_)}) { 402 return &details->shape(); 403 } else { 404 return nullptr; 405 } 406 } 407 408 bool Symbol::IsObjectArray() const { 409 const ArraySpec *shape{GetShape()}; 410 return shape && !shape->empty(); 411 } 412 413 bool Symbol::IsSubprogram() const { 414 return common::visit( 415 common::visitors{ 416 [](const SubprogramDetails &) { return true; }, 417 [](const SubprogramNameDetails &) { return true; }, 418 [](const GenericDetails &) { return true; }, 419 [](const UseDetails &x) { return x.symbol().IsSubprogram(); }, 420 [](const auto &) { return false; }, 421 }, 422 details_); 423 } 424 425 bool Symbol::IsFromModFile() const { 426 return test(Flag::ModFile) || 427 (!owner_->IsTopLevel() && owner_->symbol()->IsFromModFile()); 428 } 429 430 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) { 431 DumpBool(os, "dummy", x.isDummy()); 432 DumpBool(os, "funcResult", x.isFuncResult()); 433 if (x.type()) { 434 os << " type: " << *x.type(); 435 } 436 DumpOptional(os, "bindName", x.bindName()); 437 DumpBool(os, "CDEFINED", x.isCDefined()); 438 return os; 439 } 440 441 llvm::raw_ostream &operator<<( 442 llvm::raw_ostream &os, const ObjectEntityDetails &x) { 443 os << *static_cast<const EntityDetails *>(&x); 444 DumpList(os, "shape", x.shape()); 445 DumpList(os, "coshape", x.coshape()); 446 DumpExpr(os, "init", x.init_); 447 if (x.unanalyzedPDTComponentInit()) { 448 os << " (has unanalyzedPDTComponentInit)"; 449 } 450 if (!x.ignoreTKR_.empty()) { 451 x.ignoreTKR_.Dump(os << ' ', common::EnumToString); 452 } 453 if (x.cudaDataAttr()) { 454 os << " cudaDataAttr: " << common::EnumToString(*x.cudaDataAttr()); 455 } 456 return os; 457 } 458 459 llvm::raw_ostream &operator<<( 460 llvm::raw_ostream &os, const AssocEntityDetails &x) { 461 os << *static_cast<const EntityDetails *>(&x); 462 if (x.IsAssumedSize()) { 463 os << " RANK(*)"; 464 } else if (x.IsAssumedRank()) { 465 os << " RANK DEFAULT"; 466 } else if (auto assocRank{x.rank()}) { 467 os << " RANK(" << *assocRank << ')'; 468 } 469 DumpExpr(os, "expr", x.expr()); 470 return os; 471 } 472 473 llvm::raw_ostream &operator<<( 474 llvm::raw_ostream &os, const ProcEntityDetails &x) { 475 if (x.procInterface_) { 476 if (x.rawProcInterface_ != x.procInterface_) { 477 os << ' ' << x.rawProcInterface_->name() << " ->"; 478 } 479 os << ' ' << x.procInterface_->name(); 480 } else { 481 DumpType(os, x.type()); 482 } 483 DumpOptional(os, "bindName", x.bindName()); 484 DumpOptional(os, "passName", x.passName()); 485 if (x.init()) { 486 if (const Symbol * target{*x.init()}) { 487 os << " => " << target->name(); 488 } else { 489 os << " => NULL()"; 490 } 491 } 492 if (x.isCUDAKernel()) { 493 os << " isCUDAKernel"; 494 } 495 return os; 496 } 497 498 llvm::raw_ostream &operator<<( 499 llvm::raw_ostream &os, const DerivedTypeDetails &x) { 500 DumpBool(os, "sequence", x.sequence_); 501 DumpList(os, "components", x.componentNames_); 502 return os; 503 } 504 505 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) { 506 os << ' ' << x.kind().ToString(); 507 DumpBool(os, "(specific)", x.specific() != nullptr); 508 DumpBool(os, "(derivedType)", x.derivedType() != nullptr); 509 if (const auto &uses{x.uses()}; !uses.empty()) { 510 os << " (uses:"; 511 char sep{' '}; 512 for (const Symbol &use : uses) { 513 const Symbol &ultimate{use.GetUltimate()}; 514 os << sep << ultimate.name() << "->" 515 << ultimate.owner().GetName().value(); 516 sep = ','; 517 } 518 os << ')'; 519 } 520 os << " procs:"; 521 DumpSymbolVector(os, x.specificProcs()); 522 return os; 523 } 524 525 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) { 526 os << DetailsToString(details); 527 common::visit( // 528 common::visitors{ 529 [&](const UnknownDetails &) {}, 530 [&](const MainProgramDetails &) {}, 531 [&](const ModuleDetails &x) { 532 if (x.isSubmodule()) { 533 os << " ("; 534 if (x.ancestor()) { 535 auto ancestor{x.ancestor()->GetName().value()}; 536 os << ancestor; 537 if (x.parent()) { 538 auto parent{x.parent()->GetName().value()}; 539 if (ancestor != parent) { 540 os << ':' << parent; 541 } 542 } 543 } 544 os << ")"; 545 } 546 if (x.isDefaultPrivate()) { 547 os << " isDefaultPrivate"; 548 } 549 }, 550 [&](const SubprogramNameDetails &x) { 551 os << ' ' << EnumToString(x.kind()); 552 }, 553 [&](const UseDetails &x) { 554 os << " from " << x.symbol().name() << " in " 555 << GetUsedModule(x).name(); 556 }, 557 [&](const UseErrorDetails &x) { 558 os << " uses:"; 559 char sep{':'}; 560 for (const auto &[location, sym] : x.occurrences()) { 561 os << sep << " from " << sym->name() << " at " << location; 562 sep = ','; 563 } 564 }, 565 [](const HostAssocDetails &) {}, 566 [&](const ProcBindingDetails &x) { 567 os << " => " << x.symbol().name(); 568 DumpOptional(os, "passName", x.passName()); 569 if (x.numPrivatesNotOverridden() > 0) { 570 os << " numPrivatesNotOverridden: " 571 << x.numPrivatesNotOverridden(); 572 } 573 }, 574 [&](const NamelistDetails &x) { 575 os << ':'; 576 DumpSymbolVector(os, x.objects()); 577 }, 578 [&](const CommonBlockDetails &x) { 579 DumpOptional(os, "bindName", x.bindName()); 580 if (x.alignment()) { 581 os << " alignment=" << x.alignment(); 582 } 583 os << ':'; 584 for (const auto &object : x.objects()) { 585 os << ' ' << object->name(); 586 } 587 }, 588 [&](const TypeParamDetails &x) { 589 DumpOptional(os, "type", x.type()); 590 if (auto attr{x.attr()}) { 591 os << ' ' << common::EnumToString(*attr); 592 } else { 593 os << " (no attr)"; 594 } 595 DumpExpr(os, "init", x.init()); 596 }, 597 [&](const MiscDetails &x) { 598 os << ' ' << MiscDetails::EnumToString(x.kind()); 599 }, 600 [&](const auto &x) { os << x; }, 601 }, 602 details); 603 return os; 604 } 605 606 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) { 607 return o << Symbol::EnumToString(flag); 608 } 609 610 llvm::raw_ostream &operator<<( 611 llvm::raw_ostream &o, const Symbol::Flags &flags) { 612 std::size_t n{flags.count()}; 613 std::size_t seen{0}; 614 for (std::size_t j{0}; seen < n; ++j) { 615 Symbol::Flag flag{static_cast<Symbol::Flag>(j)}; 616 if (flags.test(flag)) { 617 if (seen++ > 0) { 618 o << ", "; 619 } 620 o << flag; 621 } 622 } 623 return o; 624 } 625 626 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) { 627 os << symbol.name(); 628 if (!symbol.attrs().empty()) { 629 os << ", " << symbol.attrs(); 630 } 631 if (!symbol.flags().empty()) { 632 os << " (" << symbol.flags() << ')'; 633 } 634 if (symbol.size_) { 635 os << " size=" << symbol.size_ << " offset=" << symbol.offset_; 636 } 637 os << ": " << symbol.details_; 638 return os; 639 } 640 641 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 642 void Symbol::dump() const { llvm::errs() << *this << '\n'; } 643 #endif 644 645 // Output a unique name for a scope by qualifying it with the names of 646 // parent scopes. For scopes without corresponding symbols, use the kind 647 // with an index (e.g. Block1, Block2, etc.). 648 static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) { 649 if (!scope.IsTopLevel()) { 650 DumpUniqueName(os, scope.parent()); 651 os << '/'; 652 if (auto *scopeSymbol{scope.symbol()}; 653 scopeSymbol && !scopeSymbol->name().empty()) { 654 os << scopeSymbol->name(); 655 } else { 656 int index{1}; 657 for (auto &child : scope.parent().children()) { 658 if (child == scope) { 659 break; 660 } 661 if (child.kind() == scope.kind()) { 662 ++index; 663 } 664 } 665 os << Scope::EnumToString(scope.kind()) << index; 666 } 667 } 668 } 669 670 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the 671 // format should be reasonably stable. 672 llvm::raw_ostream &DumpForUnparse( 673 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) { 674 DumpUniqueName(os, symbol.owner()); 675 os << '/' << symbol.name(); 676 if (isDef) { 677 if (!symbol.attrs().empty()) { 678 os << ' ' << symbol.attrs(); 679 } 680 if (!symbol.flags().empty()) { 681 os << " (" << symbol.flags() << ')'; 682 } 683 os << ' ' << symbol.GetDetailsName(); 684 DumpType(os, symbol.GetType()); 685 } 686 return os; 687 } 688 689 const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const { 690 if (const Symbol * parentComponent{GetParentComponent(scope)}) { 691 const auto &object{parentComponent->get<ObjectEntityDetails>()}; 692 return &object.type()->derivedTypeSpec(); 693 } else { 694 return nullptr; 695 } 696 } 697 698 const Symbol *Symbol::GetParentComponent(const Scope *scope) const { 699 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) { 700 if (const Scope * localScope{scope ? scope : scope_}) { 701 return dtDetails->GetParentComponent(DEREF(localScope)); 702 } 703 } 704 return nullptr; 705 } 706 707 void DerivedTypeDetails::add_component(const Symbol &symbol) { 708 if (symbol.test(Symbol::Flag::ParentComp)) { 709 CHECK(componentNames_.empty()); 710 } 711 componentNames_.push_back(symbol.name()); 712 } 713 714 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const { 715 if (auto extends{GetParentComponentName()}) { 716 if (auto iter{scope.find(*extends)}; iter != scope.cend()) { 717 if (const Symbol & symbol{*iter->second}; 718 symbol.test(Symbol::Flag::ParentComp)) { 719 return &symbol; 720 } 721 } 722 } 723 return nullptr; 724 } 725 726 const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const { 727 for (const auto &pair : finals_) { 728 const Symbol &symbol{*pair.second}; 729 if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) { 730 if (details->dummyArgs().size() == 1) { 731 if (const Symbol * arg{details->dummyArgs().at(0)}) { 732 if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) { 733 if (rank == object->shape().Rank() || object->IsAssumedRank() || 734 IsElementalProcedure(symbol)) { 735 return &symbol; 736 } 737 } 738 } 739 } 740 } 741 } 742 return nullptr; 743 } 744 745 TypeParamDetails &TypeParamDetails::set_attr(common::TypeParamAttr attr) { 746 CHECK(!attr_); 747 attr_ = attr; 748 return *this; 749 } 750 751 TypeParamDetails &TypeParamDetails::set_type(const DeclTypeSpec &type) { 752 CHECK(!type_); 753 type_ = &type; 754 return *this; 755 } 756 757 bool GenericKind::IsIntrinsicOperator() const { 758 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() || 759 Has<common::NumericOperator>() || Has<common::RelationalOperator>(); 760 } 761 762 bool GenericKind::IsOperator() const { 763 return IsDefinedOperator() || IsIntrinsicOperator(); 764 } 765 766 std::string GenericKind::ToString() const { 767 return common::visit( 768 common::visitors{ 769 [](const OtherKind &x) { return std::string{EnumToString(x)}; }, 770 [](const common::DefinedIo &x) { return AsFortran(x).ToString(); }, 771 [](const auto &x) { return std::string{common::EnumToString(x)}; }, 772 }, 773 u); 774 } 775 776 SourceName GenericKind::AsFortran(common::DefinedIo x) { 777 const char *name{common::AsFortran(x)}; 778 return {name, std::strlen(name)}; 779 } 780 781 bool GenericKind::Is(GenericKind::OtherKind x) const { 782 const OtherKind *y{std::get_if<OtherKind>(&u)}; 783 return y && *y == x; 784 } 785 786 std::string Symbol::OmpFlagToClauseName(Symbol::Flag ompFlag) { 787 std::string clauseName; 788 switch (ompFlag) { 789 case Symbol::Flag::OmpShared: 790 clauseName = "SHARED"; 791 break; 792 case Symbol::Flag::OmpPrivate: 793 clauseName = "PRIVATE"; 794 break; 795 case Symbol::Flag::OmpLinear: 796 clauseName = "LINEAR"; 797 break; 798 case Symbol::Flag::OmpFirstPrivate: 799 clauseName = "FIRSTPRIVATE"; 800 break; 801 case Symbol::Flag::OmpLastPrivate: 802 clauseName = "LASTPRIVATE"; 803 break; 804 case Symbol::Flag::OmpMapTo: 805 case Symbol::Flag::OmpMapFrom: 806 case Symbol::Flag::OmpMapToFrom: 807 case Symbol::Flag::OmpMapAlloc: 808 case Symbol::Flag::OmpMapRelease: 809 case Symbol::Flag::OmpMapDelete: 810 clauseName = "MAP"; 811 break; 812 case Symbol::Flag::OmpUseDevicePtr: 813 clauseName = "USE_DEVICE_PTR"; 814 break; 815 case Symbol::Flag::OmpUseDeviceAddr: 816 clauseName = "USE_DEVICE_ADDR"; 817 break; 818 case Symbol::Flag::OmpCopyIn: 819 clauseName = "COPYIN"; 820 break; 821 case Symbol::Flag::OmpCopyPrivate: 822 clauseName = "COPYPRIVATE"; 823 break; 824 case Symbol::Flag::OmpIsDevicePtr: 825 clauseName = "IS_DEVICE_PTR"; 826 break; 827 case Symbol::Flag::OmpHasDeviceAddr: 828 clauseName = "HAS_DEVICE_ADDR"; 829 break; 830 default: 831 clauseName = ""; 832 break; 833 } 834 return clauseName; 835 } 836 837 bool SymbolOffsetCompare::operator()( 838 const SymbolRef &x, const SymbolRef &y) const { 839 const Symbol *xCommon{FindCommonBlockContaining(*x)}; 840 const Symbol *yCommon{FindCommonBlockContaining(*y)}; 841 if (xCommon) { 842 if (yCommon) { 843 const SymbolSourcePositionCompare sourceCmp; 844 if (sourceCmp(*xCommon, *yCommon)) { 845 return true; 846 } else if (sourceCmp(*yCommon, *xCommon)) { 847 return false; 848 } else if (x->offset() == y->offset()) { 849 return x->size() > y->size(); 850 } else { 851 return x->offset() < y->offset(); 852 } 853 } else { 854 return false; 855 } 856 } else if (yCommon) { 857 return true; 858 } else if (x->offset() == y->offset()) { 859 return x->size() > y->size(); 860 } else { 861 return x->offset() < y->offset(); 862 } 863 return x->GetSemanticsContext().allCookedSources().Precedes( 864 x->name(), y->name()); 865 } 866 867 bool SymbolOffsetCompare::operator()( 868 const MutableSymbolRef &x, const MutableSymbolRef &y) const { 869 return (*this)(SymbolRef{*x}, SymbolRef{*y}); 870 } 871 872 } // namespace Fortran::semantics 873