brintos

brintos / llvm-project-archived public Read only

0
0
Text · 29.1 KiB · ed0715a Raw
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