brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.7 KiB · 2606d99 Raw
783 lines · cpp
1//===-- lib/Semantics/semantics.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/semantics.h"10#include "assignment.h"11#include "canonicalize-acc.h"12#include "canonicalize-directives.h"13#include "canonicalize-do.h"14#include "canonicalize-omp.h"15#include "check-acc-structure.h"16#include "check-allocate.h"17#include "check-arithmeticif.h"18#include "check-case.h"19#include "check-coarray.h"20#include "check-cuda.h"21#include "check-data.h"22#include "check-deallocate.h"23#include "check-declarations.h"24#include "check-do-forall.h"25#include "check-if-stmt.h"26#include "check-io.h"27#include "check-namelist.h"28#include "check-nullify.h"29#include "check-omp-structure.h"30#include "check-purity.h"31#include "check-return.h"32#include "check-select-rank.h"33#include "check-select-type.h"34#include "check-stop.h"35#include "compute-offsets.h"36#include "mod-file.h"37#include "resolve-labels.h"38#include "resolve-names.h"39#include "rewrite-parse-tree.h"40#include "flang/Parser/parse-tree-visitor.h"41#include "flang/Parser/tools.h"42#include "flang/Semantics/expression.h"43#include "flang/Semantics/scope.h"44#include "flang/Semantics/symbol.h"45#include "flang/Support/default-kinds.h"46#include "llvm/Support/raw_ostream.h"47#include "llvm/TargetParser/Host.h"48#include "llvm/TargetParser/Triple.h"49 50namespace Fortran::semantics {51 52using NameToSymbolMap = std::multimap<parser::CharBlock, SymbolRef>;53static void DoDumpSymbols(llvm::raw_ostream &, const Scope &, int indent = 0);54static void PutIndent(llvm::raw_ostream &, int indent);55 56static void GetSymbolNames(const Scope &scope, NameToSymbolMap &symbols) {57  // Finds all symbol names in the scope without collecting duplicates.58  for (const auto &pair : scope) {59    symbols.emplace(pair.second->name(), *pair.second);60  }61  for (const auto &pair : scope.commonBlocks()) {62    symbols.emplace(pair.second->name(), *pair.second);63  }64  for (const auto &child : scope.children()) {65    GetSymbolNames(child, symbols);66  }67}68 69// A parse tree visitor that calls Enter/Leave functions from each checker70// class C supplied as template parameters. Enter is called before the node's71// children are visited, Leave is called after. No two checkers may have the72// same Enter or Leave function. Each checker must be constructible from73// SemanticsContext and have BaseChecker as a virtual base class.74template <typename... C>75class SemanticsVisitor : public virtual BaseChecker, public virtual C... {76public:77  using BaseChecker::Enter;78  using BaseChecker::Leave;79  using C::Enter...;80  using C::Leave...;81  SemanticsVisitor(SemanticsContext &context)82      : C{context}..., context_{context} {}83 84  template <typename N> bool Pre(const N &node) {85    if constexpr (common::HasMember<const N *, ConstructNode>) {86      context_.PushConstruct(node);87    }88    Enter(node);89    return true;90  }91  template <typename N> void Post(const N &node) {92    Leave(node);93    if constexpr (common::HasMember<const N *, ConstructNode>) {94      context_.PopConstruct();95    }96  }97 98  template <typename T> bool Pre(const parser::Statement<T> &node) {99    context_.set_location(node.source);100    Enter(node);101    return true;102  }103  template <typename T> bool Pre(const parser::UnlabeledStatement<T> &node) {104    context_.set_location(node.source);105    Enter(node);106    return true;107  }108  template <typename T> void Post(const parser::Statement<T> &node) {109    Leave(node);110    context_.set_location(std::nullopt);111  }112  template <typename T> void Post(const parser::UnlabeledStatement<T> &node) {113    Leave(node);114    context_.set_location(std::nullopt);115  }116 117  bool Walk(const parser::Program &program) {118    parser::Walk(program, *this);119    return !context_.AnyFatalError();120  }121 122private:123  SemanticsContext &context_;124};125 126class MiscChecker : public virtual BaseChecker {127public:128  explicit MiscChecker(SemanticsContext &context) : context_{context} {}129  void Leave(const parser::EntryStmt &) {130    if (!context_.constructStack().empty()) { // C1571131      context_.Say("ENTRY may not appear in an executable construct"_err_en_US);132    }133  }134  void Leave(const parser::AssignStmt &stmt) {135    CheckAssignGotoName(std::get<parser::Name>(stmt.t));136  }137  void Leave(const parser::AssignedGotoStmt &stmt) {138    CheckAssignGotoName(std::get<parser::Name>(stmt.t));139  }140 141private:142  void CheckAssignGotoName(const parser::Name &name) {143    if (context_.HasError(name.symbol)) {144      return;145    }146    const Symbol &symbol{DEREF(name.symbol)};147    auto type{evaluate::DynamicType::From(symbol)};148    if (!IsVariableName(symbol) || symbol.Rank() != 0 || !type ||149        type->category() != TypeCategory::Integer ||150        type->kind() !=151            context_.defaultKinds().GetDefaultKind(TypeCategory::Integer)) {152      context_153          .Say(name.source,154              "'%s' must be a default integer scalar variable"_err_en_US,155              name.source)156          .Attach(symbol.name(), "Declaration of '%s'"_en_US, symbol.name());157    }158  }159 160  SemanticsContext &context_;161};162 163static void WarnUndefinedFunctionResult(164    SemanticsContext &context, const Scope &scope) {165  auto WasDefined{[&context](const Symbol &symbol) {166    return context.IsSymbolDefined(symbol) ||167        IsInitialized(symbol, /*ignoreDataStatements=*/true,168            /*ignoreAllocatable=*/true, /*ignorePointer=*/true);169  }};170  if (const Symbol * symbol{scope.symbol()}) {171    if (const auto *subp{symbol->detailsIf<SubprogramDetails>()}) {172      if (subp->isFunction() && !subp->isInterface() && !subp->stmtFunction()) {173        bool wasDefined{WasDefined(subp->result())};174        if (!wasDefined) {175          // Definitions of ENTRY result variables also count.176          for (const auto &pair : scope) {177            const Symbol &local{*pair.second};178            if (IsFunctionResult(local) && WasDefined(local)) {179              wasDefined = true;180              break;181            }182          }183          if (!wasDefined) {184            context.Warn(common::UsageWarning::UndefinedFunctionResult,185                symbol->name(), "Function result is never defined"_warn_en_US);186          }187        }188      }189    }190  }191  if (!scope.IsModuleFile()) {192    for (const Scope &child : scope.children()) {193      WarnUndefinedFunctionResult(context, child);194    }195  }196}197 198using StatementSemanticsPass1 = ExprChecker;199using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker,200    ArithmeticIfStmtChecker, AssignmentChecker, CaseChecker, CoarrayChecker,201    DataChecker, DeallocateChecker, DoForallChecker, IfStmtChecker, IoChecker,202    MiscChecker, NamelistChecker, NullifyChecker, PurityChecker,203    ReturnStmtChecker, SelectRankConstructChecker, SelectTypeChecker,204    StopChecker>;205 206static bool PerformStatementSemantics(207    SemanticsContext &context, parser::Program &program) {208  ResolveNames(context, program, context.globalScope());209  RewriteParseTree(context, program);210  ComputeOffsets(context, context.globalScope());211  CheckDeclarations(context);212  StatementSemanticsPass1{context}.Walk(program);213  StatementSemanticsPass2 pass2{context};214  pass2.Walk(program);215  if (context.languageFeatures().IsEnabled(common::LanguageFeature::OpenACC)) {216    SemanticsVisitor<AccStructureChecker>{context}.Walk(program);217  }218  if (context.languageFeatures().IsEnabled(common::LanguageFeature::OpenMP)) {219    SemanticsVisitor<OmpStructureChecker>{context}.Walk(program);220  }221  if (context.languageFeatures().IsEnabled(common::LanguageFeature::CUDA)) {222    SemanticsVisitor<CUDAChecker>{context}.Walk(program);223  }224  if (!context.messages().AnyFatalError()) {225    WarnUndefinedFunctionResult(context, context.globalScope());226  }227  if (!context.AnyFatalError()) {228    pass2.CompileDataInitializationsIntoInitializers();229  }230  return !context.AnyFatalError();231}232 233/// This class keeps track of the common block appearances with the biggest size234/// and with an initial value (if any) in a program. This allows reporting235/// conflicting initialization and warning about appearances of a same236/// named common block with different sizes. The biggest common block size and237/// initialization (if any) can later be provided so that lowering can generate238/// the correct symbol size and initial values, even when named common blocks239/// appears with different sizes and are initialized outside of block data.240class CommonBlockMap {241private:242  struct CommonBlockInfo {243    // Common block symbol for the appearance with the biggest size.244    SymbolRef biggestSize;245    // Common block symbol for the appearance with the initialized members (if246    // any).247    std::optional<SymbolRef> initialization;248  };249 250public:251  void MapCommonBlockAndCheckConflicts(252      SemanticsContext &context, const Symbol &common) {253    const Symbol *isInitialized{CommonBlockIsInitialized(common)};254    // Merge common according to the name they will have in the object files.255    // This allows merging BIND(C) and non BIND(C) common block instead of256    // later crashing. This "merge" matches what ifort/gfortran/nvfortran are257    // doing and what a linker would do if the definition were in distinct258    // files.259    std::string commonName{260        GetCommonBlockObjectName(common, context.underscoring())};261    auto [it, firstAppearance] = commonBlocks_.insert({commonName,262        isInitialized ? CommonBlockInfo{common, common}263                      : CommonBlockInfo{common, std::nullopt}});264    if (!firstAppearance) {265      CommonBlockInfo &info{it->second};266      if (isInitialized) {267        if (info.initialization.has_value() &&268            &**info.initialization != &common) {269          // Use the location of the initialization in the error message because270          // common block symbols may have no location if they are blank271          // commons.272          const Symbol &previousInit{273              DEREF(CommonBlockIsInitialized(**info.initialization))};274          context275              .Say(isInitialized->name(),276                  "Multiple initialization of COMMON block /%s/"_err_en_US,277                  common.name())278              .Attach(previousInit.name(),279                  "Previous initialization of COMMON block /%s/"_en_US,280                  common.name());281        } else {282          info.initialization = common;283        }284      }285      if (common.size() != info.biggestSize->size() && !common.name().empty()) {286        if (auto *msg{context.Warn(common::LanguageFeature::DistinctCommonSizes,287                common.name(),288                "A named COMMON block should have the same size everywhere it appears (%zd bytes here)"_port_en_US,289                common.size())}) {290          msg->Attach(info.biggestSize->name(),291              "Previously defined with a size of %zd bytes"_en_US,292              info.biggestSize->size());293        }294      }295      if (common.size() > info.biggestSize->size()) {296        info.biggestSize = common;297      }298    }299  }300 301  CommonBlockList GetCommonBlocks() const {302    CommonBlockList result;303    for (const auto &[_, blockInfo] : commonBlocks_) {304      result.emplace_back(305          std::make_pair(blockInfo.initialization ? *blockInfo.initialization306                                                  : blockInfo.biggestSize,307              blockInfo.biggestSize->size()));308    }309    return result;310  }311 312private:313  /// Return the symbol of an initialized member if a COMMON block314  /// is initalized. Otherwise, return nullptr.315  static Symbol *CommonBlockIsInitialized(const Symbol &common) {316    const auto &commonDetails{317        common.get<Fortran::semantics::CommonBlockDetails>()};318    for (const auto &member : commonDetails.objects()) {319      if (IsInitialized(*member)) {320        return &*member;321      }322    }323    // Common block may be initialized via initialized variables that are in an324    // equivalence with the common block members.325    for (const Fortran::semantics::EquivalenceSet &set :326        common.owner().equivalenceSets()) {327      for (const Fortran::semantics::EquivalenceObject &obj : set) {328        if (!obj.symbol.test(329                Fortran::semantics::Symbol::Flag::CompilerCreated)) {330          if (FindCommonBlockContaining(obj.symbol) == &common &&331              IsInitialized(obj.symbol)) {332            return &obj.symbol;333          }334        }335      }336    }337    return nullptr;338  }339 340  std::map<std::string, CommonBlockInfo> commonBlocks_;341};342 343SemanticsContext::SemanticsContext(344    const common::IntrinsicTypeDefaultKinds &defaultKinds,345    const common::LanguageFeatureControl &languageFeatures,346    const common::LangOptions &langOpts,347    parser::AllCookedSources &allCookedSources)348    : defaultKinds_{defaultKinds}, languageFeatures_{languageFeatures},349      langOpts_{langOpts}, allCookedSources_{allCookedSources},350      intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds_)},351      globalScope_{*this}, intrinsicModulesScope_{globalScope_.MakeScope(352                               Scope::Kind::IntrinsicModules, nullptr)},353      foldingContext_{parser::ContextualMessages{&messages_}, defaultKinds_,354          intrinsics_, targetCharacteristics_, languageFeatures_, tempNames_} {}355 356SemanticsContext::~SemanticsContext() {}357 358int SemanticsContext::GetDefaultKind(TypeCategory category) const {359  return defaultKinds_.GetDefaultKind(category);360}361 362const DeclTypeSpec &SemanticsContext::MakeNumericType(363    TypeCategory category, int kind) {364  if (kind == 0) {365    kind = GetDefaultKind(category);366  }367  return globalScope_.MakeNumericType(category, KindExpr{kind});368}369const DeclTypeSpec &SemanticsContext::MakeLogicalType(int kind) {370  if (kind == 0) {371    kind = GetDefaultKind(TypeCategory::Logical);372  }373  return globalScope_.MakeLogicalType(KindExpr{kind});374}375 376bool SemanticsContext::AnyFatalError() const {377  return messages_.AnyFatalError(warningsAreErrors_);378}379bool SemanticsContext::HasError(const Symbol &symbol) {380  return errorSymbols_.count(symbol) > 0;381}382bool SemanticsContext::HasError(const Symbol *symbol) {383  return !symbol || HasError(*symbol);384}385bool SemanticsContext::HasError(const parser::Name &name) {386  return HasError(name.symbol);387}388void SemanticsContext::SetError(const Symbol &symbol, bool value) {389  if (value) {390    CheckError(symbol);391    errorSymbols_.emplace(symbol);392  }393}394void SemanticsContext::CheckError(const Symbol &symbol) {395  if (!AnyFatalError()) {396    std::string buf;397    llvm::raw_string_ostream ss{buf};398    ss << symbol;399    common::die(400        "No error was reported but setting error on: %s", ss.str().c_str());401  }402}403 404bool SemanticsContext::ScopeIndexComparator::operator()(405    parser::CharBlock x, parser::CharBlock y) const {406  return x.begin() < y.begin() ||407      (x.begin() == y.begin() && x.size() > y.size());408}409 410auto SemanticsContext::SearchScopeIndex(parser::CharBlock source)411    -> ScopeIndex::iterator {412  if (!scopeIndex_.empty()) {413    auto iter{scopeIndex_.upper_bound(source)};414    auto begin{scopeIndex_.begin()};415    do {416      --iter;417      if (iter->first.Contains(source)) {418        return iter;419      }420    } while (iter != begin);421  }422  return scopeIndex_.end();423}424 425const Scope &SemanticsContext::FindScope(parser::CharBlock source) const {426  return const_cast<SemanticsContext *>(this)->FindScope(source);427}428 429Scope &SemanticsContext::FindScope(parser::CharBlock source) {430  if (auto iter{SearchScopeIndex(source)}; iter != scopeIndex_.end()) {431    return iter->second;432  } else {433    common::die(434        "SemanticsContext::FindScope(): invalid source location for '%s'",435        source.ToString().c_str());436  }437}438 439void SemanticsContext::UpdateScopeIndex(440    Scope &scope, parser::CharBlock newSource) {441  if (scope.sourceRange().empty()) {442    scopeIndex_.emplace(newSource, scope);443  } else if (!scope.sourceRange().Contains(newSource)) {444    auto iter{SearchScopeIndex(scope.sourceRange())};445    CHECK(iter != scopeIndex_.end());446    while (&iter->second != &scope) {447      CHECK(iter != scopeIndex_.begin());448      --iter;449    }450    scopeIndex_.erase(iter);451    scopeIndex_.emplace(newSource, scope);452  }453}454 455void SemanticsContext::DumpScopeIndex(llvm::raw_ostream &out) const {456  out << "scopeIndex_:\n";457  for (const auto &[source, scope] : scopeIndex_) {458    out << "source '" << source.ToString() << "' -> scope " << scope459        << "... whose source range is '" << scope.sourceRange().ToString()460        << "'\n";461  }462}463 464bool SemanticsContext::IsInModuleFile(parser::CharBlock source) const {465  for (const Scope *scope{&FindScope(source)}; !scope->IsGlobal();466       scope = &scope->parent()) {467    if (scope->IsModuleFile()) {468      return true;469    }470  }471  return false;472}473 474void SemanticsContext::PopConstruct() {475  CHECK(!constructStack_.empty());476  constructStack_.pop_back();477}478 479parser::Message *SemanticsContext::CheckIndexVarRedefine(480    const parser::CharBlock &location, const Symbol &variable,481    parser::MessageFixedText &&message) {482  const Symbol &symbol{ResolveAssociations(variable)};483  auto it{activeIndexVars_.find(symbol)};484  if (it != activeIndexVars_.end()) {485    std::string kind{EnumToString(it->second.kind)};486    return &Say(location, std::move(message), kind, symbol.name())487                .Attach(488                    it->second.location, "Enclosing %s construct"_en_US, kind);489  } else {490    return nullptr;491  }492}493 494void SemanticsContext::WarnIndexVarRedefine(495    const parser::CharBlock &location, const Symbol &variable) {496  if (ShouldWarn(common::UsageWarning::IndexVarRedefinition)) {497    if (auto *msg{CheckIndexVarRedefine(location, variable,498            "Possible redefinition of %s variable '%s'"_warn_en_US)}) {499      msg->set_usageWarning(common::UsageWarning::IndexVarRedefinition);500    }501  }502}503 504void SemanticsContext::CheckIndexVarRedefine(505    const parser::CharBlock &location, const Symbol &variable) {506  CheckIndexVarRedefine(507      location, variable, "Cannot redefine %s variable '%s'"_err_en_US);508}509 510void SemanticsContext::CheckIndexVarRedefine(const parser::Variable &variable) {511  if (const Symbol * entity{GetLastName(variable).symbol}) {512    CheckIndexVarRedefine(variable.GetSource(), *entity);513  }514}515 516void SemanticsContext::CheckIndexVarRedefine(const parser::Name &name) {517  if (const Symbol * entity{name.symbol}) {518    CheckIndexVarRedefine(name.source, *entity);519  }520}521 522void SemanticsContext::ActivateIndexVar(523    const parser::Name &name, IndexVarKind kind) {524  CheckIndexVarRedefine(name);525  if (const Symbol * indexVar{name.symbol}) {526    activeIndexVars_.emplace(527        ResolveAssociations(*indexVar), IndexVarInfo{name.source, kind});528  }529}530 531void SemanticsContext::DeactivateIndexVar(const parser::Name &name) {532  if (Symbol * indexVar{name.symbol}) {533    auto it{activeIndexVars_.find(ResolveAssociations(*indexVar))};534    if (it != activeIndexVars_.end() && it->second.location == name.source) {535      activeIndexVars_.erase(it);536    }537  }538}539 540SymbolVector SemanticsContext::GetIndexVars(IndexVarKind kind) {541  SymbolVector result;542  for (const auto &[symbol, info] : activeIndexVars_) {543    if (info.kind == kind) {544      result.push_back(symbol);545    }546  }547  return result;548}549 550SourceName SemanticsContext::SaveTempName(std::string &&name) {551  return {*tempNames_.emplace(std::move(name)).first};552}553 554SourceName SemanticsContext::GetTempName(const Scope &scope) {555  for (const auto &str : tempNames_) {556    if (IsTempName(str)) {557      SourceName name{str};558      if (scope.find(name) == scope.end()) {559        return name;560      }561    }562  }563  return SaveTempName(".F18."s + std::to_string(tempNames_.size()));564}565 566bool SemanticsContext::IsTempName(const std::string &name) {567  return name.size() > 5 && name.substr(0, 5) == ".F18.";568}569 570Scope *SemanticsContext::GetBuiltinModule(const char *name) {571  return ModFileReader{*this}.Read(SourceName{name, std::strlen(name)},572      true /*intrinsic*/, nullptr, /*silent=*/true);573}574 575void SemanticsContext::UseFortranBuiltinsModule() {576  if (builtinsScope_ == nullptr) {577    builtinsScope_ = GetBuiltinModule("__fortran_builtins");578    if (builtinsScope_) {579      intrinsics_.SupplyBuiltins(*builtinsScope_);580    }581  }582}583 584void SemanticsContext::UsePPCBuiltinTypesModule() {585  if (ppcBuiltinTypesScope_ == nullptr) {586    ppcBuiltinTypesScope_ = GetBuiltinModule("__ppc_types");587  }588}589 590const Scope &SemanticsContext::GetCUDABuiltinsScope() {591  if (!cudaBuiltinsScope_) {592    cudaBuiltinsScope_ = GetBuiltinModule("__cuda_builtins");593    CHECK(cudaBuiltinsScope_.value() != nullptr);594  }595  return **cudaBuiltinsScope_;596}597 598const Scope &SemanticsContext::GetCUDADeviceScope() {599  if (!cudaDeviceScope_) {600    cudaDeviceScope_ = GetBuiltinModule("cudadevice");601    CHECK(cudaDeviceScope_.value() != nullptr);602  }603  return **cudaDeviceScope_;604}605 606void SemanticsContext::UsePPCBuiltinsModule() {607  if (ppcBuiltinsScope_ == nullptr) {608    ppcBuiltinsScope_ = GetBuiltinModule("__ppc_intrinsics");609  }610}611 612parser::Program &SemanticsContext::SaveParseTree(parser::Program &&tree) {613  return modFileParseTrees_.emplace_back(std::move(tree));614}615 616bool Semantics::Perform() {617  // Implicitly USE the __Fortran_builtins module so that special types618  // (e.g., __builtin_team_type) are available to semantics, esp. for619  // intrinsic checking.620  if (!program_.v.empty()) {621    const auto *frontModule{std::get_if<common::Indirection<parser::Module>>(622        &program_.v.front().u)};623    if (frontModule &&624        (std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)625                    .statement.v.source == "__fortran_builtins" ||626            std::get<parser::Statement<parser::ModuleStmt>>(627                frontModule->value().t)628                    .statement.v.source == "__ppc_types")) {629      // Don't try to read the builtins module when we're actually building it.630    } else if (frontModule &&631        (std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)632                    .statement.v.source == "__ppc_intrinsics" ||633            std::get<parser::Statement<parser::ModuleStmt>>(634                frontModule->value().t)635                    .statement.v.source == "mma")) {636      // The derived type definition for the vectors is needed.637      context_.UsePPCBuiltinTypesModule();638    } else {639      context_.UseFortranBuiltinsModule();640      llvm::Triple targetTriple{llvm::Triple(641          llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};642      // Only use __ppc_intrinsics module when targetting PowerPC arch643      if (context_.targetCharacteristics().isPPC()) {644        context_.UsePPCBuiltinTypesModule();645        context_.UsePPCBuiltinsModule();646      }647    }648  }649  return ValidateLabels(context_, program_) &&650      parser::CanonicalizeDo(program_) && // force line break651      CanonicalizeAcc(context_.messages(), program_) &&652      CanonicalizeOmp(context_, program_) && CanonicalizeCUDA(program_) &&653      PerformStatementSemantics(context_, program_) &&654      CanonicalizeDirectives(context_.messages(), program_) &&655      ModFileWriter{context_}656          .set_hermeticModuleFileOutput(hermeticModuleFileOutput_)657          .WriteAll();658}659 660void Semantics::EmitMessages(llvm::raw_ostream &os) {661  // Resolve the CharBlock locations of the Messages to ProvenanceRanges662  // so messages from parsing and semantics are intermixed in source order.663  context_.messages().ResolveProvenances(context_.allCookedSources());664  context_.messages().Emit(os, context_.allCookedSources(),665      /*echoSourceLine=*/true, &context_.languageFeatures(),666      context_.maxErrors(), context_.warningsAreErrors());667}668 669void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) {670  DoDumpSymbols(os, globalScope());671}672 673ProgramTree &SemanticsContext::SaveProgramTree(ProgramTree &&tree) {674  return programTrees_.emplace_back(std::move(tree));675}676 677void Semantics::DumpSymbols(llvm::raw_ostream &os) { context_.DumpSymbols(os); }678 679void Semantics::DumpSymbolsSources(llvm::raw_ostream &os) const {680  NameToSymbolMap symbols;681  GetSymbolNames(context_.globalScope(), symbols);682  const parser::AllCookedSources &allCooked{context_.allCookedSources()};683  for (const auto &pair : symbols) {684    const Symbol &symbol{pair.second};685    if (auto sourceInfo{allCooked.GetSourcePositionRange(symbol.name())}) {686      os << symbol.name().ToString() << ": " << sourceInfo->first.path << ", "687         << sourceInfo->first.line << ", " << sourceInfo->first.column << "-"688         << sourceInfo->second.column << "\n";689    } else if (symbol.has<semantics::UseDetails>()) {690      os << symbol.name().ToString() << ": "691         << symbol.GetUltimate().owner().symbol()->name().ToString() << "\n";692    }693  }694}695 696void DoDumpSymbols(llvm::raw_ostream &os, const Scope &scope, int indent) {697  PutIndent(os, indent);698  os << Scope::EnumToString(scope.kind()) << " scope:";699  if (const auto *symbol{scope.symbol()}) {700    os << ' ' << symbol->name();701  }702  if (scope.alignment().has_value()) {703    os << " size=" << scope.size() << " alignment=" << *scope.alignment();704  }705  if (scope.derivedTypeSpec()) {706    os << " instantiation of " << *scope.derivedTypeSpec();707  }708  os << " sourceRange=" << scope.sourceRange().size() << " bytes\n";709  ++indent;710  for (const auto &pair : scope) {711    const auto &symbol{*pair.second};712    PutIndent(os, indent);713    os << symbol << '\n';714    if (const auto *details{symbol.detailsIf<GenericDetails>()}) {715      if (const auto &type{details->derivedType()}) {716        PutIndent(os, indent);717        os << *type << '\n';718      }719    }720  }721  if (!scope.equivalenceSets().empty()) {722    PutIndent(os, indent);723    os << "Equivalence Sets:";724    for (const auto &set : scope.equivalenceSets()) {725      os << ' ';726      char sep = '(';727      for (const auto &object : set) {728        os << sep << object.AsFortran();729        sep = ',';730      }731      os << ')';732    }733    os << '\n';734  }735  if (!scope.crayPointers().empty()) {736    PutIndent(os, indent);737    os << "Cray Pointers:";738    for (const auto &[pointee, pointer] : scope.crayPointers()) {739      os << " (" << pointer->name() << ',' << pointee << ')';740    }741    os << '\n';742  }743  for (const auto &pair : scope.commonBlocks()) {744    const auto &symbol{*pair.second};745    PutIndent(os, indent);746    os << symbol << '\n';747  }748  for (const auto &child : scope.children()) {749    DoDumpSymbols(os, child, indent);750  }751  --indent;752}753 754static void PutIndent(llvm::raw_ostream &os, int indent) {755  for (int i = 0; i < indent; ++i) {756    os << "  ";757  }758}759 760void SemanticsContext::MapCommonBlockAndCheckConflicts(const Symbol &common) {761  if (!commonBlockMap_) {762    commonBlockMap_ = std::make_unique<CommonBlockMap>();763  }764  commonBlockMap_->MapCommonBlockAndCheckConflicts(*this, common);765}766 767CommonBlockList SemanticsContext::GetCommonBlocks() const {768  if (commonBlockMap_) {769    return commonBlockMap_->GetCommonBlocks();770  }771  return {};772}773 774void SemanticsContext::NoteDefinedSymbol(const Symbol &symbol) {775  isDefined_.insert(symbol);776}777 778bool SemanticsContext::IsSymbolDefined(const Symbol &symbol) const {779  return isDefined_.find(symbol) != isDefined_.end();780}781 782} // namespace Fortran::semantics783