xref: /llvm-project/flang/lib/Semantics/semantics.cpp (revision 4f2b65fb80a4b27e5fb88db816ed0ce174c9b1b4)
164ab3302SCarolineConcatto //===-- lib/Semantics/semantics.cpp ---------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "flang/Semantics/semantics.h"
1064ab3302SCarolineConcatto #include "assignment.h"
119aa3dca8SValentin Clement #include "canonicalize-acc.h"
12c6b6e18cSDavid Truby #include "canonicalize-directives.h"
1364ab3302SCarolineConcatto #include "canonicalize-do.h"
1464ab3302SCarolineConcatto #include "canonicalize-omp.h"
159aa3dca8SValentin Clement #include "check-acc-structure.h"
1664ab3302SCarolineConcatto #include "check-allocate.h"
1764ab3302SCarolineConcatto #include "check-arithmeticif.h"
187a77c20dSpeter klausler #include "check-case.h"
1964ab3302SCarolineConcatto #include "check-coarray.h"
20f674ddc1SPeter Klausler #include "check-cuda.h"
2164ab3302SCarolineConcatto #include "check-data.h"
2264ab3302SCarolineConcatto #include "check-deallocate.h"
2364ab3302SCarolineConcatto #include "check-declarations.h"
2464ab3302SCarolineConcatto #include "check-do-forall.h"
2564ab3302SCarolineConcatto #include "check-if-stmt.h"
2664ab3302SCarolineConcatto #include "check-io.h"
2792c1f6bbSVarun Jayathirtha #include "check-namelist.h"
2864ab3302SCarolineConcatto #include "check-nullify.h"
2964ab3302SCarolineConcatto #include "check-omp-structure.h"
3064ab3302SCarolineConcatto #include "check-purity.h"
3164ab3302SCarolineConcatto #include "check-return.h"
32332e6aeaSsameeran joshi #include "check-select-rank.h"
3370ad73b6Ssameeran joshi #include "check-select-type.h"
3464ab3302SCarolineConcatto #include "check-stop.h"
35c353ebbfSTim Keith #include "compute-offsets.h"
3664ab3302SCarolineConcatto #include "mod-file.h"
3764ab3302SCarolineConcatto #include "resolve-labels.h"
3864ab3302SCarolineConcatto #include "resolve-names.h"
3964ab3302SCarolineConcatto #include "rewrite-parse-tree.h"
4064ab3302SCarolineConcatto #include "flang/Common/default-kinds.h"
4164ab3302SCarolineConcatto #include "flang/Parser/parse-tree-visitor.h"
4264ab3302SCarolineConcatto #include "flang/Parser/tools.h"
4364ab3302SCarolineConcatto #include "flang/Semantics/expression.h"
4464ab3302SCarolineConcatto #include "flang/Semantics/scope.h"
4564ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
468670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
47838a4d34SKelvin Li #include "llvm/TargetParser/Host.h"
48838a4d34SKelvin Li #include "llvm/TargetParser/Triple.h"
4964ab3302SCarolineConcatto 
5064ab3302SCarolineConcatto namespace Fortran::semantics {
5164ab3302SCarolineConcatto 
52f80866bdSpeter klausler using NameToSymbolMap = std::multimap<parser::CharBlock, SymbolRef>;
538670e499SCaroline Concatto static void DoDumpSymbols(llvm::raw_ostream &, const Scope &, int indent = 0);
548670e499SCaroline Concatto static void PutIndent(llvm::raw_ostream &, int indent);
5564ab3302SCarolineConcatto 
5664ab3302SCarolineConcatto static void GetSymbolNames(const Scope &scope, NameToSymbolMap &symbols) {
5764ab3302SCarolineConcatto   // Finds all symbol names in the scope without collecting duplicates.
5864ab3302SCarolineConcatto   for (const auto &pair : scope) {
59f80866bdSpeter klausler     symbols.emplace(pair.second->name(), *pair.second);
6064ab3302SCarolineConcatto   }
6164ab3302SCarolineConcatto   for (const auto &pair : scope.commonBlocks()) {
62f80866bdSpeter klausler     symbols.emplace(pair.second->name(), *pair.second);
6364ab3302SCarolineConcatto   }
6464ab3302SCarolineConcatto   for (const auto &child : scope.children()) {
6564ab3302SCarolineConcatto     GetSymbolNames(child, symbols);
6664ab3302SCarolineConcatto   }
6764ab3302SCarolineConcatto }
6864ab3302SCarolineConcatto 
6964ab3302SCarolineConcatto // A parse tree visitor that calls Enter/Leave functions from each checker
7064ab3302SCarolineConcatto // class C supplied as template parameters. Enter is called before the node's
7164ab3302SCarolineConcatto // children are visited, Leave is called after. No two checkers may have the
7264ab3302SCarolineConcatto // same Enter or Leave function. Each checker must be constructible from
7364ab3302SCarolineConcatto // SemanticsContext and have BaseChecker as a virtual base class.
74f674ddc1SPeter Klausler template <typename... C>
75f674ddc1SPeter Klausler class SemanticsVisitor : public virtual BaseChecker, public virtual C... {
7664ab3302SCarolineConcatto public:
7764ab3302SCarolineConcatto   using BaseChecker::Enter;
7864ab3302SCarolineConcatto   using BaseChecker::Leave;
79f674ddc1SPeter Klausler   using C::Enter...;
80f674ddc1SPeter Klausler   using C::Leave...;
8164ab3302SCarolineConcatto   SemanticsVisitor(SemanticsContext &context)
8264ab3302SCarolineConcatto       : C{context}..., context_{context} {}
8364ab3302SCarolineConcatto 
8464ab3302SCarolineConcatto   template <typename N> bool Pre(const N &node) {
8564ab3302SCarolineConcatto     if constexpr (common::HasMember<const N *, ConstructNode>) {
8664ab3302SCarolineConcatto       context_.PushConstruct(node);
8764ab3302SCarolineConcatto     }
8864ab3302SCarolineConcatto     Enter(node);
8964ab3302SCarolineConcatto     return true;
9064ab3302SCarolineConcatto   }
9164ab3302SCarolineConcatto   template <typename N> void Post(const N &node) {
9264ab3302SCarolineConcatto     Leave(node);
9364ab3302SCarolineConcatto     if constexpr (common::HasMember<const N *, ConstructNode>) {
9464ab3302SCarolineConcatto       context_.PopConstruct();
9564ab3302SCarolineConcatto     }
9664ab3302SCarolineConcatto   }
9764ab3302SCarolineConcatto 
9864ab3302SCarolineConcatto   template <typename T> bool Pre(const parser::Statement<T> &node) {
9964ab3302SCarolineConcatto     context_.set_location(node.source);
10064ab3302SCarolineConcatto     Enter(node);
10164ab3302SCarolineConcatto     return true;
10264ab3302SCarolineConcatto   }
10364ab3302SCarolineConcatto   template <typename T> bool Pre(const parser::UnlabeledStatement<T> &node) {
10464ab3302SCarolineConcatto     context_.set_location(node.source);
10564ab3302SCarolineConcatto     Enter(node);
10664ab3302SCarolineConcatto     return true;
10764ab3302SCarolineConcatto   }
10864ab3302SCarolineConcatto   template <typename T> void Post(const parser::Statement<T> &node) {
10964ab3302SCarolineConcatto     Leave(node);
11064ab3302SCarolineConcatto     context_.set_location(std::nullopt);
11164ab3302SCarolineConcatto   }
11264ab3302SCarolineConcatto   template <typename T> void Post(const parser::UnlabeledStatement<T> &node) {
11364ab3302SCarolineConcatto     Leave(node);
11464ab3302SCarolineConcatto     context_.set_location(std::nullopt);
11564ab3302SCarolineConcatto   }
11664ab3302SCarolineConcatto 
11764ab3302SCarolineConcatto   bool Walk(const parser::Program &program) {
11864ab3302SCarolineConcatto     parser::Walk(program, *this);
11964ab3302SCarolineConcatto     return !context_.AnyFatalError();
12064ab3302SCarolineConcatto   }
12164ab3302SCarolineConcatto 
12264ab3302SCarolineConcatto private:
12364ab3302SCarolineConcatto   SemanticsContext &context_;
12464ab3302SCarolineConcatto };
12564ab3302SCarolineConcatto 
126455ed8deSpeter klausler class MiscChecker : public virtual BaseChecker {
127c42f6314Speter klausler public:
128455ed8deSpeter klausler   explicit MiscChecker(SemanticsContext &context) : context_{context} {}
129c42f6314Speter klausler   void Leave(const parser::EntryStmt &) {
130c42f6314Speter klausler     if (!context_.constructStack().empty()) { // C1571
131c42f6314Speter klausler       context_.Say("ENTRY may not appear in an executable construct"_err_en_US);
132c42f6314Speter klausler     }
133c42f6314Speter klausler   }
134455ed8deSpeter klausler   void Leave(const parser::AssignStmt &stmt) {
135455ed8deSpeter klausler     CheckAssignGotoName(std::get<parser::Name>(stmt.t));
136455ed8deSpeter klausler   }
137455ed8deSpeter klausler   void Leave(const parser::AssignedGotoStmt &stmt) {
138455ed8deSpeter klausler     CheckAssignGotoName(std::get<parser::Name>(stmt.t));
139455ed8deSpeter klausler   }
140c42f6314Speter klausler 
141c42f6314Speter klausler private:
142455ed8deSpeter klausler   void CheckAssignGotoName(const parser::Name &name) {
143455ed8deSpeter klausler     if (context_.HasError(name.symbol)) {
144455ed8deSpeter klausler       return;
145455ed8deSpeter klausler     }
146455ed8deSpeter klausler     const Symbol &symbol{DEREF(name.symbol)};
147455ed8deSpeter klausler     auto type{evaluate::DynamicType::From(symbol)};
148455ed8deSpeter klausler     if (!IsVariableName(symbol) || symbol.Rank() != 0 || !type ||
149455ed8deSpeter klausler         type->category() != TypeCategory::Integer ||
150455ed8deSpeter klausler         type->kind() !=
151455ed8deSpeter klausler             context_.defaultKinds().GetDefaultKind(TypeCategory::Integer)) {
152455ed8deSpeter klausler       context_
153455ed8deSpeter klausler           .Say(name.source,
154455ed8deSpeter klausler               "'%s' must be a default integer scalar variable"_err_en_US,
155455ed8deSpeter klausler               name.source)
156455ed8deSpeter klausler           .Attach(symbol.name(), "Declaration of '%s'"_en_US, symbol.name());
157455ed8deSpeter klausler     }
158455ed8deSpeter klausler   }
159455ed8deSpeter klausler 
160c42f6314Speter klausler   SemanticsContext &context_;
161c42f6314Speter klausler };
162c42f6314Speter klausler 
16333c27f28SPeter Klausler static void WarnUndefinedFunctionResult(
16433c27f28SPeter Klausler     SemanticsContext &context, const Scope &scope) {
16533c27f28SPeter Klausler   auto WasDefined{[&context](const Symbol &symbol) {
16633c27f28SPeter Klausler     return context.IsSymbolDefined(symbol) ||
16733c27f28SPeter Klausler         IsInitialized(symbol, /*ignoreDataStatements=*/true,
16833c27f28SPeter Klausler             /*ignoreAllocatable=*/true, /*ignorePointer=*/true);
16933c27f28SPeter Klausler   }};
17033c27f28SPeter Klausler   if (const Symbol * symbol{scope.symbol()}) {
17133c27f28SPeter Klausler     if (const auto *subp{symbol->detailsIf<SubprogramDetails>()}) {
17233c27f28SPeter Klausler       if (subp->isFunction() && !subp->isInterface() && !subp->stmtFunction()) {
17333c27f28SPeter Klausler         bool wasDefined{WasDefined(subp->result())};
17433c27f28SPeter Klausler         if (!wasDefined) {
17533c27f28SPeter Klausler           // Definitions of ENTRY result variables also count.
17633c27f28SPeter Klausler           for (const auto &pair : scope) {
17733c27f28SPeter Klausler             const Symbol &local{*pair.second};
17833c27f28SPeter Klausler             if (IsFunctionResult(local) && WasDefined(local)) {
17933c27f28SPeter Klausler               wasDefined = true;
18033c27f28SPeter Klausler               break;
18133c27f28SPeter Klausler             }
18233c27f28SPeter Klausler           }
18333c27f28SPeter Klausler           if (!wasDefined) {
1840f973ac7SPeter Klausler             context.Warn(common::UsageWarning::UndefinedFunctionResult,
18533c27f28SPeter Klausler                 symbol->name(), "Function result is never defined"_warn_en_US);
18633c27f28SPeter Klausler           }
18733c27f28SPeter Klausler         }
18833c27f28SPeter Klausler       }
18933c27f28SPeter Klausler     }
19033c27f28SPeter Klausler   }
19133c27f28SPeter Klausler   if (!scope.IsModuleFile()) {
19233c27f28SPeter Klausler     for (const Scope &child : scope.children()) {
19333c27f28SPeter Klausler       WarnUndefinedFunctionResult(context, child);
19433c27f28SPeter Klausler     }
19533c27f28SPeter Klausler   }
19633c27f28SPeter Klausler }
19733c27f28SPeter Klausler 
19864ab3302SCarolineConcatto using StatementSemanticsPass1 = ExprChecker;
199f674ddc1SPeter Klausler using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker,
200f674ddc1SPeter Klausler     ArithmeticIfStmtChecker, AssignmentChecker, CaseChecker, CoarrayChecker,
201f674ddc1SPeter Klausler     DataChecker, DeallocateChecker, DoForallChecker, IfStmtChecker, IoChecker,
202f674ddc1SPeter Klausler     MiscChecker, NamelistChecker, NullifyChecker, PurityChecker,
203f674ddc1SPeter Klausler     ReturnStmtChecker, SelectRankConstructChecker, SelectTypeChecker,
204f674ddc1SPeter Klausler     StopChecker>;
20564ab3302SCarolineConcatto 
20664ab3302SCarolineConcatto static bool PerformStatementSemantics(
20764ab3302SCarolineConcatto     SemanticsContext &context, parser::Program &program) {
20852a1346bSPeter Klausler   ResolveNames(context, program, context.globalScope());
20964ab3302SCarolineConcatto   RewriteParseTree(context, program);
2106aa3591eSpeter klausler   ComputeOffsets(context, context.globalScope());
21164ab3302SCarolineConcatto   CheckDeclarations(context);
21264ab3302SCarolineConcatto   StatementSemanticsPass1{context}.Walk(program);
213a20d48d7Speter klausler   StatementSemanticsPass2 pass2{context};
214a20d48d7Speter klausler   pass2.Walk(program);
215c988e78fSValentin Clement   if (context.languageFeatures().IsEnabled(common::LanguageFeature::OpenACC)) {
216c988e78fSValentin Clement     SemanticsVisitor<AccStructureChecker>{context}.Walk(program);
217c988e78fSValentin Clement   }
218c988e78fSValentin Clement   if (context.languageFeatures().IsEnabled(common::LanguageFeature::OpenMP)) {
219c988e78fSValentin Clement     SemanticsVisitor<OmpStructureChecker>{context}.Walk(program);
220c988e78fSValentin Clement   }
221c988e78fSValentin Clement   if (context.languageFeatures().IsEnabled(common::LanguageFeature::CUDA)) {
222c988e78fSValentin Clement     SemanticsVisitor<CUDAChecker>{context}.Walk(program);
223f674ddc1SPeter Klausler   }
224b949a6f5SPeter Klausler   if (!context.messages().AnyFatalError()) {
22533c27f28SPeter Klausler     WarnUndefinedFunctionResult(context, context.globalScope());
22633c27f28SPeter Klausler   }
227b949a6f5SPeter Klausler   if (!context.AnyFatalError()) {
228a20d48d7Speter klausler     pass2.CompileDataInitializationsIntoInitializers();
229a20d48d7Speter klausler   }
23064ab3302SCarolineConcatto   return !context.AnyFatalError();
23164ab3302SCarolineConcatto }
23264ab3302SCarolineConcatto 
2332c8cb9acSJean Perier /// This class keeps track of the common block appearances with the biggest size
2342c8cb9acSJean Perier /// and with an initial value (if any) in a program. This allows reporting
2352c8cb9acSJean Perier /// conflicting initialization and warning about appearances of a same
2362c8cb9acSJean Perier /// named common block with different sizes. The biggest common block size and
2372c8cb9acSJean Perier /// initialization (if any) can later be provided so that lowering can generate
2382c8cb9acSJean Perier /// the correct symbol size and initial values, even when named common blocks
2392c8cb9acSJean Perier /// appears with different sizes and are initialized outside of block data.
2402c8cb9acSJean Perier class CommonBlockMap {
2412c8cb9acSJean Perier private:
2422c8cb9acSJean Perier   struct CommonBlockInfo {
2432c8cb9acSJean Perier     // Common block symbol for the appearance with the biggest size.
2442c8cb9acSJean Perier     SymbolRef biggestSize;
2452c8cb9acSJean Perier     // Common block symbol for the appearance with the initialized members (if
2462c8cb9acSJean Perier     // any).
2472c8cb9acSJean Perier     std::optional<SymbolRef> initialization;
2482c8cb9acSJean Perier   };
2492c8cb9acSJean Perier 
2502c8cb9acSJean Perier public:
2512c8cb9acSJean Perier   void MapCommonBlockAndCheckConflicts(
2522c8cb9acSJean Perier       SemanticsContext &context, const Symbol &common) {
2532c8cb9acSJean Perier     const Symbol *isInitialized{CommonBlockIsInitialized(common)};
2546ffea74fSjeanPerier     // Merge common according to the name they will have in the object files.
2556ffea74fSjeanPerier     // This allows merging BIND(C) and non BIND(C) common block instead of
2566ffea74fSjeanPerier     // later crashing. This "merge" matches what ifort/gfortran/nvfortran are
2576ffea74fSjeanPerier     // doing and what a linker would do if the definition were in distinct
2586ffea74fSjeanPerier     // files.
2596ffea74fSjeanPerier     std::string commonName{
2606ffea74fSjeanPerier         GetCommonBlockObjectName(common, context.underscoring())};
2616ffea74fSjeanPerier     auto [it, firstAppearance] = commonBlocks_.insert({commonName,
2622c8cb9acSJean Perier         isInitialized ? CommonBlockInfo{common, common}
2632c8cb9acSJean Perier                       : CommonBlockInfo{common, std::nullopt}});
2642c8cb9acSJean Perier     if (!firstAppearance) {
2652c8cb9acSJean Perier       CommonBlockInfo &info{it->second};
2662c8cb9acSJean Perier       if (isInitialized) {
2672c8cb9acSJean Perier         if (info.initialization.has_value() &&
2682c8cb9acSJean Perier             &**info.initialization != &common) {
2692c8cb9acSJean Perier           // Use the location of the initialization in the error message because
2702c8cb9acSJean Perier           // common block symbols may have no location if they are blank
2712c8cb9acSJean Perier           // commons.
2722c8cb9acSJean Perier           const Symbol &previousInit{
2732c8cb9acSJean Perier               DEREF(CommonBlockIsInitialized(**info.initialization))};
2742c8cb9acSJean Perier           context
2752c8cb9acSJean Perier               .Say(isInitialized->name(),
2762c8cb9acSJean Perier                   "Multiple initialization of COMMON block /%s/"_err_en_US,
2772c8cb9acSJean Perier                   common.name())
2782c8cb9acSJean Perier               .Attach(previousInit.name(),
2792c8cb9acSJean Perier                   "Previous initialization of COMMON block /%s/"_en_US,
2802c8cb9acSJean Perier                   common.name());
2812c8cb9acSJean Perier         } else {
2822c8cb9acSJean Perier           info.initialization = common;
2832c8cb9acSJean Perier         }
2842c8cb9acSJean Perier       }
2850f973ac7SPeter Klausler       if (common.size() != info.biggestSize->size() && !common.name().empty()) {
2860f973ac7SPeter Klausler         if (auto *msg{context.Warn(common::LanguageFeature::DistinctCommonSizes,
2870f973ac7SPeter Klausler                 common.name(),
2882c8cb9acSJean Perier                 "A named COMMON block should have the same size everywhere it appears (%zd bytes here)"_port_en_US,
2890f973ac7SPeter Klausler                 common.size())}) {
2900f973ac7SPeter Klausler           msg->Attach(info.biggestSize->name(),
2912c8cb9acSJean Perier               "Previously defined with a size of %zd bytes"_en_US,
2922c8cb9acSJean Perier               info.biggestSize->size());
2932c8cb9acSJean Perier         }
2940f973ac7SPeter Klausler       }
2952c8cb9acSJean Perier       if (common.size() > info.biggestSize->size()) {
2962c8cb9acSJean Perier         info.biggestSize = common;
2972c8cb9acSJean Perier       }
2982c8cb9acSJean Perier     }
2992c8cb9acSJean Perier   }
3002c8cb9acSJean Perier 
3012c8cb9acSJean Perier   CommonBlockList GetCommonBlocks() const {
3022c8cb9acSJean Perier     CommonBlockList result;
3032c8cb9acSJean Perier     for (const auto &[_, blockInfo] : commonBlocks_) {
3042c8cb9acSJean Perier       result.emplace_back(
3052c8cb9acSJean Perier           std::make_pair(blockInfo.initialization ? *blockInfo.initialization
3062c8cb9acSJean Perier                                                   : blockInfo.biggestSize,
3072c8cb9acSJean Perier               blockInfo.biggestSize->size()));
3082c8cb9acSJean Perier     }
3092c8cb9acSJean Perier     return result;
3102c8cb9acSJean Perier   }
3112c8cb9acSJean Perier 
3122c8cb9acSJean Perier private:
3132c8cb9acSJean Perier   /// Return the symbol of an initialized member if a COMMON block
3142c8cb9acSJean Perier   /// is initalized. Otherwise, return nullptr.
3152c8cb9acSJean Perier   static Symbol *CommonBlockIsInitialized(const Symbol &common) {
3162c8cb9acSJean Perier     const auto &commonDetails =
3172c8cb9acSJean Perier         common.get<Fortran::semantics::CommonBlockDetails>();
3182c8cb9acSJean Perier 
3192c8cb9acSJean Perier     for (const auto &member : commonDetails.objects()) {
3202c8cb9acSJean Perier       if (IsInitialized(*member)) {
3212c8cb9acSJean Perier         return &*member;
3222c8cb9acSJean Perier       }
3232c8cb9acSJean Perier     }
3242c8cb9acSJean Perier 
3252c8cb9acSJean Perier     // Common block may be initialized via initialized variables that are in an
3262c8cb9acSJean Perier     // equivalence with the common block members.
3272c8cb9acSJean Perier     for (const Fortran::semantics::EquivalenceSet &set :
3282c8cb9acSJean Perier         common.owner().equivalenceSets()) {
3292c8cb9acSJean Perier       for (const Fortran::semantics::EquivalenceObject &obj : set) {
3302c8cb9acSJean Perier         if (!obj.symbol.test(
3312c8cb9acSJean Perier                 Fortran::semantics::Symbol::Flag::CompilerCreated)) {
3322c8cb9acSJean Perier           if (FindCommonBlockContaining(obj.symbol) == &common &&
3332c8cb9acSJean Perier               IsInitialized(obj.symbol)) {
3342c8cb9acSJean Perier             return &obj.symbol;
3352c8cb9acSJean Perier           }
3362c8cb9acSJean Perier         }
3372c8cb9acSJean Perier       }
3382c8cb9acSJean Perier     }
3392c8cb9acSJean Perier     return nullptr;
3402c8cb9acSJean Perier   }
3416ffea74fSjeanPerier 
3426ffea74fSjeanPerier   std::map<std::string, CommonBlockInfo> commonBlocks_;
3432c8cb9acSJean Perier };
3442c8cb9acSJean Perier 
34564ab3302SCarolineConcatto SemanticsContext::SemanticsContext(
34664ab3302SCarolineConcatto     const common::IntrinsicTypeDefaultKinds &defaultKinds,
34764ab3302SCarolineConcatto     const common::LanguageFeatureControl &languageFeatures,
3483b20a833SKrzysztof Parzyszek     const common::LangOptions &langOpts,
34992a54197Speter klausler     parser::AllCookedSources &allCookedSources)
35064ab3302SCarolineConcatto     : defaultKinds_{defaultKinds}, languageFeatures_{languageFeatures},
3513b20a833SKrzysztof Parzyszek       langOpts_{langOpts}, allCookedSources_{allCookedSources},
35264ab3302SCarolineConcatto       intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds_)},
35352a1346bSPeter Klausler       globalScope_{*this}, intrinsicModulesScope_{globalScope_.MakeScope(
35452a1346bSPeter Klausler                                Scope::Kind::IntrinsicModules, nullptr)},
35523c2bedfSPeter Klausler       foldingContext_{parser::ContextualMessages{&messages_}, defaultKinds_,
356181eab27SjeanPerier           intrinsics_, targetCharacteristics_, languageFeatures_, tempNames_} {}
35764ab3302SCarolineConcatto 
35864ab3302SCarolineConcatto SemanticsContext::~SemanticsContext() {}
35964ab3302SCarolineConcatto 
36064ab3302SCarolineConcatto int SemanticsContext::GetDefaultKind(TypeCategory category) const {
36164ab3302SCarolineConcatto   return defaultKinds_.GetDefaultKind(category);
36264ab3302SCarolineConcatto }
36364ab3302SCarolineConcatto 
36464ab3302SCarolineConcatto const DeclTypeSpec &SemanticsContext::MakeNumericType(
36564ab3302SCarolineConcatto     TypeCategory category, int kind) {
36664ab3302SCarolineConcatto   if (kind == 0) {
36764ab3302SCarolineConcatto     kind = GetDefaultKind(category);
36864ab3302SCarolineConcatto   }
36964ab3302SCarolineConcatto   return globalScope_.MakeNumericType(category, KindExpr{kind});
37064ab3302SCarolineConcatto }
37164ab3302SCarolineConcatto const DeclTypeSpec &SemanticsContext::MakeLogicalType(int kind) {
37264ab3302SCarolineConcatto   if (kind == 0) {
37364ab3302SCarolineConcatto     kind = GetDefaultKind(TypeCategory::Logical);
37464ab3302SCarolineConcatto   }
37564ab3302SCarolineConcatto   return globalScope_.MakeLogicalType(KindExpr{kind});
37664ab3302SCarolineConcatto }
37764ab3302SCarolineConcatto 
37864ab3302SCarolineConcatto bool SemanticsContext::AnyFatalError() const {
37964ab3302SCarolineConcatto   return !messages_.empty() &&
38064ab3302SCarolineConcatto       (warningsAreErrors_ || messages_.AnyFatalError());
38164ab3302SCarolineConcatto }
38264ab3302SCarolineConcatto bool SemanticsContext::HasError(const Symbol &symbol) {
383627e9007STim Keith   return errorSymbols_.count(symbol) > 0;
38464ab3302SCarolineConcatto }
38564ab3302SCarolineConcatto bool SemanticsContext::HasError(const Symbol *symbol) {
386627e9007STim Keith   return !symbol || HasError(*symbol);
38764ab3302SCarolineConcatto }
38864ab3302SCarolineConcatto bool SemanticsContext::HasError(const parser::Name &name) {
38964ab3302SCarolineConcatto   return HasError(name.symbol);
39064ab3302SCarolineConcatto }
391627e9007STim Keith void SemanticsContext::SetError(const Symbol &symbol, bool value) {
39264ab3302SCarolineConcatto   if (value) {
393627e9007STim Keith     CheckError(symbol);
394627e9007STim Keith     errorSymbols_.emplace(symbol);
39564ab3302SCarolineConcatto   }
39664ab3302SCarolineConcatto }
397627e9007STim Keith void SemanticsContext::CheckError(const Symbol &symbol) {
398627e9007STim Keith   if (!AnyFatalError()) {
399627e9007STim Keith     std::string buf;
400627e9007STim Keith     llvm::raw_string_ostream ss{buf};
401627e9007STim Keith     ss << symbol;
402627e9007STim Keith     common::die(
403627e9007STim Keith         "No error was reported but setting error on: %s", ss.str().c_str());
404627e9007STim Keith   }
40564ab3302SCarolineConcatto }
40664ab3302SCarolineConcatto 
407e727bda1SPeter Klausler bool SemanticsContext::ScopeIndexComparator::operator()(
408e727bda1SPeter Klausler     parser::CharBlock x, parser::CharBlock y) const {
409e727bda1SPeter Klausler   return x.begin() < y.begin() ||
410e727bda1SPeter Klausler       (x.begin() == y.begin() && x.size() > y.size());
411e727bda1SPeter Klausler }
412e727bda1SPeter Klausler 
413e727bda1SPeter Klausler auto SemanticsContext::SearchScopeIndex(parser::CharBlock source)
414e727bda1SPeter Klausler     -> ScopeIndex::iterator {
415e727bda1SPeter Klausler   if (!scopeIndex_.empty()) {
416e727bda1SPeter Klausler     auto iter{scopeIndex_.upper_bound(source)};
417e727bda1SPeter Klausler     auto begin{scopeIndex_.begin()};
418e727bda1SPeter Klausler     do {
419e727bda1SPeter Klausler       --iter;
420e727bda1SPeter Klausler       if (iter->first.Contains(source)) {
421e727bda1SPeter Klausler         return iter;
422e727bda1SPeter Klausler       }
423e727bda1SPeter Klausler     } while (iter != begin);
424e727bda1SPeter Klausler   }
425e727bda1SPeter Klausler   return scopeIndex_.end();
426e727bda1SPeter Klausler }
427e727bda1SPeter Klausler 
42864ab3302SCarolineConcatto const Scope &SemanticsContext::FindScope(parser::CharBlock source) const {
42964ab3302SCarolineConcatto   return const_cast<SemanticsContext *>(this)->FindScope(source);
43064ab3302SCarolineConcatto }
43164ab3302SCarolineConcatto 
43264ab3302SCarolineConcatto Scope &SemanticsContext::FindScope(parser::CharBlock source) {
433e727bda1SPeter Klausler   if (auto iter{SearchScopeIndex(source)}; iter != scopeIndex_.end()) {
434e727bda1SPeter Klausler     return iter->second;
43564ab3302SCarolineConcatto   } else {
43652a1346bSPeter Klausler     common::die(
43752a1346bSPeter Klausler         "SemanticsContext::FindScope(): invalid source location for '%s'",
43852a1346bSPeter Klausler         source.ToString().c_str());
43964ab3302SCarolineConcatto   }
44064ab3302SCarolineConcatto }
44164ab3302SCarolineConcatto 
442e727bda1SPeter Klausler void SemanticsContext::UpdateScopeIndex(
443e727bda1SPeter Klausler     Scope &scope, parser::CharBlock newSource) {
444e727bda1SPeter Klausler   if (scope.sourceRange().empty()) {
445e727bda1SPeter Klausler     scopeIndex_.emplace(newSource, scope);
446e727bda1SPeter Klausler   } else if (!scope.sourceRange().Contains(newSource)) {
447e727bda1SPeter Klausler     auto iter{SearchScopeIndex(scope.sourceRange())};
448e727bda1SPeter Klausler     CHECK(iter != scopeIndex_.end());
449e727bda1SPeter Klausler     while (&iter->second != &scope) {
450e727bda1SPeter Klausler       CHECK(iter != scopeIndex_.begin());
451e727bda1SPeter Klausler       --iter;
452e727bda1SPeter Klausler     }
453e727bda1SPeter Klausler     scopeIndex_.erase(iter);
454e727bda1SPeter Klausler     scopeIndex_.emplace(newSource, scope);
455e727bda1SPeter Klausler   }
456e727bda1SPeter Klausler }
457e727bda1SPeter Klausler 
45873506256SPeter Klausler bool SemanticsContext::IsInModuleFile(parser::CharBlock source) const {
45973506256SPeter Klausler   for (const Scope *scope{&FindScope(source)}; !scope->IsGlobal();
46073506256SPeter Klausler        scope = &scope->parent()) {
46173506256SPeter Klausler     if (scope->IsModuleFile()) {
46273506256SPeter Klausler       return true;
46373506256SPeter Klausler     }
46473506256SPeter Klausler   }
46573506256SPeter Klausler   return false;
46673506256SPeter Klausler }
46773506256SPeter Klausler 
46864ab3302SCarolineConcatto void SemanticsContext::PopConstruct() {
46964ab3302SCarolineConcatto   CHECK(!constructStack_.empty());
47064ab3302SCarolineConcatto   constructStack_.pop_back();
47164ab3302SCarolineConcatto }
47264ab3302SCarolineConcatto 
4730f973ac7SPeter Klausler parser::Message *SemanticsContext::CheckIndexVarRedefine(
4740f973ac7SPeter Klausler     const parser::CharBlock &location, const Symbol &variable,
4750f973ac7SPeter Klausler     parser::MessageFixedText &&message) {
476a50bb84eSpeter klausler   const Symbol &symbol{ResolveAssociations(variable)};
477a50bb84eSpeter klausler   auto it{activeIndexVars_.find(symbol)};
47864ab3302SCarolineConcatto   if (it != activeIndexVars_.end()) {
47964ab3302SCarolineConcatto     std::string kind{EnumToString(it->second.kind)};
4800f973ac7SPeter Klausler     return &Say(location, std::move(message), kind, symbol.name())
4810f973ac7SPeter Klausler                 .Attach(
4820f973ac7SPeter Klausler                     it->second.location, "Enclosing %s construct"_en_US, kind);
4830f973ac7SPeter Klausler   } else {
4840f973ac7SPeter Klausler     return nullptr;
48564ab3302SCarolineConcatto   }
48664ab3302SCarolineConcatto }
48764ab3302SCarolineConcatto 
48864ab3302SCarolineConcatto void SemanticsContext::WarnIndexVarRedefine(
48964ab3302SCarolineConcatto     const parser::CharBlock &location, const Symbol &variable) {
490505f6da1SPeter Klausler   if (ShouldWarn(common::UsageWarning::IndexVarRedefinition)) {
4910f973ac7SPeter Klausler     if (auto *msg{CheckIndexVarRedefine(location, variable,
4920f973ac7SPeter Klausler             "Possible redefinition of %s variable '%s'"_warn_en_US)}) {
4930f973ac7SPeter Klausler       msg->set_usageWarning(common::UsageWarning::IndexVarRedefinition);
4940f973ac7SPeter Klausler     }
49564ab3302SCarolineConcatto   }
496505f6da1SPeter Klausler }
49764ab3302SCarolineConcatto 
49864ab3302SCarolineConcatto void SemanticsContext::CheckIndexVarRedefine(
49964ab3302SCarolineConcatto     const parser::CharBlock &location, const Symbol &variable) {
50064ab3302SCarolineConcatto   CheckIndexVarRedefine(
50164ab3302SCarolineConcatto       location, variable, "Cannot redefine %s variable '%s'"_err_en_US);
50264ab3302SCarolineConcatto }
50364ab3302SCarolineConcatto 
50464ab3302SCarolineConcatto void SemanticsContext::CheckIndexVarRedefine(const parser::Variable &variable) {
50564ab3302SCarolineConcatto   if (const Symbol * entity{GetLastName(variable).symbol}) {
50664ab3302SCarolineConcatto     CheckIndexVarRedefine(variable.GetSource(), *entity);
50764ab3302SCarolineConcatto   }
50864ab3302SCarolineConcatto }
50964ab3302SCarolineConcatto 
51064ab3302SCarolineConcatto void SemanticsContext::CheckIndexVarRedefine(const parser::Name &name) {
51164ab3302SCarolineConcatto   if (const Symbol * entity{name.symbol}) {
51264ab3302SCarolineConcatto     CheckIndexVarRedefine(name.source, *entity);
51364ab3302SCarolineConcatto   }
51464ab3302SCarolineConcatto }
51564ab3302SCarolineConcatto 
51664ab3302SCarolineConcatto void SemanticsContext::ActivateIndexVar(
51764ab3302SCarolineConcatto     const parser::Name &name, IndexVarKind kind) {
51864ab3302SCarolineConcatto   CheckIndexVarRedefine(name);
51964ab3302SCarolineConcatto   if (const Symbol * indexVar{name.symbol}) {
520a50bb84eSpeter klausler     activeIndexVars_.emplace(
521a50bb84eSpeter klausler         ResolveAssociations(*indexVar), IndexVarInfo{name.source, kind});
52264ab3302SCarolineConcatto   }
52364ab3302SCarolineConcatto }
52464ab3302SCarolineConcatto 
52564ab3302SCarolineConcatto void SemanticsContext::DeactivateIndexVar(const parser::Name &name) {
52664ab3302SCarolineConcatto   if (Symbol * indexVar{name.symbol}) {
527a50bb84eSpeter klausler     auto it{activeIndexVars_.find(ResolveAssociations(*indexVar))};
52864ab3302SCarolineConcatto     if (it != activeIndexVars_.end() && it->second.location == name.source) {
52964ab3302SCarolineConcatto       activeIndexVars_.erase(it);
53064ab3302SCarolineConcatto     }
53164ab3302SCarolineConcatto   }
53264ab3302SCarolineConcatto }
53364ab3302SCarolineConcatto 
53464ab3302SCarolineConcatto SymbolVector SemanticsContext::GetIndexVars(IndexVarKind kind) {
53564ab3302SCarolineConcatto   SymbolVector result;
53664ab3302SCarolineConcatto   for (const auto &[symbol, info] : activeIndexVars_) {
53764ab3302SCarolineConcatto     if (info.kind == kind) {
53864ab3302SCarolineConcatto       result.push_back(symbol);
53964ab3302SCarolineConcatto     }
54064ab3302SCarolineConcatto   }
54164ab3302SCarolineConcatto   return result;
54264ab3302SCarolineConcatto }
54364ab3302SCarolineConcatto 
5441bd083b5Speter klausler SourceName SemanticsContext::SaveTempName(std::string &&name) {
5451bd083b5Speter klausler   return {*tempNames_.emplace(std::move(name)).first};
5461bd083b5Speter klausler }
5471bd083b5Speter klausler 
5484ac617f4Speter klausler SourceName SemanticsContext::GetTempName(const Scope &scope) {
5494ac617f4Speter klausler   for (const auto &str : tempNames_) {
550c14cf92bSPeter Klausler     if (IsTempName(str)) {
5514ac617f4Speter klausler       SourceName name{str};
5524ac617f4Speter klausler       if (scope.find(name) == scope.end()) {
5534ac617f4Speter klausler         return name;
5544ac617f4Speter klausler       }
5554ac617f4Speter klausler     }
5561bd083b5Speter klausler   }
5571bd083b5Speter klausler   return SaveTempName(".F18."s + std::to_string(tempNames_.size()));
5584ac617f4Speter klausler }
5594ac617f4Speter klausler 
560c14cf92bSPeter Klausler bool SemanticsContext::IsTempName(const std::string &name) {
561c14cf92bSPeter Klausler   return name.size() > 5 && name.substr(0, 5) == ".F18.";
562c14cf92bSPeter Klausler }
563c14cf92bSPeter Klausler 
56452711fb8Speter klausler Scope *SemanticsContext::GetBuiltinModule(const char *name) {
56552a1346bSPeter Klausler   return ModFileReader{*this}.Read(SourceName{name, std::strlen(name)},
566f7a15e00SPeter Klausler       true /*intrinsic*/, nullptr, /*silent=*/true);
56752711fb8Speter klausler }
56852711fb8Speter klausler 
56952711fb8Speter klausler void SemanticsContext::UseFortranBuiltinsModule() {
57052711fb8Speter klausler   if (builtinsScope_ == nullptr) {
57152711fb8Speter klausler     builtinsScope_ = GetBuiltinModule("__fortran_builtins");
57252711fb8Speter klausler     if (builtinsScope_) {
57352711fb8Speter klausler       intrinsics_.SupplyBuiltins(*builtinsScope_);
57452711fb8Speter klausler     }
57552711fb8Speter klausler   }
57652711fb8Speter klausler }
57752711fb8Speter klausler 
5787e82379dSKelvin Li void SemanticsContext::UsePPCBuiltinTypesModule() {
579ef934174SKelvin Li   if (ppcBuiltinTypesScope_ == nullptr) {
5807e82379dSKelvin Li     ppcBuiltinTypesScope_ = GetBuiltinModule("__ppc_types");
581ef934174SKelvin Li   }
582ef934174SKelvin Li }
583ef934174SKelvin Li 
584f674ddc1SPeter Klausler const Scope &SemanticsContext::GetCUDABuiltinsScope() {
585f674ddc1SPeter Klausler   if (!cudaBuiltinsScope_) {
586f674ddc1SPeter Klausler     cudaBuiltinsScope_ = GetBuiltinModule("__cuda_builtins");
587f674ddc1SPeter Klausler     CHECK(cudaBuiltinsScope_.value() != nullptr);
58827f71807SPeter Klausler   }
589f674ddc1SPeter Klausler   return **cudaBuiltinsScope_;
59027f71807SPeter Klausler }
59127f71807SPeter Klausler 
5926d50a79bSValentin Clement (バレンタイン クレメン) const Scope &SemanticsContext::GetCUDADeviceScope() {
5936d50a79bSValentin Clement (バレンタイン クレメン)   if (!cudaDeviceScope_) {
5946d50a79bSValentin Clement (バレンタイン クレメン)     cudaDeviceScope_ = GetBuiltinModule("cudadevice");
5956d50a79bSValentin Clement (バレンタイン クレメン)     CHECK(cudaDeviceScope_.value() != nullptr);
5966d50a79bSValentin Clement (バレンタイン クレメン)   }
5976d50a79bSValentin Clement (バレンタイン クレメン)   return **cudaDeviceScope_;
5986d50a79bSValentin Clement (バレンタイン クレメン) }
5996d50a79bSValentin Clement (バレンタイン クレメン) 
6007e82379dSKelvin Li void SemanticsContext::UsePPCBuiltinsModule() {
601838a4d34SKelvin Li   if (ppcBuiltinsScope_ == nullptr) {
6027e82379dSKelvin Li     ppcBuiltinsScope_ = GetBuiltinModule("__ppc_intrinsics");
603838a4d34SKelvin Li   }
604838a4d34SKelvin Li }
605838a4d34SKelvin Li 
606f4bb211aSPeter Klausler parser::Program &SemanticsContext::SaveParseTree(parser::Program &&tree) {
607f4bb211aSPeter Klausler   return modFileParseTrees_.emplace_back(std::move(tree));
608f4bb211aSPeter Klausler }
609f4bb211aSPeter Klausler 
61064ab3302SCarolineConcatto bool Semantics::Perform() {
61152711fb8Speter klausler   // Implicitly USE the __Fortran_builtins module so that special types
61252711fb8Speter klausler   // (e.g., __builtin_team_type) are available to semantics, esp. for
61352711fb8Speter klausler   // intrinsic checking.
61452711fb8Speter klausler   if (!program_.v.empty()) {
61552711fb8Speter klausler     const auto *frontModule{std::get_if<common::Indirection<parser::Module>>(
61652711fb8Speter klausler         &program_.v.front().u)};
61752711fb8Speter klausler     if (frontModule &&
618838a4d34SKelvin Li         (std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
619838a4d34SKelvin Li                     .statement.v.source == "__fortran_builtins" ||
620838a4d34SKelvin Li             std::get<parser::Statement<parser::ModuleStmt>>(
621838a4d34SKelvin Li                 frontModule->value().t)
6227e82379dSKelvin Li                     .statement.v.source == "__ppc_types")) {
62352711fb8Speter klausler       // Don't try to read the builtins module when we're actually building it.
624a9e1d2e7SKelvin Li     } else if (frontModule &&
6252c2d427cSKelvin Li         (std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
6262c2d427cSKelvin Li                     .statement.v.source == "__ppc_intrinsics" ||
6272c2d427cSKelvin Li             std::get<parser::Statement<parser::ModuleStmt>>(
6282c2d427cSKelvin Li                 frontModule->value().t)
6292c2d427cSKelvin Li                     .statement.v.source == "mma")) {
630a9e1d2e7SKelvin Li       // The derived type definition for the vectors is needed.
6317e82379dSKelvin Li       context_.UsePPCBuiltinTypesModule();
63252711fb8Speter klausler     } else {
63352711fb8Speter klausler       context_.UseFortranBuiltinsModule();
634838a4d34SKelvin Li       llvm::Triple targetTriple{llvm::Triple(
635838a4d34SKelvin Li           llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};
6367e82379dSKelvin Li       // Only use __ppc_intrinsics module when targetting PowerPC arch
637a9e1d2e7SKelvin Li       if (context_.targetCharacteristics().isPPC()) {
6387e82379dSKelvin Li         context_.UsePPCBuiltinTypesModule();
6397e82379dSKelvin Li         context_.UsePPCBuiltinsModule();
640838a4d34SKelvin Li       }
64152711fb8Speter klausler     }
64252711fb8Speter klausler   }
64364ab3302SCarolineConcatto   return ValidateLabels(context_, program_) &&
64464ab3302SCarolineConcatto       parser::CanonicalizeDo(program_) && // force line break
6459aa3dca8SValentin Clement       CanonicalizeAcc(context_.messages(), program_) &&
64664ab3302SCarolineConcatto       CanonicalizeOmp(context_.messages(), program_) &&
647f674ddc1SPeter Klausler       CanonicalizeCUDA(program_) &&
64864ab3302SCarolineConcatto       PerformStatementSemantics(context_, program_) &&
649c734d77bSTom Eccles       CanonicalizeDirectives(context_.messages(), program_) &&
65065987954SPeter Klausler       ModFileWriter{context_}
65165987954SPeter Klausler           .set_hermeticModuleFileOutput(hermeticModuleFileOutput_)
65265987954SPeter Klausler           .WriteAll();
65364ab3302SCarolineConcatto }
65464ab3302SCarolineConcatto 
655f2e80893SPeter Klausler void Semantics::EmitMessages(llvm::raw_ostream &os) {
656f2e80893SPeter Klausler   // Resolve the CharBlock locations of the Messages to ProvenanceRanges
657f2e80893SPeter Klausler   // so messages from parsing and semantics are intermixed in source order.
658f2e80893SPeter Klausler   context_.messages().ResolveProvenances(context_.allCookedSources());
65992a54197Speter klausler   context_.messages().Emit(os, context_.allCookedSources());
66064ab3302SCarolineConcatto }
66164ab3302SCarolineConcatto 
662d1e4a2d3SPeter Klausler void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) {
663d1e4a2d3SPeter Klausler   DoDumpSymbols(os, globalScope());
66464ab3302SCarolineConcatto }
66564ab3302SCarolineConcatto 
666*4f2b65fbSPeter Klausler ProgramTree &SemanticsContext::SaveProgramTree(ProgramTree &&tree) {
667*4f2b65fbSPeter Klausler   return programTrees_.emplace_back(std::move(tree));
668*4f2b65fbSPeter Klausler }
669*4f2b65fbSPeter Klausler 
670d1e4a2d3SPeter Klausler void Semantics::DumpSymbols(llvm::raw_ostream &os) { context_.DumpSymbols(os); }
671d1e4a2d3SPeter Klausler 
6728670e499SCaroline Concatto void Semantics::DumpSymbolsSources(llvm::raw_ostream &os) const {
67364ab3302SCarolineConcatto   NameToSymbolMap symbols;
67464ab3302SCarolineConcatto   GetSymbolNames(context_.globalScope(), symbols);
67592a54197Speter klausler   const parser::AllCookedSources &allCooked{context_.allCookedSources()};
67664ab3302SCarolineConcatto   for (const auto &pair : symbols) {
67764ab3302SCarolineConcatto     const Symbol &symbol{pair.second};
67892a54197Speter klausler     if (auto sourceInfo{allCooked.GetSourcePositionRange(symbol.name())}) {
679e12ffe6aSPeter Klausler       os << symbol.name().ToString() << ": " << sourceInfo->first.path << ", "
680e12ffe6aSPeter Klausler          << sourceInfo->first.line << ", " << sourceInfo->first.column << "-"
681e12ffe6aSPeter Klausler          << sourceInfo->second.column << "\n";
68264ab3302SCarolineConcatto     } else if (symbol.has<semantics::UseDetails>()) {
68364ab3302SCarolineConcatto       os << symbol.name().ToString() << ": "
68464ab3302SCarolineConcatto          << symbol.GetUltimate().owner().symbol()->name().ToString() << "\n";
68564ab3302SCarolineConcatto     }
68664ab3302SCarolineConcatto   }
68764ab3302SCarolineConcatto }
68864ab3302SCarolineConcatto 
6898670e499SCaroline Concatto void DoDumpSymbols(llvm::raw_ostream &os, const Scope &scope, int indent) {
69064ab3302SCarolineConcatto   PutIndent(os, indent);
69164ab3302SCarolineConcatto   os << Scope::EnumToString(scope.kind()) << " scope:";
69264ab3302SCarolineConcatto   if (const auto *symbol{scope.symbol()}) {
69364ab3302SCarolineConcatto     os << ' ' << symbol->name();
69464ab3302SCarolineConcatto   }
6954fede8bcSpeter klausler   if (scope.alignment().has_value()) {
6964fede8bcSpeter klausler     os << " size=" << scope.size() << " alignment=" << *scope.alignment();
697c353ebbfSTim Keith   }
698c353ebbfSTim Keith   if (scope.derivedTypeSpec()) {
699c353ebbfSTim Keith     os << " instantiation of " << *scope.derivedTypeSpec();
700c353ebbfSTim Keith   }
701f674ddc1SPeter Klausler   os << " sourceRange=" << scope.sourceRange().size() << " bytes\n";
70264ab3302SCarolineConcatto   ++indent;
70364ab3302SCarolineConcatto   for (const auto &pair : scope) {
70464ab3302SCarolineConcatto     const auto &symbol{*pair.second};
70564ab3302SCarolineConcatto     PutIndent(os, indent);
70664ab3302SCarolineConcatto     os << symbol << '\n';
70764ab3302SCarolineConcatto     if (const auto *details{symbol.detailsIf<GenericDetails>()}) {
70864ab3302SCarolineConcatto       if (const auto &type{details->derivedType()}) {
70964ab3302SCarolineConcatto         PutIndent(os, indent);
71064ab3302SCarolineConcatto         os << *type << '\n';
71164ab3302SCarolineConcatto       }
71264ab3302SCarolineConcatto     }
71364ab3302SCarolineConcatto   }
71464ab3302SCarolineConcatto   if (!scope.equivalenceSets().empty()) {
71564ab3302SCarolineConcatto     PutIndent(os, indent);
71664ab3302SCarolineConcatto     os << "Equivalence Sets:";
71764ab3302SCarolineConcatto     for (const auto &set : scope.equivalenceSets()) {
71864ab3302SCarolineConcatto       os << ' ';
71964ab3302SCarolineConcatto       char sep = '(';
72064ab3302SCarolineConcatto       for (const auto &object : set) {
72164ab3302SCarolineConcatto         os << sep << object.AsFortran();
72264ab3302SCarolineConcatto         sep = ',';
72364ab3302SCarolineConcatto       }
72464ab3302SCarolineConcatto       os << ')';
72564ab3302SCarolineConcatto     }
72664ab3302SCarolineConcatto     os << '\n';
72764ab3302SCarolineConcatto   }
72864ab3302SCarolineConcatto   if (!scope.crayPointers().empty()) {
72964ab3302SCarolineConcatto     PutIndent(os, indent);
73064ab3302SCarolineConcatto     os << "Cray Pointers:";
73164ab3302SCarolineConcatto     for (const auto &[pointee, pointer] : scope.crayPointers()) {
73264ab3302SCarolineConcatto       os << " (" << pointer->name() << ',' << pointee << ')';
73364ab3302SCarolineConcatto     }
73464ab3302SCarolineConcatto   }
73564ab3302SCarolineConcatto   for (const auto &pair : scope.commonBlocks()) {
73664ab3302SCarolineConcatto     const auto &symbol{*pair.second};
73764ab3302SCarolineConcatto     PutIndent(os, indent);
73864ab3302SCarolineConcatto     os << symbol << '\n';
73964ab3302SCarolineConcatto   }
74064ab3302SCarolineConcatto   for (const auto &child : scope.children()) {
74164ab3302SCarolineConcatto     DoDumpSymbols(os, child, indent);
74264ab3302SCarolineConcatto   }
74364ab3302SCarolineConcatto   --indent;
74464ab3302SCarolineConcatto }
74564ab3302SCarolineConcatto 
7468670e499SCaroline Concatto static void PutIndent(llvm::raw_ostream &os, int indent) {
74764ab3302SCarolineConcatto   for (int i = 0; i < indent; ++i) {
74864ab3302SCarolineConcatto     os << "  ";
74964ab3302SCarolineConcatto   }
75064ab3302SCarolineConcatto }
7512c8cb9acSJean Perier 
7522c8cb9acSJean Perier void SemanticsContext::MapCommonBlockAndCheckConflicts(const Symbol &common) {
7532c8cb9acSJean Perier   if (!commonBlockMap_) {
7542c8cb9acSJean Perier     commonBlockMap_ = std::make_unique<CommonBlockMap>();
7552c8cb9acSJean Perier   }
7562c8cb9acSJean Perier   commonBlockMap_->MapCommonBlockAndCheckConflicts(*this, common);
7572c8cb9acSJean Perier }
7582c8cb9acSJean Perier 
7592c8cb9acSJean Perier CommonBlockList SemanticsContext::GetCommonBlocks() const {
7602c8cb9acSJean Perier   if (commonBlockMap_) {
7612c8cb9acSJean Perier     return commonBlockMap_->GetCommonBlocks();
7622c8cb9acSJean Perier   }
7632c8cb9acSJean Perier   return {};
7642c8cb9acSJean Perier }
7652c8cb9acSJean Perier 
76633c27f28SPeter Klausler void SemanticsContext::NoteDefinedSymbol(const Symbol &symbol) {
76733c27f28SPeter Klausler   isDefined_.insert(symbol);
76833c27f28SPeter Klausler }
76933c27f28SPeter Klausler 
77033c27f28SPeter Klausler bool SemanticsContext::IsSymbolDefined(const Symbol &symbol) const {
77133c27f28SPeter Klausler   return isDefined_.find(symbol) != isDefined_.end();
77233c27f28SPeter Klausler }
77333c27f28SPeter Klausler 
7747a77c20dSpeter klausler } // namespace Fortran::semantics
775