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