164ab3302SCarolineConcatto //===-- lib/Semantics/mod-file.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 "mod-file.h" 1064ab3302SCarolineConcatto #include "resolve-names.h" 113780d3ebSTim Keith #include "flang/Common/restorer.h" 1264ab3302SCarolineConcatto #include "flang/Evaluate/tools.h" 1364ab3302SCarolineConcatto #include "flang/Parser/message.h" 1464ab3302SCarolineConcatto #include "flang/Parser/parsing.h" 159e7eef99SPeter Klausler #include "flang/Parser/unparse.h" 1664ab3302SCarolineConcatto #include "flang/Semantics/scope.h" 1764ab3302SCarolineConcatto #include "flang/Semantics/semantics.h" 1864ab3302SCarolineConcatto #include "flang/Semantics/symbol.h" 1964ab3302SCarolineConcatto #include "flang/Semantics/tools.h" 200855c454SDavid Truby #include "llvm/Support/FileSystem.h" 210855c454SDavid Truby #include "llvm/Support/MemoryBuffer.h" 220855c454SDavid Truby #include "llvm/Support/raw_ostream.h" 2364ab3302SCarolineConcatto #include <algorithm> 2464ab3302SCarolineConcatto #include <fstream> 2564ab3302SCarolineConcatto #include <set> 2664ab3302SCarolineConcatto #include <string_view> 2764ab3302SCarolineConcatto #include <vector> 2864ab3302SCarolineConcatto 2964ab3302SCarolineConcatto namespace Fortran::semantics { 3064ab3302SCarolineConcatto 3164ab3302SCarolineConcatto using namespace parser::literals; 3264ab3302SCarolineConcatto 3364ab3302SCarolineConcatto // The first line of a file that identifies it as a .mod file. 3464ab3302SCarolineConcatto // The first three bytes are a Unicode byte order mark that ensures 3564ab3302SCarolineConcatto // that the module file is decoded as UTF-8 even if source files 3664ab3302SCarolineConcatto // are using another encoding. 3764ab3302SCarolineConcatto struct ModHeader { 3864ab3302SCarolineConcatto static constexpr const char bom[3 + 1]{"\xef\xbb\xbf"}; 3964ab3302SCarolineConcatto static constexpr int magicLen{13}; 4064ab3302SCarolineConcatto static constexpr int sumLen{16}; 4164ab3302SCarolineConcatto static constexpr const char magic[magicLen + 1]{"!mod$ v1 sum:"}; 4264ab3302SCarolineConcatto static constexpr char terminator{'\n'}; 4364ab3302SCarolineConcatto static constexpr int len{magicLen + 1 + sumLen}; 44f7a15e00SPeter Klausler static constexpr int needLen{7}; 45f7a15e00SPeter Klausler static constexpr const char need[needLen + 1]{"!need$ "}; 4664ab3302SCarolineConcatto }; 4764ab3302SCarolineConcatto 4864ab3302SCarolineConcatto static std::optional<SourceName> GetSubmoduleParent(const parser::Program &); 499ce8e63cSPeter Klausler static void CollectSymbols( 509ce8e63cSPeter Klausler const Scope &, SymbolVector &, SymbolVector &, UnorderedSymbolSet &); 518670e499SCaroline Concatto static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &); 529e7eef99SPeter Klausler static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &, 539ce8e63cSPeter Klausler const parser::Expr *); 548670e499SCaroline Concatto static void PutInit(llvm::raw_ostream &, const MaybeIntExpr &); 558670e499SCaroline Concatto static void PutBound(llvm::raw_ostream &, const Bound &); 56c14cf92bSPeter Klausler static void PutShapeSpec(llvm::raw_ostream &, const ShapeSpec &); 57c14cf92bSPeter Klausler static void PutShape( 58c14cf92bSPeter Klausler llvm::raw_ostream &, const ArraySpec &, char open, char close); 598670e499SCaroline Concatto 608670e499SCaroline Concatto static llvm::raw_ostream &PutAttr(llvm::raw_ostream &, Attr); 618670e499SCaroline Concatto static llvm::raw_ostream &PutType(llvm::raw_ostream &, const DeclTypeSpec &); 62bcba39a5SPeter Klausler static llvm::raw_ostream &PutLower(llvm::raw_ostream &, std::string_view); 63f7a15e00SPeter Klausler static std::error_code WriteFile(const std::string &, const std::string &, 64f7a15e00SPeter Klausler ModuleCheckSumType &, bool debug = true); 6564ab3302SCarolineConcatto static bool FileContentsMatch( 6664ab3302SCarolineConcatto const std::string &, const std::string &, const std::string &); 67f7a15e00SPeter Klausler static ModuleCheckSumType ComputeCheckSum(const std::string_view &); 68f7a15e00SPeter Klausler static std::string CheckSumString(ModuleCheckSumType); 6964ab3302SCarolineConcatto 7064ab3302SCarolineConcatto // Collect symbols needed for a subprogram interface 7164ab3302SCarolineConcatto class SubprogramSymbolCollector { 7264ab3302SCarolineConcatto public: 73c42f6314Speter klausler SubprogramSymbolCollector(const Symbol &symbol, const Scope &scope) 74c42f6314Speter klausler : symbol_{symbol}, scope_{scope} {} 7564ab3302SCarolineConcatto const SymbolVector &symbols() const { return need_; } 7664ab3302SCarolineConcatto const std::set<SourceName> &imports() const { return imports_; } 7764ab3302SCarolineConcatto void Collect(); 7864ab3302SCarolineConcatto 7964ab3302SCarolineConcatto private: 8064ab3302SCarolineConcatto const Symbol &symbol_; 8164ab3302SCarolineConcatto const Scope &scope_; 8264ab3302SCarolineConcatto bool isInterface_{false}; 8364ab3302SCarolineConcatto SymbolVector need_; // symbols that are needed 840d8331c0Speter klausler UnorderedSymbolSet needSet_; // symbols already in need_ 850d8331c0Speter klausler UnorderedSymbolSet useSet_; // use-associations that might be needed 8664ab3302SCarolineConcatto std::set<SourceName> imports_; // imports from host that are needed 8764ab3302SCarolineConcatto 8864ab3302SCarolineConcatto void DoSymbol(const Symbol &); 8964ab3302SCarolineConcatto void DoSymbol(const SourceName &, const Symbol &); 9064ab3302SCarolineConcatto void DoType(const DeclTypeSpec *); 9164ab3302SCarolineConcatto void DoBound(const Bound &); 9264ab3302SCarolineConcatto void DoParamValue(const ParamValue &); 9364ab3302SCarolineConcatto bool NeedImport(const SourceName &, const Symbol &); 9464ab3302SCarolineConcatto 9564ab3302SCarolineConcatto template <typename T> void DoExpr(evaluate::Expr<T> expr) { 9664ab3302SCarolineConcatto for (const Symbol &symbol : evaluate::CollectSymbols(expr)) { 9764ab3302SCarolineConcatto DoSymbol(symbol); 9864ab3302SCarolineConcatto } 9964ab3302SCarolineConcatto } 10064ab3302SCarolineConcatto }; 10164ab3302SCarolineConcatto 10264ab3302SCarolineConcatto bool ModFileWriter::WriteAll() { 1033780d3ebSTim Keith // this flag affects character literals: force it to be consistent 1043780d3ebSTim Keith auto restorer{ 1053780d3ebSTim Keith common::ScopedSet(parser::useHexadecimalEscapeSequences, false)}; 10664ab3302SCarolineConcatto WriteAll(context_.globalScope()); 10764ab3302SCarolineConcatto return !context_.AnyFatalError(); 10864ab3302SCarolineConcatto } 10964ab3302SCarolineConcatto 11064ab3302SCarolineConcatto void ModFileWriter::WriteAll(const Scope &scope) { 11164ab3302SCarolineConcatto for (const auto &child : scope.children()) { 11264ab3302SCarolineConcatto WriteOne(child); 11364ab3302SCarolineConcatto } 11464ab3302SCarolineConcatto } 11564ab3302SCarolineConcatto 11664ab3302SCarolineConcatto void ModFileWriter::WriteOne(const Scope &scope) { 11764ab3302SCarolineConcatto if (scope.kind() == Scope::Kind::Module) { 11864ab3302SCarolineConcatto auto *symbol{scope.symbol()}; 11964ab3302SCarolineConcatto if (!symbol->test(Symbol::Flag::ModFile)) { 12064ab3302SCarolineConcatto Write(*symbol); 12164ab3302SCarolineConcatto } 12264ab3302SCarolineConcatto WriteAll(scope); // write out submodules 12364ab3302SCarolineConcatto } 12464ab3302SCarolineConcatto } 12564ab3302SCarolineConcatto 12664ab3302SCarolineConcatto // Construct the name of a module file. Non-empty ancestorName means submodule. 12764ab3302SCarolineConcatto static std::string ModFileName(const SourceName &name, 12864ab3302SCarolineConcatto const std::string &ancestorName, const std::string &suffix) { 12964ab3302SCarolineConcatto std::string result{name.ToString() + suffix}; 13064ab3302SCarolineConcatto return ancestorName.empty() ? result : ancestorName + '-' + result; 13164ab3302SCarolineConcatto } 13264ab3302SCarolineConcatto 13364ab3302SCarolineConcatto // Write the module file for symbol, which must be a module or submodule. 13464ab3302SCarolineConcatto void ModFileWriter::Write(const Symbol &symbol) { 135e00a3ccfSPeter Klausler const auto &module{symbol.get<ModuleDetails>()}; 136f7a15e00SPeter Klausler if (module.moduleFileHash()) { 137f7a15e00SPeter Klausler return; // already written 138f7a15e00SPeter Klausler } 139e00a3ccfSPeter Klausler const auto *ancestor{module.ancestor()}; 1404b7428e1SPeter Klausler isSubmodule_ = ancestor != nullptr; 14164ab3302SCarolineConcatto auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s}; 1429629f2c4SPeter Klausler std::string path{context_.moduleDirectory() + '/' + 14364ab3302SCarolineConcatto ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())}; 14465987954SPeter Klausler 14565987954SPeter Klausler UnorderedSymbolSet hermeticModules; 14665987954SPeter Klausler hermeticModules.insert(symbol); 14765987954SPeter Klausler UnorderedSymbolSet additionalModules; 14865987954SPeter Klausler PutSymbols(DEREF(symbol.scope()), 14965987954SPeter Klausler hermeticModuleFileOutput_ ? &additionalModules : nullptr); 15065987954SPeter Klausler auto asStr{GetAsString(symbol)}; 15165987954SPeter Klausler while (!additionalModules.empty()) { 15265987954SPeter Klausler for (auto ref : UnorderedSymbolSet{std::move(additionalModules)}) { 15365987954SPeter Klausler if (hermeticModules.insert(*ref).second && 15465987954SPeter Klausler !ref->owner().IsIntrinsicModules()) { 15565987954SPeter Klausler PutSymbols(DEREF(ref->scope()), &additionalModules); 15665987954SPeter Klausler asStr += GetAsString(*ref); 15765987954SPeter Klausler } 15865987954SPeter Klausler } 15965987954SPeter Klausler } 16065987954SPeter Klausler 161f7a15e00SPeter Klausler ModuleCheckSumType checkSum; 16265987954SPeter Klausler if (std::error_code error{ 16365987954SPeter Klausler WriteFile(path, asStr, checkSum, context_.debugModuleWriter())}) { 1640855c454SDavid Truby context_.Say( 1650855c454SDavid Truby symbol.name(), "Error writing %s: %s"_err_en_US, path, error.message()); 16664ab3302SCarolineConcatto } 167f7a15e00SPeter Klausler const_cast<ModuleDetails &>(module).set_moduleFileHash(checkSum); 16864ab3302SCarolineConcatto } 16964ab3302SCarolineConcatto 170e00a3ccfSPeter Klausler void ModFileWriter::WriteClosure(llvm::raw_ostream &out, const Symbol &symbol, 171e00a3ccfSPeter Klausler UnorderedSymbolSet &nonIntrinsicModulesWritten) { 172e00a3ccfSPeter Klausler if (!symbol.has<ModuleDetails>() || symbol.owner().IsIntrinsicModules() || 173e00a3ccfSPeter Klausler !nonIntrinsicModulesWritten.insert(symbol).second) { 174e00a3ccfSPeter Klausler return; 175e00a3ccfSPeter Klausler } 17665987954SPeter Klausler PutSymbols(DEREF(symbol.scope()), /*hermeticModules=*/nullptr); 177e00a3ccfSPeter Klausler needsBuf_.clear(); // omit module checksums 178e00a3ccfSPeter Klausler auto str{GetAsString(symbol)}; 179e00a3ccfSPeter Klausler for (auto depRef : std::move(usedNonIntrinsicModules_)) { 180e00a3ccfSPeter Klausler WriteClosure(out, *depRef, nonIntrinsicModulesWritten); 181e00a3ccfSPeter Klausler } 182e00a3ccfSPeter Klausler out << std::move(str); 183e00a3ccfSPeter Klausler } 184e00a3ccfSPeter Klausler 18564ab3302SCarolineConcatto // Return the entire body of the module file 18664ab3302SCarolineConcatto // and clear saved uses, decls, and contains. 18764ab3302SCarolineConcatto std::string ModFileWriter::GetAsString(const Symbol &symbol) { 1888670e499SCaroline Concatto std::string buf; 1898670e499SCaroline Concatto llvm::raw_string_ostream all{buf}; 190f7a15e00SPeter Klausler all << needs_.str(); 191f7a15e00SPeter Klausler needs_.str().clear(); 19264ab3302SCarolineConcatto auto &details{symbol.get<ModuleDetails>()}; 19364ab3302SCarolineConcatto if (!details.isSubmodule()) { 19464ab3302SCarolineConcatto all << "module " << symbol.name(); 19564ab3302SCarolineConcatto } else { 19664ab3302SCarolineConcatto auto *parent{details.parent()->symbol()}; 19764ab3302SCarolineConcatto auto *ancestor{details.ancestor()->symbol()}; 19864ab3302SCarolineConcatto all << "submodule(" << ancestor->name(); 19964ab3302SCarolineConcatto if (parent != ancestor) { 20064ab3302SCarolineConcatto all << ':' << parent->name(); 20164ab3302SCarolineConcatto } 20264ab3302SCarolineConcatto all << ") " << symbol.name(); 20364ab3302SCarolineConcatto } 20464ab3302SCarolineConcatto all << '\n' << uses_.str(); 2058670e499SCaroline Concatto uses_.str().clear(); 20664ab3302SCarolineConcatto all << useExtraAttrs_.str(); 2078670e499SCaroline Concatto useExtraAttrs_.str().clear(); 20864ab3302SCarolineConcatto all << decls_.str(); 2098670e499SCaroline Concatto decls_.str().clear(); 21064ab3302SCarolineConcatto auto str{contains_.str()}; 2118670e499SCaroline Concatto contains_.str().clear(); 21264ab3302SCarolineConcatto if (!str.empty()) { 21364ab3302SCarolineConcatto all << "contains\n" << str; 21464ab3302SCarolineConcatto } 21564ab3302SCarolineConcatto all << "end\n"; 21664ab3302SCarolineConcatto return all.str(); 21764ab3302SCarolineConcatto } 21864ab3302SCarolineConcatto 2199ce8e63cSPeter Klausler // Collect symbols from constant and specification expressions that are being 2209ce8e63cSPeter Klausler // referenced directly from other modules; they may require new USE 2219ce8e63cSPeter Klausler // associations. 2229ce8e63cSPeter Klausler static void HarvestSymbolsNeededFromOtherModules( 2239ce8e63cSPeter Klausler SourceOrderedSymbolSet &, const Scope &); 2249ce8e63cSPeter Klausler static void HarvestSymbolsNeededFromOtherModules( 2259ce8e63cSPeter Klausler SourceOrderedSymbolSet &set, const Symbol &symbol, const Scope &scope) { 2269ce8e63cSPeter Klausler auto HarvestBound{[&](const Bound &bound) { 2279ce8e63cSPeter Klausler if (const auto &expr{bound.GetExplicit()}) { 2289ce8e63cSPeter Klausler for (SymbolRef ref : evaluate::CollectSymbols(*expr)) { 2299ce8e63cSPeter Klausler set.emplace(*ref); 2301bea0347SPeter Klausler } 2319ce8e63cSPeter Klausler } 2329ce8e63cSPeter Klausler }}; 2339ce8e63cSPeter Klausler auto HarvestShapeSpec{[&](const ShapeSpec &shapeSpec) { 2349ce8e63cSPeter Klausler HarvestBound(shapeSpec.lbound()); 2359ce8e63cSPeter Klausler HarvestBound(shapeSpec.ubound()); 2369ce8e63cSPeter Klausler }}; 2379ce8e63cSPeter Klausler auto HarvestArraySpec{[&](const ArraySpec &arraySpec) { 2389ce8e63cSPeter Klausler for (const auto &shapeSpec : arraySpec) { 2399ce8e63cSPeter Klausler HarvestShapeSpec(shapeSpec); 2409ce8e63cSPeter Klausler } 2419ce8e63cSPeter Klausler }}; 2429ce8e63cSPeter Klausler 2439ce8e63cSPeter Klausler if (symbol.has<DerivedTypeDetails>()) { 2449ce8e63cSPeter Klausler if (symbol.scope()) { 2459ce8e63cSPeter Klausler HarvestSymbolsNeededFromOtherModules(set, *symbol.scope()); 2469ce8e63cSPeter Klausler } 2479ce8e63cSPeter Klausler } else if (const auto &generic{symbol.detailsIf<GenericDetails>()}; 2487f542662SPeter Klausler generic && generic->derivedType()) { 2497f542662SPeter Klausler const Symbol &dtSym{*generic->derivedType()}; 25037180ed7SPeter Klausler if (dtSym.has<DerivedTypeDetails>()) { 2517f542662SPeter Klausler if (dtSym.scope()) { 2529ce8e63cSPeter Klausler HarvestSymbolsNeededFromOtherModules(set, *dtSym.scope()); 2537f542662SPeter Klausler } 25437180ed7SPeter Klausler } else { 25571113047SPeter Klausler CHECK(dtSym.has<UseDetails>() || dtSym.has<UseErrorDetails>()); 25637180ed7SPeter Klausler } 2579ce8e63cSPeter Klausler } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 2589ce8e63cSPeter Klausler HarvestArraySpec(object->shape()); 2599ce8e63cSPeter Klausler HarvestArraySpec(object->coshape()); 2609ce8e63cSPeter Klausler if (IsNamedConstant(symbol) || scope.IsDerivedType()) { 2611bea0347SPeter Klausler if (object->init()) { 2621bea0347SPeter Klausler for (SymbolRef ref : evaluate::CollectSymbols(*object->init())) { 2631bea0347SPeter Klausler set.emplace(*ref); 2641bea0347SPeter Klausler } 2651bea0347SPeter Klausler } 2669ce8e63cSPeter Klausler } 2679ce8e63cSPeter Klausler } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 2689ce8e63cSPeter Klausler if (proc->init() && *proc->init() && scope.IsDerivedType()) { 2691bea0347SPeter Klausler set.emplace(**proc->init()); 2701bea0347SPeter Klausler } 2719ce8e63cSPeter Klausler } else if (const auto *subp{symbol.detailsIf<SubprogramDetails>()}) { 2729ce8e63cSPeter Klausler for (const Symbol *dummy : subp->dummyArgs()) { 2739ce8e63cSPeter Klausler if (dummy) { 2749ce8e63cSPeter Klausler HarvestSymbolsNeededFromOtherModules(set, *dummy, scope); 2751bea0347SPeter Klausler } 2761bea0347SPeter Klausler } 2779ce8e63cSPeter Klausler if (subp->isFunction()) { 2789ce8e63cSPeter Klausler HarvestSymbolsNeededFromOtherModules(set, subp->result(), scope); 2799ce8e63cSPeter Klausler } 2801bea0347SPeter Klausler } 2811bea0347SPeter Klausler } 2821bea0347SPeter Klausler 2839ce8e63cSPeter Klausler static void HarvestSymbolsNeededFromOtherModules( 2849ce8e63cSPeter Klausler SourceOrderedSymbolSet &set, const Scope &scope) { 2859ce8e63cSPeter Klausler for (const auto &[_, symbol] : scope) { 2869ce8e63cSPeter Klausler HarvestSymbolsNeededFromOtherModules(set, *symbol, scope); 2879ce8e63cSPeter Klausler } 2889ce8e63cSPeter Klausler } 2899ce8e63cSPeter Klausler 2901bea0347SPeter Klausler void ModFileWriter::PrepareRenamings(const Scope &scope) { 2919ce8e63cSPeter Klausler // Identify use-associated symbols already in scope under some name 2929ce8e63cSPeter Klausler std::map<const Symbol *, const Symbol *> useMap; 2939ce8e63cSPeter Klausler for (const auto &[name, symbolRef] : scope) { 2949ce8e63cSPeter Klausler const Symbol *symbol{&*symbolRef}; 2959ce8e63cSPeter Klausler while (const auto *hostAssoc{symbol->detailsIf<HostAssocDetails>()}) { 2969ce8e63cSPeter Klausler symbol = &hostAssoc->symbol(); 2979ce8e63cSPeter Klausler } 2989ce8e63cSPeter Klausler if (const auto *use{symbol->detailsIf<UseDetails>()}) { 2999ce8e63cSPeter Klausler useMap.emplace(&use->symbol(), symbol); 3009ce8e63cSPeter Klausler } 3019ce8e63cSPeter Klausler } 3029ce8e63cSPeter Klausler // Collect symbols needed from other modules 3039ce8e63cSPeter Klausler SourceOrderedSymbolSet symbolsNeeded; 3049ce8e63cSPeter Klausler HarvestSymbolsNeededFromOtherModules(symbolsNeeded, scope); 3059ce8e63cSPeter Klausler // Establish any necessary renamings of symbols in other modules 3069ce8e63cSPeter Klausler // to their names in this scope, creating those new names when needed. 3079ce8e63cSPeter Klausler auto &renamings{context_.moduleFileOutputRenamings()}; 3089ce8e63cSPeter Klausler for (SymbolRef s : symbolsNeeded) { 30982bd7adbSPeter Klausler if (s->owner().kind() == Scope::Kind::DerivedType) { 31082bd7adbSPeter Klausler continue; // component or binding: ok 31182bd7adbSPeter Klausler } 3121bea0347SPeter Klausler const Scope *sMod{FindModuleContaining(s->owner())}; 3139ce8e63cSPeter Klausler if (!sMod || sMod == &scope) { 3149ce8e63cSPeter Klausler continue; 3159ce8e63cSPeter Klausler } 3169ce8e63cSPeter Klausler if (auto iter{useMap.find(&*s)}; iter != useMap.end()) { 3179ce8e63cSPeter Klausler renamings.emplace(&*s, iter->second->name()); 3181bea0347SPeter Klausler continue; 3191bea0347SPeter Klausler } 3201bea0347SPeter Klausler SourceName rename{s->name()}; 3211bea0347SPeter Klausler if (const Symbol * found{scope.FindSymbol(s->name())}) { 3221bea0347SPeter Klausler if (found == &*s) { 3231bea0347SPeter Klausler continue; // available in scope 3241bea0347SPeter Klausler } 3251bea0347SPeter Klausler if (const auto *generic{found->detailsIf<GenericDetails>()}) { 3261bea0347SPeter Klausler if (generic->derivedType() == &*s || generic->specific() == &*s) { 3271bea0347SPeter Klausler continue; 3281bea0347SPeter Klausler } 3291bea0347SPeter Klausler } else if (found->has<UseDetails>()) { 3301bea0347SPeter Klausler if (&found->GetUltimate() == &*s) { 3311bea0347SPeter Klausler continue; // already use-associated with same name 3321bea0347SPeter Klausler } 3331bea0347SPeter Klausler } 3341bea0347SPeter Klausler if (&s->owner() != &found->owner()) { // Symbol needs renaming 3351bea0347SPeter Klausler rename = scope.context().SaveTempName( 3361bea0347SPeter Klausler DEREF(sMod->symbol()).name().ToString() + "$" + 3371bea0347SPeter Klausler s->name().ToString()); 3381bea0347SPeter Klausler } 3391bea0347SPeter Klausler } 3401bea0347SPeter Klausler // Symbol is used in this scope but not visible under its name 3411bea0347SPeter Klausler if (sMod->parent().IsIntrinsicModules()) { 3421bea0347SPeter Klausler uses_ << "use,intrinsic::"; 3431bea0347SPeter Klausler } else { 3441bea0347SPeter Klausler uses_ << "use "; 3451bea0347SPeter Klausler } 3461bea0347SPeter Klausler uses_ << DEREF(sMod->symbol()).name() << ",only:"; 3471bea0347SPeter Klausler if (rename != s->name()) { 3481bea0347SPeter Klausler uses_ << rename << "=>"; 3499ce8e63cSPeter Klausler renamings.emplace(&*s, rename); 3501bea0347SPeter Klausler } 3511bea0347SPeter Klausler uses_ << s->name() << '\n'; 3521bea0347SPeter Klausler useExtraAttrs_ << "private::" << rename << '\n'; 3531bea0347SPeter Klausler } 3541bea0347SPeter Klausler } 3551bea0347SPeter Klausler 35664ab3302SCarolineConcatto // Put out the visible symbols from scope. 35765987954SPeter Klausler void ModFileWriter::PutSymbols( 35865987954SPeter Klausler const Scope &scope, UnorderedSymbolSet *hermeticModules) { 35986f59de1STim Keith SymbolVector sorted; 36086f59de1STim Keith SymbolVector uses; 3619ce8e63cSPeter Klausler auto &renamings{context_.moduleFileOutputRenamings()}; 3629ce8e63cSPeter Klausler auto previousRenamings{std::move(renamings)}; 3631bea0347SPeter Klausler PrepareRenamings(scope); 364f7a15e00SPeter Klausler UnorderedSymbolSet modules; 3659ce8e63cSPeter Klausler CollectSymbols(scope, sorted, uses, modules); 366f7a15e00SPeter Klausler // Write module files for dependencies first so that their 367f7a15e00SPeter Klausler // hashes are known. 368f7a15e00SPeter Klausler for (auto ref : modules) { 36965987954SPeter Klausler if (hermeticModules) { 37065987954SPeter Klausler hermeticModules->insert(*ref); 37165987954SPeter Klausler } else { 372f7a15e00SPeter Klausler Write(*ref); 373f7a15e00SPeter Klausler needs_ << ModHeader::need 37465987954SPeter Klausler << CheckSumString( 37565987954SPeter Klausler ref->get<ModuleDetails>().moduleFileHash().value()) 376f7a15e00SPeter Klausler << (ref->owner().IsIntrinsicModules() ? " i " : " n ") 377f7a15e00SPeter Klausler << ref->name().ToString() << '\n'; 378f7a15e00SPeter Klausler } 37965987954SPeter Klausler } 38086f59de1STim Keith std::string buf; // stuff after CONTAINS in derived type 38186f59de1STim Keith llvm::raw_string_ostream typeBindings{buf}; 38286f59de1STim Keith for (const Symbol &symbol : sorted) { 383d60a0220Speter klausler if (!symbol.test(Symbol::Flag::CompilerCreated)) { 38464ab3302SCarolineConcatto PutSymbol(typeBindings, symbol); 38564ab3302SCarolineConcatto } 386d60a0220Speter klausler } 38786f59de1STim Keith for (const Symbol &symbol : uses) { 38886f59de1STim Keith PutUse(symbol); 38986f59de1STim Keith } 390d60a0220Speter klausler for (const auto &set : scope.equivalenceSets()) { 391d60a0220Speter klausler if (!set.empty() && 392d60a0220Speter klausler !set.front().symbol.test(Symbol::Flag::CompilerCreated)) { 393d60a0220Speter klausler char punctuation{'('}; 394d60a0220Speter klausler decls_ << "equivalence"; 395d60a0220Speter klausler for (const auto &object : set) { 396d60a0220Speter klausler decls_ << punctuation << object.AsFortran(); 397d60a0220Speter klausler punctuation = ','; 398d60a0220Speter klausler } 399d60a0220Speter klausler decls_ << ")\n"; 400d60a0220Speter klausler } 401d60a0220Speter klausler } 402c14cf92bSPeter Klausler CHECK(typeBindings.str().empty()); 4039ce8e63cSPeter Klausler renamings = std::move(previousRenamings); 404c14cf92bSPeter Klausler } 405c14cf92bSPeter Klausler 406c14cf92bSPeter Klausler // Emit components in order 407c14cf92bSPeter Klausler bool ModFileWriter::PutComponents(const Symbol &typeSymbol) { 408c14cf92bSPeter Klausler const auto &scope{DEREF(typeSymbol.scope())}; 409c14cf92bSPeter Klausler std::string buf; // stuff after CONTAINS in derived type 410c14cf92bSPeter Klausler llvm::raw_string_ostream typeBindings{buf}; 411c14cf92bSPeter Klausler UnorderedSymbolSet emitted; 412c14cf92bSPeter Klausler SymbolVector symbols{scope.GetSymbols()}; 413539a6b50SPeter Klausler // Emit type parameter declarations first, in order 414539a6b50SPeter Klausler const auto &details{typeSymbol.get<DerivedTypeDetails>()}; 415539a6b50SPeter Klausler for (const Symbol &symbol : details.paramDeclOrder()) { 416539a6b50SPeter Klausler CHECK(symbol.has<TypeParamDetails>()); 417c14cf92bSPeter Klausler PutSymbol(typeBindings, symbol); 418c14cf92bSPeter Klausler emitted.emplace(symbol); 419c14cf92bSPeter Klausler } 420539a6b50SPeter Klausler // Emit actual components in component order. 421c14cf92bSPeter Klausler for (SourceName name : details.componentNames()) { 422c14cf92bSPeter Klausler auto iter{scope.find(name)}; 423c14cf92bSPeter Klausler if (iter != scope.end()) { 424c14cf92bSPeter Klausler const Symbol &component{*iter->second}; 425c14cf92bSPeter Klausler if (!component.test(Symbol::Flag::ParentComp)) { 426c14cf92bSPeter Klausler PutSymbol(typeBindings, component); 427c14cf92bSPeter Klausler } 428c14cf92bSPeter Klausler emitted.emplace(component); 429c14cf92bSPeter Klausler } 430c14cf92bSPeter Klausler } 431c14cf92bSPeter Klausler // Emit remaining symbols from the type's scope 432c14cf92bSPeter Klausler for (const Symbol &symbol : symbols) { 433c14cf92bSPeter Klausler if (emitted.find(symbol) == emitted.end()) { 434c14cf92bSPeter Klausler PutSymbol(typeBindings, symbol); 435c14cf92bSPeter Klausler } 436c14cf92bSPeter Klausler } 43764ab3302SCarolineConcatto if (auto str{typeBindings.str()}; !str.empty()) { 43864ab3302SCarolineConcatto CHECK(scope.IsDerivedType()); 43964ab3302SCarolineConcatto decls_ << "contains\n" << str; 44037b2e2b0Speter klausler return true; 44137b2e2b0Speter klausler } else { 44237b2e2b0Speter klausler return false; 44364ab3302SCarolineConcatto } 44464ab3302SCarolineConcatto } 44564ab3302SCarolineConcatto 4461db42fa6SSlava Zakharin // Return the symbol's attributes that should be written 4471db42fa6SSlava Zakharin // into the mod file. 4481db42fa6SSlava Zakharin static Attrs getSymbolAttrsToWrite(const Symbol &symbol) { 4491db42fa6SSlava Zakharin // Is SAVE attribute is implicit, it should be omitted 4501db42fa6SSlava Zakharin // to not violate F202x C862 for a common block member. 4511db42fa6SSlava Zakharin return symbol.attrs() & ~(symbol.implicitAttrs() & Attrs{Attr::SAVE}); 4521db42fa6SSlava Zakharin } 4531db42fa6SSlava Zakharin 4544864d9f7Speter klausler static llvm::raw_ostream &PutGenericName( 4554864d9f7Speter klausler llvm::raw_ostream &os, const Symbol &symbol) { 4564864d9f7Speter klausler if (IsGenericDefinedOp(symbol)) { 4574864d9f7Speter klausler return os << "operator(" << symbol.name() << ')'; 4584864d9f7Speter klausler } else { 4594864d9f7Speter klausler return os << symbol.name(); 4604864d9f7Speter klausler } 4614864d9f7Speter klausler } 4624864d9f7Speter klausler 46364ab3302SCarolineConcatto // Emit a symbol to decls_, except for bindings in a derived type (type-bound 46464ab3302SCarolineConcatto // procedures, type-bound generics, final procedures) which go to typeBindings. 46564ab3302SCarolineConcatto void ModFileWriter::PutSymbol( 4668670e499SCaroline Concatto llvm::raw_ostream &typeBindings, const Symbol &symbol) { 467cd03e96fSPeter Klausler common::visit( 468cd03e96fSPeter Klausler common::visitors{ 46964ab3302SCarolineConcatto [&](const ModuleDetails &) { /* should be current module */ }, 47064ab3302SCarolineConcatto [&](const DerivedTypeDetails &) { PutDerivedType(symbol); }, 47164ab3302SCarolineConcatto [&](const SubprogramDetails &) { PutSubprogram(symbol); }, 47264ab3302SCarolineConcatto [&](const GenericDetails &x) { 47364ab3302SCarolineConcatto if (symbol.owner().IsDerivedType()) { 47464ab3302SCarolineConcatto // generic binding 47564ab3302SCarolineConcatto for (const Symbol &proc : x.specificProcs()) { 4764864d9f7Speter klausler PutGenericName(typeBindings << "generic::", symbol) 4774864d9f7Speter klausler << "=>" << proc.name() << '\n'; 47864ab3302SCarolineConcatto } 47964ab3302SCarolineConcatto } else { 48064ab3302SCarolineConcatto PutGeneric(symbol); 48164ab3302SCarolineConcatto } 48264ab3302SCarolineConcatto }, 48364ab3302SCarolineConcatto [&](const UseDetails &) { PutUse(symbol); }, 48464ab3302SCarolineConcatto [](const UseErrorDetails &) {}, 48564ab3302SCarolineConcatto [&](const ProcBindingDetails &x) { 48664ab3302SCarolineConcatto bool deferred{symbol.attrs().test(Attr::DEFERRED)}; 48764ab3302SCarolineConcatto typeBindings << "procedure"; 48864ab3302SCarolineConcatto if (deferred) { 48964ab3302SCarolineConcatto typeBindings << '(' << x.symbol().name() << ')'; 49064ab3302SCarolineConcatto } 49164ab3302SCarolineConcatto PutPassName(typeBindings, x.passName()); 49264ab3302SCarolineConcatto auto attrs{symbol.attrs()}; 49364ab3302SCarolineConcatto if (x.passName()) { 49464ab3302SCarolineConcatto attrs.reset(Attr::PASS); 49564ab3302SCarolineConcatto } 49664ab3302SCarolineConcatto PutAttrs(typeBindings, attrs); 49764ab3302SCarolineConcatto typeBindings << "::" << symbol.name(); 49864ab3302SCarolineConcatto if (!deferred && x.symbol().name() != symbol.name()) { 49964ab3302SCarolineConcatto typeBindings << "=>" << x.symbol().name(); 50064ab3302SCarolineConcatto } 50164ab3302SCarolineConcatto typeBindings << '\n'; 50264ab3302SCarolineConcatto }, 50364ab3302SCarolineConcatto [&](const NamelistDetails &x) { 50464ab3302SCarolineConcatto decls_ << "namelist/" << symbol.name(); 50564ab3302SCarolineConcatto char sep{'/'}; 50664ab3302SCarolineConcatto for (const Symbol &object : x.objects()) { 50764ab3302SCarolineConcatto decls_ << sep << object.name(); 50864ab3302SCarolineConcatto sep = ','; 50964ab3302SCarolineConcatto } 51064ab3302SCarolineConcatto decls_ << '\n'; 5114b7428e1SPeter Klausler if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { 5124b7428e1SPeter Klausler decls_ << "private::" << symbol.name() << '\n'; 5134b7428e1SPeter Klausler } 51464ab3302SCarolineConcatto }, 51564ab3302SCarolineConcatto [&](const CommonBlockDetails &x) { 51664ab3302SCarolineConcatto decls_ << "common/" << symbol.name(); 51764ab3302SCarolineConcatto char sep = '/'; 518d5c05cedSTim Keith for (const auto &object : x.objects()) { 519d5c05cedSTim Keith decls_ << sep << object->name(); 52064ab3302SCarolineConcatto sep = ','; 52164ab3302SCarolineConcatto } 52264ab3302SCarolineConcatto decls_ << '\n'; 52364ab3302SCarolineConcatto if (symbol.attrs().test(Attr::BIND_C)) { 5241db42fa6SSlava Zakharin PutAttrs(decls_, getSymbolAttrsToWrite(symbol), x.bindName(), 52569e2665cSPeter Klausler x.isExplicitBindName(), ""s); 52664ab3302SCarolineConcatto decls_ << "::/" << symbol.name() << "/\n"; 52764ab3302SCarolineConcatto } 52864ab3302SCarolineConcatto }, 52964ab3302SCarolineConcatto [](const HostAssocDetails &) {}, 53064ab3302SCarolineConcatto [](const MiscDetails &) {}, 5312cbd4fc4SPeixin-Qiao [&](const auto &) { 5322cbd4fc4SPeixin-Qiao PutEntity(decls_, symbol); 53322f63b5cSValentin Clement PutDirective(decls_, symbol); 5342cbd4fc4SPeixin-Qiao }, 53564ab3302SCarolineConcatto }, 53664ab3302SCarolineConcatto symbol.details()); 53764ab3302SCarolineConcatto } 53864ab3302SCarolineConcatto 539c14cf92bSPeter Klausler void ModFileWriter::PutDerivedType( 540c14cf92bSPeter Klausler const Symbol &typeSymbol, const Scope *scope) { 54164ab3302SCarolineConcatto auto &details{typeSymbol.get<DerivedTypeDetails>()}; 542c14cf92bSPeter Klausler if (details.isDECStructure()) { 543c14cf92bSPeter Klausler PutDECStructure(typeSymbol, scope); 544c14cf92bSPeter Klausler return; 545c14cf92bSPeter Klausler } 54664ab3302SCarolineConcatto PutAttrs(decls_ << "type", typeSymbol.attrs()); 54764ab3302SCarolineConcatto if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) { 54864ab3302SCarolineConcatto decls_ << ",extends(" << extends->name() << ')'; 54964ab3302SCarolineConcatto } 55064ab3302SCarolineConcatto decls_ << "::" << typeSymbol.name(); 551539a6b50SPeter Klausler if (!details.paramNameOrder().empty()) { 55264ab3302SCarolineConcatto char sep{'('}; 553539a6b50SPeter Klausler for (const SymbolRef &ref : details.paramNameOrder()) { 554539a6b50SPeter Klausler decls_ << sep << ref->name(); 55564ab3302SCarolineConcatto sep = ','; 55664ab3302SCarolineConcatto } 55764ab3302SCarolineConcatto decls_ << ')'; 55864ab3302SCarolineConcatto } 55964ab3302SCarolineConcatto decls_ << '\n'; 56064ab3302SCarolineConcatto if (details.sequence()) { 56164ab3302SCarolineConcatto decls_ << "sequence\n"; 56264ab3302SCarolineConcatto } 563c14cf92bSPeter Klausler bool contains{PutComponents(typeSymbol)}; 56437b2e2b0Speter klausler if (!details.finals().empty()) { 56537b2e2b0Speter klausler const char *sep{contains ? "final::" : "contains\nfinal::"}; 56637b2e2b0Speter klausler for (const auto &pair : details.finals()) { 56737b2e2b0Speter klausler decls_ << sep << pair.second->name(); 56837b2e2b0Speter klausler sep = ","; 56937b2e2b0Speter klausler } 57037b2e2b0Speter klausler if (*sep == ',') { 57137b2e2b0Speter klausler decls_ << '\n'; 57237b2e2b0Speter klausler } 57337b2e2b0Speter klausler } 57464ab3302SCarolineConcatto decls_ << "end type\n"; 57564ab3302SCarolineConcatto } 57664ab3302SCarolineConcatto 577c14cf92bSPeter Klausler void ModFileWriter::PutDECStructure( 578c14cf92bSPeter Klausler const Symbol &typeSymbol, const Scope *scope) { 579c14cf92bSPeter Klausler if (emittedDECStructures_.find(typeSymbol) != emittedDECStructures_.end()) { 580c14cf92bSPeter Klausler return; 581c14cf92bSPeter Klausler } 582c14cf92bSPeter Klausler if (!scope && context_.IsTempName(typeSymbol.name().ToString())) { 583c14cf92bSPeter Klausler return; // defer until used 584c14cf92bSPeter Klausler } 585c14cf92bSPeter Klausler emittedDECStructures_.insert(typeSymbol); 586c14cf92bSPeter Klausler decls_ << "structure "; 587c14cf92bSPeter Klausler if (!context_.IsTempName(typeSymbol.name().ToString())) { 588c14cf92bSPeter Klausler decls_ << typeSymbol.name(); 589c14cf92bSPeter Klausler } 590c14cf92bSPeter Klausler if (scope && scope->kind() == Scope::Kind::DerivedType) { 591c14cf92bSPeter Klausler // Nested STRUCTURE: emit entity declarations right now 592c14cf92bSPeter Klausler // on the STRUCTURE statement. 593c14cf92bSPeter Klausler bool any{false}; 594c14cf92bSPeter Klausler for (const auto &ref : scope->GetSymbols()) { 595c14cf92bSPeter Klausler const auto *object{ref->detailsIf<ObjectEntityDetails>()}; 596c14cf92bSPeter Klausler if (object && object->type() && 597c14cf92bSPeter Klausler object->type()->category() == DeclTypeSpec::TypeDerived && 598c14cf92bSPeter Klausler &object->type()->derivedTypeSpec().typeSymbol() == &typeSymbol) { 599c14cf92bSPeter Klausler if (any) { 600c14cf92bSPeter Klausler decls_ << ','; 601c14cf92bSPeter Klausler } else { 602c14cf92bSPeter Klausler any = true; 603c14cf92bSPeter Klausler } 604c14cf92bSPeter Klausler decls_ << ref->name(); 605c14cf92bSPeter Klausler PutShape(decls_, object->shape(), '(', ')'); 6069ce8e63cSPeter Klausler PutInit(decls_, *ref, object->init(), nullptr); 607c14cf92bSPeter Klausler emittedDECFields_.insert(*ref); 608c14cf92bSPeter Klausler } else if (any) { 609c14cf92bSPeter Klausler break; // any later use of this structure will use RECORD/str/ 610c14cf92bSPeter Klausler } 611c14cf92bSPeter Klausler } 612c14cf92bSPeter Klausler } 613c14cf92bSPeter Klausler decls_ << '\n'; 614c14cf92bSPeter Klausler PutComponents(typeSymbol); 615c14cf92bSPeter Klausler decls_ << "end structure\n"; 616c14cf92bSPeter Klausler } 617c14cf92bSPeter Klausler 61864ab3302SCarolineConcatto // Attributes that may be in a subprogram prefix 61964ab3302SCarolineConcatto static const Attrs subprogramPrefixAttrs{Attr::ELEMENTAL, Attr::IMPURE, 62064ab3302SCarolineConcatto Attr::MODULE, Attr::NON_RECURSIVE, Attr::PURE, Attr::RECURSIVE}; 62164ab3302SCarolineConcatto 622c8ad8024SValentin Clement static void PutOpenACCDeviceTypeRoutineInfo( 623c8ad8024SValentin Clement llvm::raw_ostream &os, const OpenACCRoutineDeviceTypeInfo &info) { 62422209a67SValentin Clement if (info.isSeq()) { 62522209a67SValentin Clement os << " seq"; 62622209a67SValentin Clement } 62722209a67SValentin Clement if (info.isGang()) { 62822209a67SValentin Clement os << " gang"; 62922209a67SValentin Clement if (info.gangDim() > 0) { 63022209a67SValentin Clement os << "(dim: " << info.gangDim() << ")"; 63122209a67SValentin Clement } 63222209a67SValentin Clement } 63322209a67SValentin Clement if (info.isVector()) { 63422209a67SValentin Clement os << " vector"; 63522209a67SValentin Clement } 63622209a67SValentin Clement if (info.isWorker()) { 63722209a67SValentin Clement os << " worker"; 63822209a67SValentin Clement } 63922209a67SValentin Clement if (info.bindName()) { 64022209a67SValentin Clement os << " bind(" << *info.bindName() << ")"; 64122209a67SValentin Clement } 642c8ad8024SValentin Clement } 643c8ad8024SValentin Clement 644c8ad8024SValentin Clement static void PutOpenACCRoutineInfo( 645c8ad8024SValentin Clement llvm::raw_ostream &os, const SubprogramDetails &details) { 646c8ad8024SValentin Clement for (auto info : details.openACCRoutineInfos()) { 647c8ad8024SValentin Clement os << "!$acc routine"; 648c8ad8024SValentin Clement 649c8ad8024SValentin Clement PutOpenACCDeviceTypeRoutineInfo(os, info); 650c8ad8024SValentin Clement 651c8ad8024SValentin Clement if (info.isNohost()) { 652c8ad8024SValentin Clement os << " nohost"; 653c8ad8024SValentin Clement } 654c8ad8024SValentin Clement 655c8ad8024SValentin Clement for (auto dtype : info.deviceTypeInfos()) { 656c8ad8024SValentin Clement os << " device_type("; 657c8ad8024SValentin Clement if (dtype.dType() == common::OpenACCDeviceType::Star) { 658c8ad8024SValentin Clement os << "*"; 659c8ad8024SValentin Clement } else { 660c8ad8024SValentin Clement os << parser::ToLowerCaseLetters(common::EnumToString(dtype.dType())); 661c8ad8024SValentin Clement } 662c8ad8024SValentin Clement os << ")"; 663c8ad8024SValentin Clement 664c8ad8024SValentin Clement PutOpenACCDeviceTypeRoutineInfo(os, dtype); 665c8ad8024SValentin Clement } 666c8ad8024SValentin Clement 66722209a67SValentin Clement os << "\n"; 66822209a67SValentin Clement } 66922209a67SValentin Clement } 67022209a67SValentin Clement 67164ab3302SCarolineConcatto void ModFileWriter::PutSubprogram(const Symbol &symbol) { 67264ab3302SCarolineConcatto auto &details{symbol.get<SubprogramDetails>()}; 673b67984d3SPeter Klausler if (const Symbol * interface{details.moduleInterface()}) { 674bb7e31bcSPeter Klausler const Scope *module{FindModuleContaining(interface->owner())}; 675bb7e31bcSPeter Klausler if (module && module != &symbol.owner()) { 676bb7e31bcSPeter Klausler // Interface is in ancestor module 677bb7e31bcSPeter Klausler } else { 678b67984d3SPeter Klausler PutSubprogram(*interface); 679b67984d3SPeter Klausler } 680bb7e31bcSPeter Klausler } 681b67984d3SPeter Klausler auto attrs{symbol.attrs()}; 68264ab3302SCarolineConcatto Attrs bindAttrs{}; 68364ab3302SCarolineConcatto if (attrs.test(Attr::BIND_C)) { 68464ab3302SCarolineConcatto // bind(c) is a suffix, not prefix 68564ab3302SCarolineConcatto bindAttrs.set(Attr::BIND_C, true); 68664ab3302SCarolineConcatto attrs.set(Attr::BIND_C, false); 68764ab3302SCarolineConcatto } 688d55627d2STim Keith bool isAbstract{attrs.test(Attr::ABSTRACT)}; 689d55627d2STim Keith if (isAbstract) { 690d55627d2STim Keith attrs.set(Attr::ABSTRACT, false); 691d55627d2STim Keith } 69264ab3302SCarolineConcatto Attrs prefixAttrs{subprogramPrefixAttrs & attrs}; 69364ab3302SCarolineConcatto // emit any non-prefix attributes in an attribute statement 69464ab3302SCarolineConcatto attrs &= ~subprogramPrefixAttrs; 6958670e499SCaroline Concatto std::string ssBuf; 6968670e499SCaroline Concatto llvm::raw_string_ostream ss{ssBuf}; 69764ab3302SCarolineConcatto PutAttrs(ss, attrs); 69864ab3302SCarolineConcatto if (!ss.str().empty()) { 69964ab3302SCarolineConcatto decls_ << ss.str().substr(1) << "::" << symbol.name() << '\n'; 70064ab3302SCarolineConcatto } 70164ab3302SCarolineConcatto bool isInterface{details.isInterface()}; 7028670e499SCaroline Concatto llvm::raw_ostream &os{isInterface ? decls_ : contains_}; 70364ab3302SCarolineConcatto if (isInterface) { 704d55627d2STim Keith os << (isAbstract ? "abstract " : "") << "interface\n"; 70564ab3302SCarolineConcatto } 70669e2665cSPeter Klausler PutAttrs(os, prefixAttrs, nullptr, false, ""s, " "s); 70727f71807SPeter Klausler if (auto attrs{details.cudaSubprogramAttrs()}) { 70827f71807SPeter Klausler if (*attrs == common::CUDASubprogramAttrs::HostDevice) { 70927f71807SPeter Klausler os << "attributes(host,device) "; 71027f71807SPeter Klausler } else { 71127f71807SPeter Klausler PutLower(os << "attributes(", common::EnumToString(*attrs)) << ") "; 71227f71807SPeter Klausler } 71327f71807SPeter Klausler if (!details.cudaLaunchBounds().empty()) { 71427f71807SPeter Klausler os << "launch_bounds"; 71527f71807SPeter Klausler char sep{'('}; 71627f71807SPeter Klausler for (auto x : details.cudaLaunchBounds()) { 71727f71807SPeter Klausler os << sep << x; 71827f71807SPeter Klausler sep = ','; 71927f71807SPeter Klausler } 72027f71807SPeter Klausler os << ") "; 72127f71807SPeter Klausler } 72227f71807SPeter Klausler if (!details.cudaClusterDims().empty()) { 72327f71807SPeter Klausler os << "cluster_dims"; 72427f71807SPeter Klausler char sep{'('}; 72527f71807SPeter Klausler for (auto x : details.cudaClusterDims()) { 72627f71807SPeter Klausler os << sep << x; 72727f71807SPeter Klausler sep = ','; 72827f71807SPeter Klausler } 72927f71807SPeter Klausler os << ") "; 73027f71807SPeter Klausler } 73127f71807SPeter Klausler } 73264ab3302SCarolineConcatto os << (details.isFunction() ? "function " : "subroutine "); 73364ab3302SCarolineConcatto os << symbol.name() << '('; 73464ab3302SCarolineConcatto int n = 0; 73564ab3302SCarolineConcatto for (const auto &dummy : details.dummyArgs()) { 73664ab3302SCarolineConcatto if (n++ > 0) { 73764ab3302SCarolineConcatto os << ','; 73864ab3302SCarolineConcatto } 7393ed2909fSPete Steinfeld if (dummy) { 74064ab3302SCarolineConcatto os << dummy->name(); 7413ed2909fSPete Steinfeld } else { 7423ed2909fSPete Steinfeld os << "*"; 7433ed2909fSPete Steinfeld } 74464ab3302SCarolineConcatto } 74564ab3302SCarolineConcatto os << ')'; 74669e2665cSPeter Klausler PutAttrs(os, bindAttrs, details.bindName(), details.isExplicitBindName(), 74769e2665cSPeter Klausler " "s, ""s); 74864ab3302SCarolineConcatto if (details.isFunction()) { 74964ab3302SCarolineConcatto const Symbol &result{details.result()}; 75064ab3302SCarolineConcatto if (result.name() != symbol.name()) { 75164ab3302SCarolineConcatto os << " result(" << result.name() << ')'; 75264ab3302SCarolineConcatto } 75364ab3302SCarolineConcatto } 75464ab3302SCarolineConcatto os << '\n'; 755c42f6314Speter klausler // walk symbols, collect ones needed for interface 756c42f6314Speter klausler const Scope &scope{ 757c42f6314Speter klausler details.entryScope() ? *details.entryScope() : DEREF(symbol.scope())}; 758c42f6314Speter klausler SubprogramSymbolCollector collector{symbol, scope}; 759c42f6314Speter klausler collector.Collect(); 7608670e499SCaroline Concatto std::string typeBindingsBuf; 7618670e499SCaroline Concatto llvm::raw_string_ostream typeBindings{typeBindingsBuf}; 762c42f6314Speter klausler ModFileWriter writer{context_}; 76364ab3302SCarolineConcatto for (const Symbol &need : collector.symbols()) { 76464ab3302SCarolineConcatto writer.PutSymbol(typeBindings, need); 76564ab3302SCarolineConcatto } 76664ab3302SCarolineConcatto CHECK(typeBindings.str().empty()); 76764ab3302SCarolineConcatto os << writer.uses_.str(); 76864ab3302SCarolineConcatto for (const SourceName &import : collector.imports()) { 76964ab3302SCarolineConcatto decls_ << "import::" << import << "\n"; 77064ab3302SCarolineConcatto } 77164ab3302SCarolineConcatto os << writer.decls_.str(); 77222209a67SValentin Clement PutOpenACCRoutineInfo(os, details); 77364ab3302SCarolineConcatto os << "end\n"; 77464ab3302SCarolineConcatto if (isInterface) { 77564ab3302SCarolineConcatto os << "end interface\n"; 77664ab3302SCarolineConcatto } 77764ab3302SCarolineConcatto } 77864ab3302SCarolineConcatto 77964ab3302SCarolineConcatto static bool IsIntrinsicOp(const Symbol &symbol) { 78064ab3302SCarolineConcatto if (const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()}) { 78164ab3302SCarolineConcatto return details->kind().IsIntrinsicOperator(); 78264ab3302SCarolineConcatto } else { 78364ab3302SCarolineConcatto return false; 78464ab3302SCarolineConcatto } 78564ab3302SCarolineConcatto } 78664ab3302SCarolineConcatto 78764ab3302SCarolineConcatto void ModFileWriter::PutGeneric(const Symbol &symbol) { 78886f59de1STim Keith const auto &genericOwner{symbol.owner()}; 78964ab3302SCarolineConcatto auto &details{symbol.get<GenericDetails>()}; 79064ab3302SCarolineConcatto PutGenericName(decls_ << "interface ", symbol) << '\n'; 79164ab3302SCarolineConcatto for (const Symbol &specific : details.specificProcs()) { 79286f59de1STim Keith if (specific.owner() == genericOwner) { 79364ab3302SCarolineConcatto decls_ << "procedure::" << specific.name() << '\n'; 79464ab3302SCarolineConcatto } 79586f59de1STim Keith } 79664ab3302SCarolineConcatto decls_ << "end interface\n"; 7974b7428e1SPeter Klausler if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { 79864ab3302SCarolineConcatto PutGenericName(decls_ << "private::", symbol) << '\n'; 79964ab3302SCarolineConcatto } 80064ab3302SCarolineConcatto } 80164ab3302SCarolineConcatto 80264ab3302SCarolineConcatto void ModFileWriter::PutUse(const Symbol &symbol) { 80364ab3302SCarolineConcatto auto &details{symbol.get<UseDetails>()}; 80464ab3302SCarolineConcatto auto &use{details.symbol()}; 80515faac90SPeter Klausler const Symbol &module{GetUsedModule(details)}; 80615faac90SPeter Klausler if (use.owner().parent().IsIntrinsicModules()) { 80715faac90SPeter Klausler uses_ << "use,intrinsic::"; 80815faac90SPeter Klausler } else { 80915faac90SPeter Klausler uses_ << "use "; 810e00a3ccfSPeter Klausler usedNonIntrinsicModules_.insert(module); 81115faac90SPeter Klausler } 81215faac90SPeter Klausler uses_ << module.name() << ",only:"; 81315faac90SPeter Klausler PutGenericName(uses_, symbol); 81464ab3302SCarolineConcatto // Can have intrinsic op with different local-name and use-name 81564ab3302SCarolineConcatto // (e.g. `operator(<)` and `operator(.lt.)`) but rename is not allowed 81664ab3302SCarolineConcatto if (!IsIntrinsicOp(symbol) && use.name() != symbol.name()) { 81764ab3302SCarolineConcatto PutGenericName(uses_ << "=>", use); 81864ab3302SCarolineConcatto } 81964ab3302SCarolineConcatto uses_ << '\n'; 82064ab3302SCarolineConcatto PutUseExtraAttr(Attr::VOLATILE, symbol, use); 82164ab3302SCarolineConcatto PutUseExtraAttr(Attr::ASYNCHRONOUS, symbol, use); 8224b7428e1SPeter Klausler if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { 8234864d9f7Speter klausler PutGenericName(useExtraAttrs_ << "private::", symbol) << '\n'; 8244864d9f7Speter klausler } 82564ab3302SCarolineConcatto } 82664ab3302SCarolineConcatto 82764ab3302SCarolineConcatto // We have "USE local => use" in this module. If attr was added locally 82864ab3302SCarolineConcatto // (i.e. on local but not on use), also write it out in the mod file. 82964ab3302SCarolineConcatto void ModFileWriter::PutUseExtraAttr( 83064ab3302SCarolineConcatto Attr attr, const Symbol &local, const Symbol &use) { 83164ab3302SCarolineConcatto if (local.attrs().test(attr) && !use.attrs().test(attr)) { 83264ab3302SCarolineConcatto PutAttr(useExtraAttrs_, attr) << "::"; 83364ab3302SCarolineConcatto useExtraAttrs_ << local.name() << '\n'; 83464ab3302SCarolineConcatto } 83564ab3302SCarolineConcatto } 83664ab3302SCarolineConcatto 8374864d9f7Speter klausler static inline SourceName NameInModuleFile(const Symbol &symbol) { 838a3e9d3c2SPeter Klausler if (const auto *use{symbol.detailsIf<UseDetails>()}) { 8394864d9f7Speter klausler if (use->symbol().attrs().test(Attr::PRIVATE)) { 8404864d9f7Speter klausler // Avoid the use in sorting of names created to access private 8414864d9f7Speter klausler // specific procedures as a result of generic resolution; 8424864d9f7Speter klausler // they're not in the cooked source. 8434864d9f7Speter klausler return use->symbol().name(); 8444864d9f7Speter klausler } 8454864d9f7Speter klausler } 8464864d9f7Speter klausler return symbol.name(); 8474864d9f7Speter klausler } 8484864d9f7Speter klausler 84964ab3302SCarolineConcatto // Collect the symbols of this scope sorted by their original order, not name. 850a3e9d3c2SPeter Klausler // Generics and namelists are exceptions: they are sorted after other symbols. 8511bea0347SPeter Klausler void CollectSymbols(const Scope &scope, SymbolVector &sorted, 8529ce8e63cSPeter Klausler SymbolVector &uses, UnorderedSymbolSet &modules) { 853a3e9d3c2SPeter Klausler SymbolVector namelist, generics; 854c353ebbfSTim Keith auto symbols{scope.GetSymbols()}; 8551bea0347SPeter Klausler std::size_t commonSize{scope.commonBlocks().size()}; 856c353ebbfSTim Keith sorted.reserve(symbols.size() + commonSize); 857c353ebbfSTim Keith for (SymbolRef symbol : symbols) { 858f7a15e00SPeter Klausler const auto *generic{symbol->detailsIf<GenericDetails>()}; 859f7a15e00SPeter Klausler if (generic) { 860f7a15e00SPeter Klausler uses.insert(uses.end(), generic->uses().begin(), generic->uses().end()); 861f7a15e00SPeter Klausler for (auto ref : generic->uses()) { 862f7a15e00SPeter Klausler modules.insert(GetUsedModule(ref->get<UseDetails>())); 863f7a15e00SPeter Klausler } 864f7a15e00SPeter Klausler } else if (const auto *use{symbol->detailsIf<UseDetails>()}) { 865f7a15e00SPeter Klausler modules.insert(GetUsedModule(*use)); 866f7a15e00SPeter Klausler } 8671bea0347SPeter Klausler if (symbol->test(Symbol::Flag::ParentComp)) { 8681bea0347SPeter Klausler } else if (symbol->has<NamelistDetails>()) { 86964ab3302SCarolineConcatto namelist.push_back(symbol); 870f7a15e00SPeter Klausler } else if (generic) { 871a3e9d3c2SPeter Klausler if (generic->specific() && 872a3e9d3c2SPeter Klausler &generic->specific()->owner() == &symbol->owner()) { 873a3e9d3c2SPeter Klausler sorted.push_back(*generic->specific()); 874a3e9d3c2SPeter Klausler } else if (generic->derivedType() && 875a3e9d3c2SPeter Klausler &generic->derivedType()->owner() == &symbol->owner()) { 876a3e9d3c2SPeter Klausler sorted.push_back(*generic->derivedType()); 877a3e9d3c2SPeter Klausler } 878a3e9d3c2SPeter Klausler generics.push_back(symbol); 87964ab3302SCarolineConcatto } else { 88064ab3302SCarolineConcatto sorted.push_back(symbol); 88164ab3302SCarolineConcatto } 88264ab3302SCarolineConcatto } 883d55627d2STim Keith // Sort most symbols by name: use of Symbol::ReplaceName ensures the source 884d55627d2STim Keith // location of a symbol's name is the first "real" use. 885a3e9d3c2SPeter Klausler auto sorter{[](SymbolRef x, SymbolRef y) { 886a3e9d3c2SPeter Klausler return NameInModuleFile(*x).begin() < NameInModuleFile(*y).begin(); 887a3e9d3c2SPeter Klausler }}; 888a3e9d3c2SPeter Klausler std::sort(sorted.begin(), sorted.end(), sorter); 889a3e9d3c2SPeter Klausler std::sort(generics.begin(), generics.end(), sorter); 890a3e9d3c2SPeter Klausler sorted.insert(sorted.end(), generics.begin(), generics.end()); 891c353ebbfSTim Keith sorted.insert(sorted.end(), namelist.begin(), namelist.end()); 89264ab3302SCarolineConcatto for (const auto &pair : scope.commonBlocks()) { 893c353ebbfSTim Keith sorted.push_back(*pair.second); 89464ab3302SCarolineConcatto } 8950d8331c0Speter klausler std::sort( 8960d8331c0Speter klausler sorted.end() - commonSize, sorted.end(), SymbolSourcePositionCompare{}); 89764ab3302SCarolineConcatto } 89864ab3302SCarolineConcatto 899c14cf92bSPeter Klausler void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol) { 900cd03e96fSPeter Klausler common::visit( 90164ab3302SCarolineConcatto common::visitors{ 90264ab3302SCarolineConcatto [&](const ObjectEntityDetails &) { PutObjectEntity(os, symbol); }, 90364ab3302SCarolineConcatto [&](const ProcEntityDetails &) { PutProcEntity(os, symbol); }, 90464ab3302SCarolineConcatto [&](const TypeParamDetails &) { PutTypeParam(os, symbol); }, 90564ab3302SCarolineConcatto [&](const auto &) { 90664ab3302SCarolineConcatto common::die("PutEntity: unexpected details: %s", 90764ab3302SCarolineConcatto DetailsToString(symbol.details()).c_str()); 90864ab3302SCarolineConcatto }, 90964ab3302SCarolineConcatto }, 91064ab3302SCarolineConcatto symbol.details()); 91164ab3302SCarolineConcatto } 91264ab3302SCarolineConcatto 9138670e499SCaroline Concatto void PutShapeSpec(llvm::raw_ostream &os, const ShapeSpec &x) { 91444bc97c8SPeter Klausler if (x.lbound().isStar()) { 91544bc97c8SPeter Klausler CHECK(x.ubound().isStar()); 91644bc97c8SPeter Klausler os << ".."; // assumed rank 91764ab3302SCarolineConcatto } else { 91844bc97c8SPeter Klausler if (!x.lbound().isColon()) { 91964ab3302SCarolineConcatto PutBound(os, x.lbound()); 92064ab3302SCarolineConcatto } 92164ab3302SCarolineConcatto os << ':'; 92244bc97c8SPeter Klausler if (!x.ubound().isColon()) { 92364ab3302SCarolineConcatto PutBound(os, x.ubound()); 92464ab3302SCarolineConcatto } 92564ab3302SCarolineConcatto } 92664ab3302SCarolineConcatto } 9278670e499SCaroline Concatto void PutShape( 9288670e499SCaroline Concatto llvm::raw_ostream &os, const ArraySpec &shape, char open, char close) { 92964ab3302SCarolineConcatto if (!shape.empty()) { 93064ab3302SCarolineConcatto os << open; 93164ab3302SCarolineConcatto bool first{true}; 93264ab3302SCarolineConcatto for (const auto &shapeSpec : shape) { 93364ab3302SCarolineConcatto if (first) { 93464ab3302SCarolineConcatto first = false; 93564ab3302SCarolineConcatto } else { 93664ab3302SCarolineConcatto os << ','; 93764ab3302SCarolineConcatto } 93864ab3302SCarolineConcatto PutShapeSpec(os, shapeSpec); 93964ab3302SCarolineConcatto } 94064ab3302SCarolineConcatto os << close; 94164ab3302SCarolineConcatto } 94264ab3302SCarolineConcatto } 94364ab3302SCarolineConcatto 944c14cf92bSPeter Klausler void ModFileWriter::PutObjectEntity( 945c14cf92bSPeter Klausler llvm::raw_ostream &os, const Symbol &symbol) { 94664ab3302SCarolineConcatto auto &details{symbol.get<ObjectEntityDetails>()}; 947c14cf92bSPeter Klausler if (details.type() && 948c14cf92bSPeter Klausler details.type()->category() == DeclTypeSpec::TypeDerived) { 949c14cf92bSPeter Klausler const Symbol &typeSymbol{details.type()->derivedTypeSpec().typeSymbol()}; 950c14cf92bSPeter Klausler if (typeSymbol.get<DerivedTypeDetails>().isDECStructure()) { 951c14cf92bSPeter Klausler PutDerivedType(typeSymbol, &symbol.owner()); 952c14cf92bSPeter Klausler if (emittedDECFields_.find(symbol) != emittedDECFields_.end()) { 953c14cf92bSPeter Klausler return; // symbol was emitted on STRUCTURE statement 954c14cf92bSPeter Klausler } 955c14cf92bSPeter Klausler } 956c14cf92bSPeter Klausler } 9571f879005STim Keith PutEntity( 9581f879005STim Keith os, symbol, [&]() { PutType(os, DEREF(symbol.GetType())); }, 9591db42fa6SSlava Zakharin getSymbolAttrsToWrite(symbol)); 96064ab3302SCarolineConcatto PutShape(os, details.shape(), '(', ')'); 96164ab3302SCarolineConcatto PutShape(os, details.coshape(), '[', ']'); 9629ce8e63cSPeter Klausler PutInit(os, symbol, details.init(), details.unanalyzedPDTComponentInit()); 96364ab3302SCarolineConcatto os << '\n'; 964864cb2aaSPeter Klausler if (auto tkr{GetIgnoreTKR(symbol)}; !tkr.empty()) { 965864cb2aaSPeter Klausler os << "!dir$ ignore_tkr("; 966864cb2aaSPeter Klausler tkr.IterateOverMembers([&](common::IgnoreTKR tkr) { 967864cb2aaSPeter Klausler switch (tkr) { 968864cb2aaSPeter Klausler SWITCH_COVERS_ALL_CASES 969864cb2aaSPeter Klausler case common::IgnoreTKR::Type: 970864cb2aaSPeter Klausler os << 't'; 971864cb2aaSPeter Klausler break; 972864cb2aaSPeter Klausler case common::IgnoreTKR::Kind: 973864cb2aaSPeter Klausler os << 'k'; 974864cb2aaSPeter Klausler break; 975864cb2aaSPeter Klausler case common::IgnoreTKR::Rank: 976864cb2aaSPeter Klausler os << 'r'; 977864cb2aaSPeter Klausler break; 978864cb2aaSPeter Klausler case common::IgnoreTKR::Device: 979864cb2aaSPeter Klausler os << 'd'; 980864cb2aaSPeter Klausler break; 981864cb2aaSPeter Klausler case common::IgnoreTKR::Managed: 982864cb2aaSPeter Klausler os << 'm'; 983864cb2aaSPeter Klausler break; 984864cb2aaSPeter Klausler case common::IgnoreTKR::Contiguous: 985864cb2aaSPeter Klausler os << 'c'; 986864cb2aaSPeter Klausler break; 987864cb2aaSPeter Klausler } 988864cb2aaSPeter Klausler }); 989864cb2aaSPeter Klausler os << ") " << symbol.name() << '\n'; 990864cb2aaSPeter Klausler } 99127f71807SPeter Klausler if (auto attr{details.cudaDataAttr()}) { 99227f71807SPeter Klausler PutLower(os << "attributes(", common::EnumToString(*attr)) 99327f71807SPeter Klausler << ") " << symbol.name() << '\n'; 99427f71807SPeter Klausler } 995602e5098Skkwli if (symbol.test(Fortran::semantics::Symbol::Flag::CrayPointer)) { 996602e5098Skkwli if (!symbol.owner().crayPointers().empty()) { 997602e5098Skkwli for (const auto &[pointee, pointer] : symbol.owner().crayPointers()) { 998602e5098Skkwli if (pointer == symbol) { 999602e5098Skkwli os << "pointer(" << symbol.name() << "," << pointee << ")\n"; 1000602e5098Skkwli } 1001602e5098Skkwli } 1002602e5098Skkwli } 1003602e5098Skkwli } 100464ab3302SCarolineConcatto } 100564ab3302SCarolineConcatto 1006c14cf92bSPeter Klausler void ModFileWriter::PutProcEntity(llvm::raw_ostream &os, const Symbol &symbol) { 100764ab3302SCarolineConcatto if (symbol.attrs().test(Attr::INTRINSIC)) { 100864ab3302SCarolineConcatto os << "intrinsic::" << symbol.name() << '\n'; 10094b7428e1SPeter Klausler if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { 10108f16101cSpeter klausler os << "private::" << symbol.name() << '\n'; 10118f16101cSpeter klausler } 101264ab3302SCarolineConcatto return; 101364ab3302SCarolineConcatto } 101464ab3302SCarolineConcatto const auto &details{symbol.get<ProcEntityDetails>()}; 101564ab3302SCarolineConcatto Attrs attrs{symbol.attrs()}; 101664ab3302SCarolineConcatto if (details.passName()) { 101764ab3302SCarolineConcatto attrs.reset(Attr::PASS); 101864ab3302SCarolineConcatto } 10191f879005STim Keith PutEntity( 10201f879005STim Keith os, symbol, 102164ab3302SCarolineConcatto [&]() { 102264ab3302SCarolineConcatto os << "procedure("; 102383ca78deSPeter Klausler if (details.rawProcInterface()) { 102483ca78deSPeter Klausler os << details.rawProcInterface()->name(); 1025635656f4SPeter Klausler } else if (details.type()) { 1026635656f4SPeter Klausler PutType(os, *details.type()); 102764ab3302SCarolineConcatto } 102864ab3302SCarolineConcatto os << ')'; 102964ab3302SCarolineConcatto PutPassName(os, details.passName()); 103064ab3302SCarolineConcatto }, 103164ab3302SCarolineConcatto attrs); 103264ab3302SCarolineConcatto os << '\n'; 103364ab3302SCarolineConcatto } 103464ab3302SCarolineConcatto 10358670e499SCaroline Concatto void PutPassName( 10368670e499SCaroline Concatto llvm::raw_ostream &os, const std::optional<SourceName> &passName) { 103764ab3302SCarolineConcatto if (passName) { 103864ab3302SCarolineConcatto os << ",pass(" << *passName << ')'; 103964ab3302SCarolineConcatto } 104064ab3302SCarolineConcatto } 1041c14cf92bSPeter Klausler 1042c14cf92bSPeter Klausler void ModFileWriter::PutTypeParam(llvm::raw_ostream &os, const Symbol &symbol) { 104364ab3302SCarolineConcatto auto &details{symbol.get<TypeParamDetails>()}; 10441f879005STim Keith PutEntity( 10451f879005STim Keith os, symbol, 104664ab3302SCarolineConcatto [&]() { 104764ab3302SCarolineConcatto PutType(os, DEREF(symbol.GetType())); 1048539a6b50SPeter Klausler PutLower(os << ',', common::EnumToString(details.attr().value())); 104964ab3302SCarolineConcatto }, 105064ab3302SCarolineConcatto symbol.attrs()); 105164ab3302SCarolineConcatto PutInit(os, details.init()); 105264ab3302SCarolineConcatto os << '\n'; 105364ab3302SCarolineConcatto } 105464ab3302SCarolineConcatto 10559e7eef99SPeter Klausler void PutInit(llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init, 10569ce8e63cSPeter Klausler const parser::Expr *unanalyzed) { 10571bea0347SPeter Klausler if (IsNamedConstant(symbol) || symbol.owner().IsDerivedType()) { 10589e7eef99SPeter Klausler const char *assign{symbol.attrs().test(Attr::POINTER) ? "=>" : "="}; 10599e7eef99SPeter Klausler if (unanalyzed) { 10609e7eef99SPeter Klausler parser::Unparse(os << assign, *unanalyzed); 10619e7eef99SPeter Klausler } else if (init) { 10629e7eef99SPeter Klausler init->AsFortran(os << assign); 106364ab3302SCarolineConcatto } 106464ab3302SCarolineConcatto } 106564ab3302SCarolineConcatto } 106664ab3302SCarolineConcatto 10678670e499SCaroline Concatto void PutInit(llvm::raw_ostream &os, const MaybeIntExpr &init) { 106864ab3302SCarolineConcatto if (init) { 106964ab3302SCarolineConcatto init->AsFortran(os << '='); 107064ab3302SCarolineConcatto } 107164ab3302SCarolineConcatto } 107264ab3302SCarolineConcatto 10738670e499SCaroline Concatto void PutBound(llvm::raw_ostream &os, const Bound &x) { 107444bc97c8SPeter Klausler if (x.isStar()) { 107564ab3302SCarolineConcatto os << '*'; 107644bc97c8SPeter Klausler } else if (x.isColon()) { 107764ab3302SCarolineConcatto os << ':'; 107864ab3302SCarolineConcatto } else { 107964ab3302SCarolineConcatto x.GetExplicit()->AsFortran(os); 108064ab3302SCarolineConcatto } 108164ab3302SCarolineConcatto } 108264ab3302SCarolineConcatto 108364ab3302SCarolineConcatto // Write an entity (object or procedure) declaration. 108464ab3302SCarolineConcatto // writeType is called to write out the type. 1085c14cf92bSPeter Klausler void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol, 108664ab3302SCarolineConcatto std::function<void()> writeType, Attrs attrs) { 108764ab3302SCarolineConcatto writeType(); 108869e2665cSPeter Klausler PutAttrs(os, attrs, symbol.GetBindName(), symbol.GetIsExplicitBindName()); 1089c14cf92bSPeter Klausler if (symbol.owner().kind() == Scope::Kind::DerivedType && 1090c14cf92bSPeter Klausler context_.IsTempName(symbol.name().ToString())) { 1091c14cf92bSPeter Klausler os << "::%FILL"; 1092c14cf92bSPeter Klausler } else { 109364ab3302SCarolineConcatto os << "::" << symbol.name(); 109464ab3302SCarolineConcatto } 1095c14cf92bSPeter Klausler } 109664ab3302SCarolineConcatto 109764ab3302SCarolineConcatto // Put out each attribute to os, surrounded by `before` and `after` and 109864ab3302SCarolineConcatto // mapped to lower case. 10994b7428e1SPeter Klausler llvm::raw_ostream &ModFileWriter::PutAttrs(llvm::raw_ostream &os, Attrs attrs, 110069e2665cSPeter Klausler const std::string *bindName, bool isExplicitBindName, std::string before, 110169e2665cSPeter Klausler std::string after) const { 110264ab3302SCarolineConcatto attrs.set(Attr::PUBLIC, false); // no need to write PUBLIC 110364ab3302SCarolineConcatto attrs.set(Attr::EXTERNAL, false); // no need to write EXTERNAL 11044b7428e1SPeter Klausler if (isSubmodule_) { 11054b7428e1SPeter Klausler attrs.set(Attr::PRIVATE, false); 11064b7428e1SPeter Klausler } 110769e2665cSPeter Klausler if (bindName || isExplicitBindName) { 110869e2665cSPeter Klausler os << before << "bind(c"; 110969e2665cSPeter Klausler if (isExplicitBindName) { 111069e2665cSPeter Klausler os << ",name=\"" << (bindName ? *bindName : ""s) << '"'; 111169e2665cSPeter Klausler } 111269e2665cSPeter Klausler os << ')' << after; 111364ab3302SCarolineConcatto attrs.set(Attr::BIND_C, false); 111464ab3302SCarolineConcatto } 111564ab3302SCarolineConcatto for (std::size_t i{0}; i < Attr_enumSize; ++i) { 111664ab3302SCarolineConcatto Attr attr{static_cast<Attr>(i)}; 111764ab3302SCarolineConcatto if (attrs.test(attr)) { 111864ab3302SCarolineConcatto PutAttr(os << before, attr) << after; 111964ab3302SCarolineConcatto } 112064ab3302SCarolineConcatto } 112164ab3302SCarolineConcatto return os; 112264ab3302SCarolineConcatto } 112364ab3302SCarolineConcatto 11248670e499SCaroline Concatto llvm::raw_ostream &PutAttr(llvm::raw_ostream &os, Attr attr) { 112564ab3302SCarolineConcatto return PutLower(os, AttrToString(attr)); 112664ab3302SCarolineConcatto } 112764ab3302SCarolineConcatto 11288670e499SCaroline Concatto llvm::raw_ostream &PutType(llvm::raw_ostream &os, const DeclTypeSpec &type) { 112964ab3302SCarolineConcatto return PutLower(os, type.AsFortran()); 113064ab3302SCarolineConcatto } 113164ab3302SCarolineConcatto 1132bcba39a5SPeter Klausler llvm::raw_ostream &PutLower(llvm::raw_ostream &os, std::string_view str) { 113364ab3302SCarolineConcatto for (char c : str) { 113464ab3302SCarolineConcatto os << parser::ToLowerCaseLetter(c); 113564ab3302SCarolineConcatto } 113664ab3302SCarolineConcatto return os; 113764ab3302SCarolineConcatto } 113864ab3302SCarolineConcatto 113968f36106SValentin Clement void PutOpenACCDirective(llvm::raw_ostream &os, const Symbol &symbol) { 114022f63b5cSValentin Clement if (symbol.test(Symbol::Flag::AccDeclare)) { 114122f63b5cSValentin Clement os << "!$acc declare "; 114222f63b5cSValentin Clement if (symbol.test(Symbol::Flag::AccCopy)) { 114322f63b5cSValentin Clement os << "copy"; 1144a749b32aSValentin Clement } else if (symbol.test(Symbol::Flag::AccCopyIn) || 1145a749b32aSValentin Clement symbol.test(Symbol::Flag::AccCopyInReadOnly)) { 114622f63b5cSValentin Clement os << "copyin"; 114722f63b5cSValentin Clement } else if (symbol.test(Symbol::Flag::AccCopyOut)) { 114822f63b5cSValentin Clement os << "copyout"; 114922f63b5cSValentin Clement } else if (symbol.test(Symbol::Flag::AccCreate)) { 115022f63b5cSValentin Clement os << "create"; 115122f63b5cSValentin Clement } else if (symbol.test(Symbol::Flag::AccPresent)) { 115222f63b5cSValentin Clement os << "present"; 115322f63b5cSValentin Clement } else if (symbol.test(Symbol::Flag::AccDevicePtr)) { 115422f63b5cSValentin Clement os << "deviceptr"; 115522f63b5cSValentin Clement } else if (symbol.test(Symbol::Flag::AccDeviceResident)) { 115622f63b5cSValentin Clement os << "device_resident"; 115722f63b5cSValentin Clement } else if (symbol.test(Symbol::Flag::AccLink)) { 115822f63b5cSValentin Clement os << "link"; 115922f63b5cSValentin Clement } 1160a749b32aSValentin Clement os << "("; 1161a749b32aSValentin Clement if (symbol.test(Symbol::Flag::AccCopyInReadOnly)) { 1162a749b32aSValentin Clement os << "readonly: "; 1163a749b32aSValentin Clement } 1164a749b32aSValentin Clement os << symbol.name() << ")\n"; 116522f63b5cSValentin Clement } 116622f63b5cSValentin Clement } 116722f63b5cSValentin Clement 116868f36106SValentin Clement void PutOpenMPDirective(llvm::raw_ostream &os, const Symbol &symbol) { 116968f36106SValentin Clement if (symbol.test(Symbol::Flag::OmpThreadprivate)) { 117068f36106SValentin Clement os << "!$omp threadprivate(" << symbol.name() << ")\n"; 117168f36106SValentin Clement } 117268f36106SValentin Clement } 117368f36106SValentin Clement 117468f36106SValentin Clement void ModFileWriter::PutDirective(llvm::raw_ostream &os, const Symbol &symbol) { 117568f36106SValentin Clement PutOpenACCDirective(os, symbol); 117668f36106SValentin Clement PutOpenMPDirective(os, symbol); 117768f36106SValentin Clement } 117868f36106SValentin Clement 117964ab3302SCarolineConcatto struct Temp { 118061106305SSteve Scalpone Temp(int fd, std::string path) : fd{fd}, path{path} {} 11810855c454SDavid Truby Temp(Temp &&t) : fd{std::exchange(t.fd, -1)}, path{std::move(t.path)} {} 118264ab3302SCarolineConcatto ~Temp() { 11830855c454SDavid Truby if (fd >= 0) { 118461106305SSteve Scalpone llvm::sys::fs::file_t native{llvm::sys::fs::convertFDToNativeFile(fd)}; 118561106305SSteve Scalpone llvm::sys::fs::closeFile(native); 11860855c454SDavid Truby llvm::sys::fs::remove(path.c_str()); 118764ab3302SCarolineConcatto } 11880855c454SDavid Truby } 118961106305SSteve Scalpone int fd; 119064ab3302SCarolineConcatto std::string path; 119164ab3302SCarolineConcatto }; 119264ab3302SCarolineConcatto 119364ab3302SCarolineConcatto // Create a temp file in the same directory and with the same suffix as path. 119464ab3302SCarolineConcatto // Return an open file descriptor and its path. 11950855c454SDavid Truby static llvm::ErrorOr<Temp> MkTemp(const std::string &path) { 119664ab3302SCarolineConcatto auto length{path.length()}; 119764ab3302SCarolineConcatto auto dot{path.find_last_of("./")}; 11980855c454SDavid Truby std::string suffix{ 11990855c454SDavid Truby dot < length && path[dot] == '.' ? path.substr(dot + 1) : ""}; 120064ab3302SCarolineConcatto CHECK(length > suffix.length() && 120164ab3302SCarolineConcatto path.substr(length - suffix.length()) == suffix); 12020855c454SDavid Truby auto prefix{path.substr(0, length - suffix.length())}; 120361106305SSteve Scalpone int fd; 12040855c454SDavid Truby llvm::SmallString<16> tempPath; 12050855c454SDavid Truby if (std::error_code err{llvm::sys::fs::createUniqueFile( 12060855c454SDavid Truby prefix + "%%%%%%" + suffix, fd, tempPath)}) { 12070855c454SDavid Truby return err; 12080855c454SDavid Truby } 12090855c454SDavid Truby return Temp{fd, tempPath.c_str()}; 121064ab3302SCarolineConcatto } 121164ab3302SCarolineConcatto 121264ab3302SCarolineConcatto // Write the module file at path, prepending header. If an error occurs, 121364ab3302SCarolineConcatto // return errno, otherwise 0. 1214f7a15e00SPeter Klausler static std::error_code WriteFile(const std::string &path, 1215f7a15e00SPeter Klausler const std::string &contents, ModuleCheckSumType &checkSum, bool debug) { 1216f7a15e00SPeter Klausler checkSum = ComputeCheckSum(contents); 121764ab3302SCarolineConcatto auto header{std::string{ModHeader::bom} + ModHeader::magic + 1218f7a15e00SPeter Klausler CheckSumString(checkSum) + ModHeader::terminator}; 12190855c454SDavid Truby if (debug) { 12200855c454SDavid Truby llvm::dbgs() << "Processing module " << path << ": "; 12210855c454SDavid Truby } 122264ab3302SCarolineConcatto if (FileContentsMatch(path, header, contents)) { 12230855c454SDavid Truby if (debug) { 12240855c454SDavid Truby llvm::dbgs() << "module unchanged, not writing\n"; 122564ab3302SCarolineConcatto } 12260855c454SDavid Truby return {}; 122764ab3302SCarolineConcatto } 12280855c454SDavid Truby llvm::ErrorOr<Temp> temp{MkTemp(path)}; 12290855c454SDavid Truby if (!temp) { 12300855c454SDavid Truby return temp.getError(); 123164ab3302SCarolineConcatto } 12320855c454SDavid Truby llvm::raw_fd_ostream writer(temp->fd, /*shouldClose=*/false); 12330855c454SDavid Truby writer << header; 12340855c454SDavid Truby writer << contents; 12350855c454SDavid Truby writer.flush(); 12360855c454SDavid Truby if (writer.has_error()) { 12370855c454SDavid Truby return writer.error(); 123864ab3302SCarolineConcatto } 12390855c454SDavid Truby if (debug) { 12400855c454SDavid Truby llvm::dbgs() << "module written\n"; 12410855c454SDavid Truby } 12420855c454SDavid Truby return llvm::sys::fs::rename(temp->path, path); 124364ab3302SCarolineConcatto } 124464ab3302SCarolineConcatto 124564ab3302SCarolineConcatto // Return true if the stream matches what we would write for the mod file. 124664ab3302SCarolineConcatto static bool FileContentsMatch(const std::string &path, 124764ab3302SCarolineConcatto const std::string &header, const std::string &contents) { 124864ab3302SCarolineConcatto std::size_t hsize{header.size()}; 124964ab3302SCarolineConcatto std::size_t csize{contents.size()}; 12500855c454SDavid Truby auto buf_or{llvm::MemoryBuffer::getFile(path)}; 12510855c454SDavid Truby if (!buf_or) { 125264ab3302SCarolineConcatto return false; 125364ab3302SCarolineConcatto } 12540855c454SDavid Truby auto buf = std::move(buf_or.get()); 12550855c454SDavid Truby if (buf->getBufferSize() != hsize + csize) { 125664ab3302SCarolineConcatto return false; 125764ab3302SCarolineConcatto } 12580855c454SDavid Truby if (!std::equal(header.begin(), header.end(), buf->getBufferStart(), 12590855c454SDavid Truby buf->getBufferStart() + hsize)) { 126064ab3302SCarolineConcatto return false; 126164ab3302SCarolineConcatto } 12620855c454SDavid Truby 12630855c454SDavid Truby return std::equal(contents.begin(), contents.end(), 12640855c454SDavid Truby buf->getBufferStart() + hsize, buf->getBufferEnd()); 126564ab3302SCarolineConcatto } 126664ab3302SCarolineConcatto 126764ab3302SCarolineConcatto // Compute a simple hash of the contents of a module file and 126864ab3302SCarolineConcatto // return it as a string of hex digits. 126964ab3302SCarolineConcatto // This uses the Fowler-Noll-Vo hash function. 1270f7a15e00SPeter Klausler static ModuleCheckSumType ComputeCheckSum(const std::string_view &contents) { 1271f7a15e00SPeter Klausler ModuleCheckSumType hash{0xcbf29ce484222325ull}; 127264ab3302SCarolineConcatto for (char c : contents) { 127364ab3302SCarolineConcatto hash ^= c & 0xff; 127464ab3302SCarolineConcatto hash *= 0x100000001b3; 127564ab3302SCarolineConcatto } 1276f7a15e00SPeter Klausler return hash; 1277f7a15e00SPeter Klausler } 1278f7a15e00SPeter Klausler 1279f7a15e00SPeter Klausler static std::string CheckSumString(ModuleCheckSumType hash) { 128064ab3302SCarolineConcatto static const char *digits = "0123456789abcdef"; 128164ab3302SCarolineConcatto std::string result(ModHeader::sumLen, '0'); 128264ab3302SCarolineConcatto for (size_t i{ModHeader::sumLen}; hash != 0; hash >>= 4) { 128364ab3302SCarolineConcatto result[--i] = digits[hash & 0xf]; 128464ab3302SCarolineConcatto } 128564ab3302SCarolineConcatto return result; 128664ab3302SCarolineConcatto } 128764ab3302SCarolineConcatto 1288f7a15e00SPeter Klausler std::optional<ModuleCheckSumType> ExtractCheckSum(const std::string_view &str) { 1289f7a15e00SPeter Klausler if (str.size() == ModHeader::sumLen) { 1290f7a15e00SPeter Klausler ModuleCheckSumType hash{0}; 1291f7a15e00SPeter Klausler for (size_t j{0}; j < ModHeader::sumLen; ++j) { 1292f7a15e00SPeter Klausler hash <<= 4; 1293f7a15e00SPeter Klausler char ch{str.at(j)}; 1294f7a15e00SPeter Klausler if (ch >= '0' && ch <= '9') { 1295f7a15e00SPeter Klausler hash += ch - '0'; 1296f7a15e00SPeter Klausler } else if (ch >= 'a' && ch <= 'f') { 1297f7a15e00SPeter Klausler hash += ch - 'a' + 10; 1298f7a15e00SPeter Klausler } else { 1299f7a15e00SPeter Klausler return std::nullopt; 130064ab3302SCarolineConcatto } 1301f7a15e00SPeter Klausler } 1302f7a15e00SPeter Klausler return hash; 1303f7a15e00SPeter Klausler } 1304f7a15e00SPeter Klausler return std::nullopt; 130564ab3302SCarolineConcatto } 130664ab3302SCarolineConcatto 1307f7a15e00SPeter Klausler static std::optional<ModuleCheckSumType> VerifyHeader( 1308f7a15e00SPeter Klausler llvm::ArrayRef<char> content) { 1309f7a15e00SPeter Klausler std::string_view sv{content.data(), content.size()}; 1310f7a15e00SPeter Klausler if (sv.substr(0, ModHeader::magicLen) != ModHeader::magic) { 1311f7a15e00SPeter Klausler return std::nullopt; 1312f7a15e00SPeter Klausler } 1313f7a15e00SPeter Klausler ModuleCheckSumType checkSum{ComputeCheckSum(sv.substr(ModHeader::len))}; 1314f7a15e00SPeter Klausler std::string_view expectSum{sv.substr(ModHeader::magicLen, ModHeader::sumLen)}; 1315f7a15e00SPeter Klausler if (auto extracted{ExtractCheckSum(expectSum)}; 1316f7a15e00SPeter Klausler extracted && *extracted == checkSum) { 1317f7a15e00SPeter Klausler return checkSum; 1318f7a15e00SPeter Klausler } else { 1319f7a15e00SPeter Klausler return std::nullopt; 1320f7a15e00SPeter Klausler } 1321f7a15e00SPeter Klausler } 1322f7a15e00SPeter Klausler 1323f7a15e00SPeter Klausler static void GetModuleDependences( 1324f7a15e00SPeter Klausler ModuleDependences &dependences, llvm::ArrayRef<char> content) { 1325f7a15e00SPeter Klausler std::size_t limit{content.size()}; 1326f7a15e00SPeter Klausler std::string_view str{content.data(), limit}; 1327f7a15e00SPeter Klausler for (std::size_t j{ModHeader::len}; 13285661188cSPeter Klausler str.substr(j, ModHeader::needLen) == ModHeader::need; ++j) { 1329f7a15e00SPeter Klausler j += 7; 1330f7a15e00SPeter Klausler auto checkSum{ExtractCheckSum(str.substr(j, ModHeader::sumLen))}; 1331f7a15e00SPeter Klausler if (!checkSum) { 1332f7a15e00SPeter Klausler break; 1333f7a15e00SPeter Klausler } 1334f7a15e00SPeter Klausler j += ModHeader::sumLen; 1335f7a15e00SPeter Klausler bool intrinsic{false}; 1336f7a15e00SPeter Klausler if (str.substr(j, 3) == " i ") { 1337f7a15e00SPeter Klausler intrinsic = true; 1338f7a15e00SPeter Klausler } else if (str.substr(j, 3) != " n ") { 1339f7a15e00SPeter Klausler break; 1340f7a15e00SPeter Klausler } 1341f7a15e00SPeter Klausler j += 3; 1342f7a15e00SPeter Klausler std::size_t start{j}; 1343f7a15e00SPeter Klausler for (; j < limit && str.at(j) != '\n'; ++j) { 1344f7a15e00SPeter Klausler } 1345f7a15e00SPeter Klausler if (j > start && j < limit && str.at(j) == '\n') { 13465661188cSPeter Klausler std::string depModName{str.substr(start, j - start)}; 13475661188cSPeter Klausler dependences.AddDependence(std::move(depModName), intrinsic, *checkSum); 1348f7a15e00SPeter Klausler } else { 1349f7a15e00SPeter Klausler break; 1350f7a15e00SPeter Klausler } 1351f7a15e00SPeter Klausler } 1352f7a15e00SPeter Klausler } 1353f7a15e00SPeter Klausler 1354f7a15e00SPeter Klausler Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic, 1355f7a15e00SPeter Klausler Scope *ancestor, bool silent) { 135664ab3302SCarolineConcatto std::string ancestorName; // empty for module 13575661188cSPeter Klausler const Symbol *notAModule{nullptr}; 13589f33dd73SPeter Klausler bool fatalError{false}; 135964ab3302SCarolineConcatto if (ancestor) { 136064ab3302SCarolineConcatto if (auto *scope{ancestor->FindSubmodule(name)}) { 136164ab3302SCarolineConcatto return scope; 136264ab3302SCarolineConcatto } 136364ab3302SCarolineConcatto ancestorName = ancestor->GetName().value().ToString(); 1364dcbfabbeSPeter Klausler } 1365f7a15e00SPeter Klausler auto requiredHash{context_.moduleDependences().GetRequiredHash( 1366f7a15e00SPeter Klausler name.ToString(), isIntrinsic.value_or(false))}; 1367dcbfabbeSPeter Klausler if (!isIntrinsic.value_or(false) && !ancestor) { 1368dcbfabbeSPeter Klausler // Already present in the symbol table as a usable non-intrinsic module? 1369038b42baSPeter Klausler if (Scope * hermeticScope{context_.currentHermeticModuleFileScope()}) { 1370038b42baSPeter Klausler auto it{hermeticScope->find(name)}; 1371038b42baSPeter Klausler if (it != hermeticScope->end()) { 1372038b42baSPeter Klausler return it->second->scope(); 1373038b42baSPeter Klausler } 1374038b42baSPeter Klausler } 137564ab3302SCarolineConcatto auto it{context_.globalScope().find(name)}; 137664ab3302SCarolineConcatto if (it != context_.globalScope().end()) { 13779f33dd73SPeter Klausler Scope *scope{it->second->scope()}; 13789f33dd73SPeter Klausler if (scope->kind() == Scope::Kind::Module) { 13795661188cSPeter Klausler for (const Symbol *found{scope->symbol()}; found;) { 13805661188cSPeter Klausler if (const auto *module{found->detailsIf<ModuleDetails>()}) { 13815661188cSPeter Klausler if (!requiredHash || 13825661188cSPeter Klausler *requiredHash == 13835661188cSPeter Klausler module->moduleFileHash().value_or(*requiredHash)) { 13845661188cSPeter Klausler return const_cast<Scope *>(found->scope()); 13855661188cSPeter Klausler } 13865661188cSPeter Klausler found = module->previous(); // same name, distinct hash 13875661188cSPeter Klausler } else { 13885661188cSPeter Klausler notAModule = found; 13895661188cSPeter Klausler break; 1390f7a15e00SPeter Klausler } 1391f7a15e00SPeter Klausler } 13929f33dd73SPeter Klausler } else { 13939f33dd73SPeter Klausler notAModule = scope->symbol(); 13945661188cSPeter Klausler } 13955661188cSPeter Klausler } 13965661188cSPeter Klausler } 13975661188cSPeter Klausler if (notAModule) { 13989f33dd73SPeter Klausler // USE, NON_INTRINSIC global name isn't a module? 13999f33dd73SPeter Klausler fatalError = isIntrinsic.has_value(); 14009f33dd73SPeter Klausler } 14019629f2c4SPeter Klausler std::string path{ 14029629f2c4SPeter Klausler ModFileName(name, ancestorName, context_.moduleFileSuffix())}; 140392a54197Speter klausler parser::Parsing parsing{context_.allCookedSources()}; 140464ab3302SCarolineConcatto parser::Options options; 140564ab3302SCarolineConcatto options.isModuleFile = true; 140664ab3302SCarolineConcatto options.features.Enable(common::LanguageFeature::BackslashEscapes); 14072cbd4fc4SPeixin-Qiao options.features.Enable(common::LanguageFeature::OpenMP); 140827f71807SPeter Klausler options.features.Enable(common::LanguageFeature::CUDA); 14099f33dd73SPeter Klausler if (!isIntrinsic.value_or(false) && !notAModule) { 1410dcbfabbeSPeter Klausler // The search for this module file will scan non-intrinsic module 1411dcbfabbeSPeter Klausler // directories. If a directory is in both the intrinsic and non-intrinsic 1412dcbfabbeSPeter Klausler // directory lists, the intrinsic module directory takes precedence. 141364ab3302SCarolineConcatto options.searchDirectories = context_.searchDirectories(); 141452a1346bSPeter Klausler for (const auto &dir : context_.intrinsicModuleDirectories()) { 1415f95bdff1SShao-Ce SUN options.searchDirectories.erase( 141652a1346bSPeter Klausler std::remove(options.searchDirectories.begin(), 1417f95bdff1SShao-Ce SUN options.searchDirectories.end(), dir), 1418f95bdff1SShao-Ce SUN options.searchDirectories.end()); 141952a1346bSPeter Klausler } 142015faac90SPeter Klausler options.searchDirectories.insert(options.searchDirectories.begin(), "."s); 142152a1346bSPeter Klausler } 1422dcbfabbeSPeter Klausler bool foundNonIntrinsicModuleFile{false}; 1423dcbfabbeSPeter Klausler if (!isIntrinsic) { 1424dcbfabbeSPeter Klausler std::list<std::string> searchDirs; 1425dcbfabbeSPeter Klausler for (const auto &d : options.searchDirectories) { 1426dcbfabbeSPeter Klausler searchDirs.push_back(d); 1427dcbfabbeSPeter Klausler } 1428dcbfabbeSPeter Klausler foundNonIntrinsicModuleFile = 1429dcbfabbeSPeter Klausler parser::LocateSourceFile(path, searchDirs).has_value(); 1430dcbfabbeSPeter Klausler } 1431dcbfabbeSPeter Klausler if (isIntrinsic.value_or(!foundNonIntrinsicModuleFile)) { 1432dcbfabbeSPeter Klausler // Explicitly intrinsic, or not specified and not found in the search 1433dcbfabbeSPeter Klausler // path; see whether it's already in the symbol table as an intrinsic 1434dcbfabbeSPeter Klausler // module. 1435dcbfabbeSPeter Klausler auto it{context_.intrinsicModulesScope().find(name)}; 1436dcbfabbeSPeter Klausler if (it != context_.intrinsicModulesScope().end()) { 1437dcbfabbeSPeter Klausler return it->second->scope(); 1438dcbfabbeSPeter Klausler } 1439dcbfabbeSPeter Klausler } 1440dcbfabbeSPeter Klausler // We don't have this module in the symbol table yet. 1441dcbfabbeSPeter Klausler // Find its module file and parse it. Define or extend the search 1442dcbfabbeSPeter Klausler // path with intrinsic module directories, if appropriate. 144352a1346bSPeter Klausler if (isIntrinsic.value_or(true)) { 144452a1346bSPeter Klausler for (const auto &dir : context_.intrinsicModuleDirectories()) { 144552a1346bSPeter Klausler options.searchDirectories.push_back(dir); 144652a1346bSPeter Klausler } 1447f7a15e00SPeter Klausler if (!requiredHash) { 1448f7a15e00SPeter Klausler requiredHash = 1449f7a15e00SPeter Klausler context_.moduleDependences().GetRequiredHash(name.ToString(), true); 145052a1346bSPeter Klausler } 1451f7a15e00SPeter Klausler } 1452f7a15e00SPeter Klausler 1453f7a15e00SPeter Klausler // Look for the right module file if its hash is known 1454f7a15e00SPeter Klausler if (requiredHash && !fatalError) { 1455f7a15e00SPeter Klausler for (const std::string &maybe : 1456f7a15e00SPeter Klausler parser::LocateSourceFileAll(path, options.searchDirectories)) { 1457f7a15e00SPeter Klausler if (const auto *srcFile{context_.allCookedSources().allSources().OpenPath( 1458f7a15e00SPeter Klausler maybe, llvm::errs())}) { 14595661188cSPeter Klausler if (auto checkSum{VerifyHeader(srcFile->content())}; 14605661188cSPeter Klausler checkSum && *checkSum == *requiredHash) { 1461f7a15e00SPeter Klausler path = maybe; 1462f7a15e00SPeter Klausler break; 1463f7a15e00SPeter Klausler } 1464f7a15e00SPeter Klausler } 1465f7a15e00SPeter Klausler } 1466f7a15e00SPeter Klausler } 14679f33dd73SPeter Klausler const auto *sourceFile{fatalError ? nullptr : parsing.Prescan(path, options)}; 14689f33dd73SPeter Klausler if (fatalError || parsing.messages().AnyFatalError()) { 146952711fb8Speter klausler if (!silent) { 14709f33dd73SPeter Klausler if (notAModule) { 14719f33dd73SPeter Klausler // Module is not explicitly INTRINSIC, and there's already a global 14729f33dd73SPeter Klausler // symbol of the same name that is not a module. 14739f33dd73SPeter Klausler context_.SayWithDecl( 14749f33dd73SPeter Klausler *notAModule, name, "'%s' is not a module"_err_en_US, name); 14759f33dd73SPeter Klausler } else { 147664ab3302SCarolineConcatto for (auto &msg : parsing.messages().messages()) { 147764ab3302SCarolineConcatto std::string str{msg.ToString()}; 14789629f2c4SPeter Klausler Say("parse", name, ancestorName, 14792895771fSPeter Klausler parser::MessageFixedText{str.c_str(), str.size(), msg.severity()}, 14802895771fSPeter Klausler path); 148152711fb8Speter klausler } 148264ab3302SCarolineConcatto } 14839f33dd73SPeter Klausler } 148464ab3302SCarolineConcatto return nullptr; 148564ab3302SCarolineConcatto } 148664ab3302SCarolineConcatto CHECK(sourceFile); 1487f7a15e00SPeter Klausler std::optional<ModuleCheckSumType> checkSum{ 1488f7a15e00SPeter Klausler VerifyHeader(sourceFile->content())}; 1489f7a15e00SPeter Klausler if (!checkSum) { 14909629f2c4SPeter Klausler Say("use", name, ancestorName, "File has invalid checksum: %s"_err_en_US, 14910e907c17SIñaki Amatria Barral sourceFile->path()); 149264ab3302SCarolineConcatto return nullptr; 1493f7a15e00SPeter Klausler } else if (requiredHash && *requiredHash != *checkSum) { 14949629f2c4SPeter Klausler Say("use", name, ancestorName, 14950e907c17SIñaki Amatria Barral "File is not the right module file for %s"_err_en_US, 14960e907c17SIñaki Amatria Barral "'"s + name.ToString() + "': "s + sourceFile->path()); 1497f7a15e00SPeter Klausler return nullptr; 149864ab3302SCarolineConcatto } 14998670e499SCaroline Concatto llvm::raw_null_ostream NullStream; 15008670e499SCaroline Concatto parsing.Parse(NullStream); 1501f4bb211aSPeter Klausler std::optional<parser::Program> &parsedProgram{parsing.parseTree()}; 150264ab3302SCarolineConcatto if (!parsing.messages().empty() || !parsing.consumedWholeFile() || 1503f4bb211aSPeter Klausler !parsedProgram) { 15049629f2c4SPeter Klausler Say("parse", name, ancestorName, "Module file is corrupt: %s"_err_en_US, 150564ab3302SCarolineConcatto sourceFile->path()); 150664ab3302SCarolineConcatto return nullptr; 150764ab3302SCarolineConcatto } 1508f4bb211aSPeter Klausler parser::Program &parseTree{context_.SaveParseTree(std::move(*parsedProgram))}; 150964ab3302SCarolineConcatto Scope *parentScope; // the scope this module/submodule goes into 151052a1346bSPeter Klausler if (!isIntrinsic.has_value()) { 151152a1346bSPeter Klausler for (const auto &dir : context_.intrinsicModuleDirectories()) { 151252a1346bSPeter Klausler if (sourceFile->path().size() > dir.size() && 151352a1346bSPeter Klausler sourceFile->path().find(dir) == 0) { 151452a1346bSPeter Klausler isIntrinsic = true; 151552a1346bSPeter Klausler break; 151652a1346bSPeter Klausler } 151752a1346bSPeter Klausler } 151852a1346bSPeter Klausler } 151952a1346bSPeter Klausler Scope &topScope{isIntrinsic.value_or(false) ? context_.intrinsicModulesScope() 152052a1346bSPeter Klausler : context_.globalScope()}; 1521e200b0e4SPeter Klausler Symbol *moduleSymbol{nullptr}; 15225661188cSPeter Klausler const Symbol *previousModuleSymbol{nullptr}; 1523e200b0e4SPeter Klausler if (!ancestor) { // module, not submodule 152452a1346bSPeter Klausler parentScope = &topScope; 15254864d9f7Speter klausler auto pair{parentScope->try_emplace(name, UnknownDetails{})}; 15264864d9f7Speter klausler if (!pair.second) { 15275661188cSPeter Klausler // There is already a global symbol or intrinsic module of the same name. 15285661188cSPeter Klausler previousModuleSymbol = &*pair.first->second; 15295661188cSPeter Klausler if (const auto *details{ 15305661188cSPeter Klausler previousModuleSymbol->detailsIf<ModuleDetails>()}) { 15315661188cSPeter Klausler if (!details->moduleFileHash().has_value()) { 153264ab3302SCarolineConcatto return nullptr; 153364ab3302SCarolineConcatto } 15345661188cSPeter Klausler } else { 15355661188cSPeter Klausler return nullptr; 15365661188cSPeter Klausler } 15375661188cSPeter Klausler CHECK(parentScope->erase(name) != 0); 15385661188cSPeter Klausler pair = parentScope->try_emplace(name, UnknownDetails{}); 15395661188cSPeter Klausler CHECK(pair.second); 15405661188cSPeter Klausler } 1541e200b0e4SPeter Klausler moduleSymbol = &*pair.first->second; 1542e200b0e4SPeter Klausler moduleSymbol->set(Symbol::Flag::ModFile); 1543e200b0e4SPeter Klausler } else if (std::optional<SourceName> parent{GetSubmoduleParent(parseTree)}) { 1544e200b0e4SPeter Klausler // submodule with submodule parent 1545e200b0e4SPeter Klausler parentScope = Read(*parent, false /*not intrinsic*/, ancestor, silent); 1546e200b0e4SPeter Klausler } else { 1547e200b0e4SPeter Klausler // submodule with module parent 1548e200b0e4SPeter Klausler parentScope = ancestor; 1549e200b0e4SPeter Klausler } 155073506256SPeter Klausler // Process declarations from the module file 1551e1ad2735SPeter Klausler auto wasModuleFileName{context_.foldingContext().moduleFileName()}; 1552e1ad2735SPeter Klausler context_.foldingContext().set_moduleFileName(name); 1553038b42baSPeter Klausler // Are there multiple modules in the module file due to it having been 1554038b42baSPeter Klausler // created under -fhermetic-module-files? If so, process them first in 1555038b42baSPeter Klausler // their own nested scope that will be visible only to USE statements 1556038b42baSPeter Klausler // within the module file. 1557038b42baSPeter Klausler if (parseTree.v.size() > 1) { 1558038b42baSPeter Klausler parser::Program hermeticModules{std::move(parseTree.v)}; 1559038b42baSPeter Klausler parseTree.v.emplace_back(std::move(hermeticModules.v.front())); 1560038b42baSPeter Klausler hermeticModules.v.pop_front(); 1561038b42baSPeter Klausler Scope &hermeticScope{topScope.MakeScope(Scope::Kind::Global)}; 1562038b42baSPeter Klausler context_.set_currentHermeticModuleFileScope(&hermeticScope); 1563038b42baSPeter Klausler ResolveNames(context_, hermeticModules, hermeticScope); 1564038b42baSPeter Klausler } 1565f7a15e00SPeter Klausler GetModuleDependences(context_.moduleDependences(), sourceFile->content()); 1566f4bb211aSPeter Klausler ResolveNames(context_, parseTree, topScope); 1567e1ad2735SPeter Klausler context_.foldingContext().set_moduleFileName(wasModuleFileName); 1568038b42baSPeter Klausler context_.set_currentHermeticModuleFileScope(nullptr); 1569e200b0e4SPeter Klausler if (!moduleSymbol) { 1570e200b0e4SPeter Klausler // Submodule symbols' storage are owned by their parents' scopes, 1571e200b0e4SPeter Klausler // but their names are not in their parents' dictionaries -- we 1572e200b0e4SPeter Klausler // don't want to report bogus errors about clashes between submodule 1573e200b0e4SPeter Klausler // names and other objects in the parent scopes. 1574e200b0e4SPeter Klausler if (Scope * submoduleScope{ancestor->FindSubmodule(name)}) { 1575e200b0e4SPeter Klausler moduleSymbol = submoduleScope->symbol(); 1576e200b0e4SPeter Klausler if (moduleSymbol) { 1577e200b0e4SPeter Klausler moduleSymbol->set(Symbol::Flag::ModFile); 157852a1346bSPeter Klausler } 1579e200b0e4SPeter Klausler } 1580e200b0e4SPeter Klausler } 1581e200b0e4SPeter Klausler if (moduleSymbol) { 1582e200b0e4SPeter Klausler CHECK(moduleSymbol->test(Symbol::Flag::ModFile)); 15835661188cSPeter Klausler auto &details{moduleSymbol->get<ModuleDetails>()}; 15845661188cSPeter Klausler details.set_moduleFileHash(checkSum.value()); 15855661188cSPeter Klausler details.set_previous(previousModuleSymbol); 1586e200b0e4SPeter Klausler if (isIntrinsic.value_or(false)) { 1587e200b0e4SPeter Klausler moduleSymbol->attrs().set(Attr::INTRINSIC); 1588e200b0e4SPeter Klausler } 1589e200b0e4SPeter Klausler return moduleSymbol->scope(); 1590e200b0e4SPeter Klausler } else { 1591e200b0e4SPeter Klausler return nullptr; 1592e200b0e4SPeter Klausler } 159364ab3302SCarolineConcatto } 159464ab3302SCarolineConcatto 15959629f2c4SPeter Klausler parser::Message &ModFileReader::Say(const char *verb, SourceName name, 159664ab3302SCarolineConcatto const std::string &ancestor, parser::MessageFixedText &&msg, 159764ab3302SCarolineConcatto const std::string &arg) { 15989629f2c4SPeter Klausler return context_.Say(name, "Cannot %s module file for %s: %s"_err_en_US, verb, 15990bfa4ac6Speter klausler parser::MessageFormattedText{ancestor.empty() 16000bfa4ac6Speter klausler ? "module '%s'"_en_US 16010bfa4ac6Speter klausler : "submodule '%s' of module '%s'"_en_US, 16020bfa4ac6Speter klausler name, ancestor} 16030bfa4ac6Speter klausler .MoveString(), 16040bfa4ac6Speter klausler parser::MessageFormattedText{std::move(msg), arg}.MoveString()); 160564ab3302SCarolineConcatto } 160664ab3302SCarolineConcatto 160764ab3302SCarolineConcatto // program was read from a .mod file for a submodule; return the name of the 160864ab3302SCarolineConcatto // submodule's parent submodule, nullptr if none. 160964ab3302SCarolineConcatto static std::optional<SourceName> GetSubmoduleParent( 161064ab3302SCarolineConcatto const parser::Program &program) { 161164ab3302SCarolineConcatto CHECK(program.v.size() == 1); 161264ab3302SCarolineConcatto auto &unit{program.v.front()}; 161364ab3302SCarolineConcatto auto &submod{std::get<common::Indirection<parser::Submodule>>(unit.u)}; 161464ab3302SCarolineConcatto auto &stmt{ 161564ab3302SCarolineConcatto std::get<parser::Statement<parser::SubmoduleStmt>>(submod.value().t)}; 161664ab3302SCarolineConcatto auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)}; 161764ab3302SCarolineConcatto if (auto &parent{std::get<std::optional<parser::Name>>(parentId.t)}) { 161864ab3302SCarolineConcatto return parent->source; 161964ab3302SCarolineConcatto } else { 162064ab3302SCarolineConcatto return std::nullopt; 162164ab3302SCarolineConcatto } 162264ab3302SCarolineConcatto } 162364ab3302SCarolineConcatto 162464ab3302SCarolineConcatto void SubprogramSymbolCollector::Collect() { 162564ab3302SCarolineConcatto const auto &details{symbol_.get<SubprogramDetails>()}; 162664ab3302SCarolineConcatto isInterface_ = details.isInterface(); 162764ab3302SCarolineConcatto for (const Symbol *dummyArg : details.dummyArgs()) { 16283ed2909fSPete Steinfeld if (dummyArg) { 16293ed2909fSPete Steinfeld DoSymbol(*dummyArg); 16303ed2909fSPete Steinfeld } 163164ab3302SCarolineConcatto } 163264ab3302SCarolineConcatto if (details.isFunction()) { 163364ab3302SCarolineConcatto DoSymbol(details.result()); 163464ab3302SCarolineConcatto } 163564ab3302SCarolineConcatto for (const auto &pair : scope_) { 163664ab3302SCarolineConcatto const Symbol &symbol{*pair.second}; 163764ab3302SCarolineConcatto if (const auto *useDetails{symbol.detailsIf<UseDetails>()}) { 1638665d4159SPeter Klausler const Symbol &ultimate{useDetails->symbol().GetUltimate()}; 1639665d4159SPeter Klausler bool needed{useSet_.count(ultimate) > 0}; 1640665d4159SPeter Klausler if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 1641665d4159SPeter Klausler // The generic may not be needed itself, but the specific procedure 1642665d4159SPeter Klausler // &/or derived type that it shadows may be needed. 1643665d4159SPeter Klausler const Symbol *spec{generic->specific()}; 1644665d4159SPeter Klausler const Symbol *dt{generic->derivedType()}; 16458be575e4SPeter Klausler needed = needed || (spec && useSet_.count(spec->GetUltimate()) > 0) || 16468be575e4SPeter Klausler (dt && useSet_.count(dt->GetUltimate()) > 0); 1647b67984d3SPeter Klausler } else if (const auto *subp{ultimate.detailsIf<SubprogramDetails>()}) { 1648b67984d3SPeter Klausler const Symbol *interface { subp->moduleInterface() }; 1649b67984d3SPeter Klausler needed = needed || (interface && useSet_.count(*interface) > 0); 1650665d4159SPeter Klausler } 1651665d4159SPeter Klausler if (needed) { 165264ab3302SCarolineConcatto need_.push_back(symbol); 165364ab3302SCarolineConcatto } 1654b85922cdSEmil Kieri } else if (symbol.has<SubprogramDetails>()) { 1655b85922cdSEmil Kieri // An internal subprogram is needed if it is used as interface 1656b85922cdSEmil Kieri // for a dummy or return value procedure. 1657b85922cdSEmil Kieri bool needed{false}; 1658b85922cdSEmil Kieri const auto hasInterface{[&symbol](const Symbol *s) -> bool { 1659b85922cdSEmil Kieri // Is 's' a procedure with interface 'symbol'? 1660b85922cdSEmil Kieri if (s) { 1661b85922cdSEmil Kieri if (const auto *sDetails{s->detailsIf<ProcEntityDetails>()}) { 1662635656f4SPeter Klausler if (sDetails->procInterface() == &symbol) { 1663b85922cdSEmil Kieri return true; 1664b85922cdSEmil Kieri } 1665b85922cdSEmil Kieri } 1666b85922cdSEmil Kieri } 1667b85922cdSEmil Kieri return false; 1668b85922cdSEmil Kieri }}; 1669b85922cdSEmil Kieri for (const Symbol *dummyArg : details.dummyArgs()) { 1670b85922cdSEmil Kieri needed = needed || hasInterface(dummyArg); 1671b85922cdSEmil Kieri } 1672b85922cdSEmil Kieri needed = 1673b85922cdSEmil Kieri needed || (details.isFunction() && hasInterface(&details.result())); 1674b85922cdSEmil Kieri if (needed && needSet_.insert(symbol).second) { 1675b85922cdSEmil Kieri need_.push_back(symbol); 1676b85922cdSEmil Kieri } 167764ab3302SCarolineConcatto } 167864ab3302SCarolineConcatto } 167964ab3302SCarolineConcatto } 168064ab3302SCarolineConcatto 168164ab3302SCarolineConcatto void SubprogramSymbolCollector::DoSymbol(const Symbol &symbol) { 168264ab3302SCarolineConcatto DoSymbol(symbol.name(), symbol); 168364ab3302SCarolineConcatto } 168464ab3302SCarolineConcatto 168564ab3302SCarolineConcatto // Do symbols this one depends on; then add to need_ 168664ab3302SCarolineConcatto void SubprogramSymbolCollector::DoSymbol( 168764ab3302SCarolineConcatto const SourceName &name, const Symbol &symbol) { 168864ab3302SCarolineConcatto const auto &scope{symbol.owner()}; 168964ab3302SCarolineConcatto if (scope != scope_ && !scope.IsDerivedType()) { 169064ab3302SCarolineConcatto if (scope != scope_.parent()) { 169164ab3302SCarolineConcatto useSet_.insert(symbol); 169264ab3302SCarolineConcatto } 169364ab3302SCarolineConcatto if (NeedImport(name, symbol)) { 169464ab3302SCarolineConcatto imports_.insert(name); 169564ab3302SCarolineConcatto } 169664ab3302SCarolineConcatto return; 169764ab3302SCarolineConcatto } 169864ab3302SCarolineConcatto if (!needSet_.insert(symbol).second) { 169964ab3302SCarolineConcatto return; // already done 170064ab3302SCarolineConcatto } 1701cd03e96fSPeter Klausler common::visit(common::visitors{ 170264ab3302SCarolineConcatto [this](const ObjectEntityDetails &details) { 170364ab3302SCarolineConcatto for (const ShapeSpec &spec : details.shape()) { 170464ab3302SCarolineConcatto DoBound(spec.lbound()); 170564ab3302SCarolineConcatto DoBound(spec.ubound()); 170664ab3302SCarolineConcatto } 170764ab3302SCarolineConcatto for (const ShapeSpec &spec : details.coshape()) { 170864ab3302SCarolineConcatto DoBound(spec.lbound()); 170964ab3302SCarolineConcatto DoBound(spec.ubound()); 171064ab3302SCarolineConcatto } 171164ab3302SCarolineConcatto if (const Symbol * commonBlock{details.commonBlock()}) { 171264ab3302SCarolineConcatto DoSymbol(*commonBlock); 171364ab3302SCarolineConcatto } 171464ab3302SCarolineConcatto }, 171564ab3302SCarolineConcatto [this](const CommonBlockDetails &details) { 1716d5c05cedSTim Keith for (const auto &object : details.objects()) { 1717d5c05cedSTim Keith DoSymbol(*object); 171864ab3302SCarolineConcatto } 171964ab3302SCarolineConcatto }, 1720df3e5f18SPeter Klausler [this](const ProcEntityDetails &details) { 172183ca78deSPeter Klausler if (details.rawProcInterface()) { 172283ca78deSPeter Klausler DoSymbol(*details.rawProcInterface()); 1723635656f4SPeter Klausler } else { 1724635656f4SPeter Klausler DoType(details.type()); 1725df3e5f18SPeter Klausler } 1726df3e5f18SPeter Klausler }, 1727d0708e62SPeter Klausler [this](const ProcBindingDetails &details) { 1728d0708e62SPeter Klausler DoSymbol(details.symbol()); 1729d0708e62SPeter Klausler }, 173064ab3302SCarolineConcatto [](const auto &) {}, 173164ab3302SCarolineConcatto }, 173264ab3302SCarolineConcatto symbol.details()); 173364ab3302SCarolineConcatto if (!symbol.has<UseDetails>()) { 173464ab3302SCarolineConcatto DoType(symbol.GetType()); 173564ab3302SCarolineConcatto } 173664ab3302SCarolineConcatto if (!scope.IsDerivedType()) { 173764ab3302SCarolineConcatto need_.push_back(symbol); 173864ab3302SCarolineConcatto } 173964ab3302SCarolineConcatto } 174064ab3302SCarolineConcatto 174164ab3302SCarolineConcatto void SubprogramSymbolCollector::DoType(const DeclTypeSpec *type) { 174264ab3302SCarolineConcatto if (!type) { 174364ab3302SCarolineConcatto return; 174464ab3302SCarolineConcatto } 174564ab3302SCarolineConcatto switch (type->category()) { 174664ab3302SCarolineConcatto case DeclTypeSpec::Numeric: 17471f879005STim Keith case DeclTypeSpec::Logical: 17481f879005STim Keith break; // nothing to do 174964ab3302SCarolineConcatto case DeclTypeSpec::Character: 175064ab3302SCarolineConcatto DoParamValue(type->characterTypeSpec().length()); 175164ab3302SCarolineConcatto break; 175264ab3302SCarolineConcatto default: 175364ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type->AsDerived()}) { 175464ab3302SCarolineConcatto const auto &typeSymbol{derived->typeSymbol()}; 175564ab3302SCarolineConcatto for (const auto &pair : derived->parameters()) { 175664ab3302SCarolineConcatto DoParamValue(pair.second); 175764ab3302SCarolineConcatto } 1758d0708e62SPeter Klausler // The components of the type (including its parent component, if 1759d0708e62SPeter Klausler // any) matter to IMPORT symbol collection only for derived types 1760d0708e62SPeter Klausler // defined in the subprogram. 1761d0708e62SPeter Klausler if (typeSymbol.owner() == scope_) { 1762d0708e62SPeter Klausler if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) { 1763d0708e62SPeter Klausler DoSymbol(extends->name(), extends->typeSymbol()); 176464ab3302SCarolineConcatto } 1765d0708e62SPeter Klausler for (const auto &pair : *typeSymbol.scope()) { 1766d0708e62SPeter Klausler DoSymbol(*pair.second); 1767d0708e62SPeter Klausler } 1768d0708e62SPeter Klausler } 1769d0708e62SPeter Klausler DoSymbol(derived->name(), typeSymbol); 177064ab3302SCarolineConcatto } 177164ab3302SCarolineConcatto } 177264ab3302SCarolineConcatto } 177364ab3302SCarolineConcatto 177464ab3302SCarolineConcatto void SubprogramSymbolCollector::DoBound(const Bound &bound) { 177564ab3302SCarolineConcatto if (const MaybeSubscriptIntExpr & expr{bound.GetExplicit()}) { 177664ab3302SCarolineConcatto DoExpr(*expr); 177764ab3302SCarolineConcatto } 177864ab3302SCarolineConcatto } 177964ab3302SCarolineConcatto void SubprogramSymbolCollector::DoParamValue(const ParamValue ¶mValue) { 178064ab3302SCarolineConcatto if (const auto &expr{paramValue.GetExplicit()}) { 178164ab3302SCarolineConcatto DoExpr(*expr); 178264ab3302SCarolineConcatto } 178364ab3302SCarolineConcatto } 178464ab3302SCarolineConcatto 178564ab3302SCarolineConcatto // Do we need a IMPORT of this symbol into an interface block? 178664ab3302SCarolineConcatto bool SubprogramSymbolCollector::NeedImport( 178764ab3302SCarolineConcatto const SourceName &name, const Symbol &symbol) { 178864ab3302SCarolineConcatto if (!isInterface_) { 178964ab3302SCarolineConcatto return false; 17909e855a6cSPeter Klausler } else if (IsSeparateModuleProcedureInterface(&symbol_)) { 17919e855a6cSPeter Klausler return false; // IMPORT needed only for external and dummy procedure 17929e855a6cSPeter Klausler // interfaces 1793df3e5f18SPeter Klausler } else if (&symbol == scope_.symbol()) { 1794df3e5f18SPeter Klausler return false; 17954864d9f7Speter klausler } else if (symbol.owner().Contains(scope_)) { 179664ab3302SCarolineConcatto return true; 17974864d9f7Speter klausler } else if (const Symbol *found{scope_.FindSymbol(name)}) { 17984864d9f7Speter klausler // detect import from ancestor of use-associated symbol 17994864d9f7Speter klausler return found->has<UseDetails>() && found->owner() != scope_; 18004864d9f7Speter klausler } else { 1801d0708e62SPeter Klausler // "found" can be null in the case of a use-associated derived type's 1802*f5ddb101SPeter Klausler // parent type, and also in the case of an object (like a dummy argument) 1803*f5ddb101SPeter Klausler // used to define a length or bound of a nested interface. 18044864d9f7Speter klausler return false; 180564ab3302SCarolineConcatto } 180664ab3302SCarolineConcatto } 180764ab3302SCarolineConcatto 18081f879005STim Keith } // namespace Fortran::semantics 1809