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