CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1 | //===-- lib/Semantics/mod-file.cpp ----------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "mod-file.h" |
| 10 | #include "resolve-names.h" |
Tim Keith | 3780d3e | 2020-07-13 19:19:17 | [diff] [blame] | 11 | #include "flang/Common/restorer.h" |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 12 | #include "flang/Evaluate/tools.h" |
| 13 | #include "flang/Parser/message.h" |
| 14 | #include "flang/Parser/parsing.h" |
Peter Klausler | 9e7eef9 | 2022-04-13 17:39:16 | [diff] [blame] | 15 | #include "flang/Parser/unparse.h" |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 16 | #include "flang/Semantics/scope.h" |
| 17 | #include "flang/Semantics/semantics.h" |
| 18 | #include "flang/Semantics/symbol.h" |
| 19 | #include "flang/Semantics/tools.h" |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 20 | #include "llvm/Support/FileSystem.h" |
| 21 | #include "llvm/Support/MemoryBuffer.h" |
| 22 | #include "llvm/Support/raw_ostream.h" |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 23 | #include <algorithm> |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 24 | #include <fstream> |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 25 | #include <set> |
| 26 | #include <string_view> |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 27 | #include <vector> |
| 28 | |
| 29 | namespace Fortran::semantics { |
| 30 | |
| 31 | using namespace parser::literals; |
| 32 | |
| 33 | // The first line of a file that identifies it as a .mod file. |
| 34 | // The first three bytes are a Unicode byte order mark that ensures |
| 35 | // that the module file is decoded as UTF-8 even if source files |
| 36 | // are using another encoding. |
| 37 | struct ModHeader { |
| 38 | static constexpr const char bom[3 + 1]{"\xef\xbb\xbf"}; |
| 39 | static constexpr int magicLen{13}; |
| 40 | static constexpr int sumLen{16}; |
| 41 | static constexpr const char magic[magicLen + 1]{"!mod$ v1 sum:"}; |
| 42 | static constexpr char terminator{'\n'}; |
| 43 | static constexpr int len{magicLen + 1 + sumLen}; |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 44 | static constexpr int needLen{7}; |
| 45 | static constexpr const char need[needLen + 1]{"!need$ "}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 46 | }; |
| 47 | |
| 48 | static std::optional<SourceName> GetSubmoduleParent(const parser::Program &); |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 49 | static void CollectSymbols(const Scope &, SymbolVector &, SymbolVector &, |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 50 | std::map<const Symbol *, SourceName> &, UnorderedSymbolSet &); |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 51 | static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &); |
Peter Klausler | 9e7eef9 | 2022-04-13 17:39:16 | [diff] [blame] | 52 | static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &, |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 53 | const parser::Expr *, const std::map<const Symbol *, SourceName> &); |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 54 | static void PutInit(llvm::raw_ostream &, const MaybeIntExpr &); |
| 55 | static void PutBound(llvm::raw_ostream &, const Bound &); |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 56 | static void PutShapeSpec(llvm::raw_ostream &, const ShapeSpec &); |
| 57 | static void PutShape( |
| 58 | llvm::raw_ostream &, const ArraySpec &, char open, char close); |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 59 | |
| 60 | static llvm::raw_ostream &PutAttr(llvm::raw_ostream &, Attr); |
| 61 | static llvm::raw_ostream &PutType(llvm::raw_ostream &, const DeclTypeSpec &); |
Peter Klausler | bcba39a5 | 2022-11-11 01:29:29 | [diff] [blame] | 62 | static llvm::raw_ostream &PutLower(llvm::raw_ostream &, std::string_view); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 63 | static std::error_code WriteFile(const std::string &, const std::string &, |
| 64 | ModuleCheckSumType &, bool debug = true); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 65 | static bool FileContentsMatch( |
| 66 | const std::string &, const std::string &, const std::string &); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 67 | static ModuleCheckSumType ComputeCheckSum(const std::string_view &); |
| 68 | static std::string CheckSumString(ModuleCheckSumType); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 69 | |
| 70 | // Collect symbols needed for a subprogram interface |
| 71 | class SubprogramSymbolCollector { |
| 72 | public: |
peter klausler | c42f631 | 2020-03-19 23:31:10 | [diff] [blame] | 73 | SubprogramSymbolCollector(const Symbol &symbol, const Scope &scope) |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 74 | : symbol_{symbol}, scope_{scope} {} |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 75 | const SymbolVector &symbols() const { return need_; } |
| 76 | const std::set<SourceName> &imports() const { return imports_; } |
| 77 | void Collect(); |
| 78 | |
| 79 | private: |
| 80 | const Symbol &symbol_; |
| 81 | const Scope &scope_; |
| 82 | bool isInterface_{false}; |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 83 | SymbolVector need_; // symbols that are needed |
peter klausler | 0d8331c | 2021-03-18 17:26:23 | [diff] [blame] | 84 | UnorderedSymbolSet needSet_; // symbols already in need_ |
| 85 | UnorderedSymbolSet useSet_; // use-associations that might be needed |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 86 | std::set<SourceName> imports_; // imports from host that are needed |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 87 | |
| 88 | void DoSymbol(const Symbol &); |
| 89 | void DoSymbol(const SourceName &, const Symbol &); |
| 90 | void DoType(const DeclTypeSpec *); |
| 91 | void DoBound(const Bound &); |
| 92 | void DoParamValue(const ParamValue &); |
| 93 | bool NeedImport(const SourceName &, const Symbol &); |
| 94 | |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 95 | template <typename T> void DoExpr(evaluate::Expr<T> expr) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 96 | for (const Symbol &symbol : evaluate::CollectSymbols(expr)) { |
| 97 | DoSymbol(symbol); |
| 98 | } |
| 99 | } |
| 100 | }; |
| 101 | |
| 102 | bool ModFileWriter::WriteAll() { |
Tim Keith | 3780d3e | 2020-07-13 19:19:17 | [diff] [blame] | 103 | // this flag affects character literals: force it to be consistent |
| 104 | auto restorer{ |
| 105 | common::ScopedSet(parser::useHexadecimalEscapeSequences, false)}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 106 | WriteAll(context_.globalScope()); |
| 107 | return !context_.AnyFatalError(); |
| 108 | } |
| 109 | |
| 110 | void ModFileWriter::WriteAll(const Scope &scope) { |
| 111 | for (const auto &child : scope.children()) { |
| 112 | WriteOne(child); |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | void ModFileWriter::WriteOne(const Scope &scope) { |
| 117 | if (scope.kind() == Scope::Kind::Module) { |
| 118 | auto *symbol{scope.symbol()}; |
| 119 | if (!symbol->test(Symbol::Flag::ModFile)) { |
| 120 | Write(*symbol); |
| 121 | } |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 122 | WriteAll(scope); // write out submodules |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 123 | } |
| 124 | } |
| 125 | |
| 126 | // Construct the name of a module file. Non-empty ancestorName means submodule. |
| 127 | static std::string ModFileName(const SourceName &name, |
| 128 | const std::string &ancestorName, const std::string &suffix) { |
| 129 | std::string result{name.ToString() + suffix}; |
| 130 | return ancestorName.empty() ? result : ancestorName + '-' + result; |
| 131 | } |
| 132 | |
| 133 | // Write the module file for symbol, which must be a module or submodule. |
| 134 | void ModFileWriter::Write(const Symbol &symbol) { |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 135 | auto &module{symbol.get<ModuleDetails>()}; |
| 136 | if (module.moduleFileHash()) { |
| 137 | return; // already written |
| 138 | } |
| 139 | auto *ancestor{module.ancestor()}; |
Peter Klausler | 4b7428e | 2022-11-17 21:34:40 | [diff] [blame] | 140 | isSubmodule_ = ancestor != nullptr; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 141 | auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s}; |
| 142 | auto path{context_.moduleDirectory() + '/' + |
| 143 | ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())}; |
| 144 | PutSymbols(DEREF(symbol.scope())); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 145 | ModuleCheckSumType checkSum; |
| 146 | if (std::error_code error{WriteFile( |
| 147 | path, GetAsString(symbol), checkSum, context_.debugModuleWriter())}) { |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 148 | context_.Say( |
| 149 | symbol.name(), "Error writing %s: %s"_err_en_US, path, error.message()); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 150 | } |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 151 | const_cast<ModuleDetails &>(module).set_moduleFileHash(checkSum); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | // Return the entire body of the module file |
| 155 | // and clear saved uses, decls, and contains. |
| 156 | std::string ModFileWriter::GetAsString(const Symbol &symbol) { |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 157 | std::string buf; |
| 158 | llvm::raw_string_ostream all{buf}; |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 159 | all << needs_.str(); |
| 160 | needs_.str().clear(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 161 | auto &details{symbol.get<ModuleDetails>()}; |
| 162 | if (!details.isSubmodule()) { |
| 163 | all << "module " << symbol.name(); |
| 164 | } else { |
| 165 | auto *parent{details.parent()->symbol()}; |
| 166 | auto *ancestor{details.ancestor()->symbol()}; |
| 167 | all << "submodule(" << ancestor->name(); |
| 168 | if (parent != ancestor) { |
| 169 | all << ':' << parent->name(); |
| 170 | } |
| 171 | all << ") " << symbol.name(); |
| 172 | } |
| 173 | all << '\n' << uses_.str(); |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 174 | uses_.str().clear(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 175 | all << useExtraAttrs_.str(); |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 176 | useExtraAttrs_.str().clear(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 177 | all << decls_.str(); |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 178 | decls_.str().clear(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 179 | auto str{contains_.str()}; |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 180 | contains_.str().clear(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 181 | if (!str.empty()) { |
| 182 | all << "contains\n" << str; |
| 183 | } |
| 184 | all << "end\n"; |
| 185 | return all.str(); |
| 186 | } |
| 187 | |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 188 | // Collect symbols from initializations that are being referenced directly |
| 189 | // from other modules; they may require new USE associations. |
| 190 | static void HarvestInitializerSymbols( |
| 191 | SourceOrderedSymbolSet &set, const Scope &scope) { |
| 192 | for (const auto &[_, symbol] : scope) { |
| 193 | if (symbol->has<DerivedTypeDetails>()) { |
| 194 | if (symbol->scope()) { |
| 195 | HarvestInitializerSymbols(set, *symbol->scope()); |
| 196 | } |
Peter Klausler | 7f54266 | 2024-01-25 22:53:52 | [diff] [blame] | 197 | } else if (const auto &generic{symbol->detailsIf<GenericDetails>()}; |
| 198 | generic && generic->derivedType()) { |
| 199 | const Symbol &dtSym{*generic->derivedType()}; |
Peter Klausler | 37180ed | 2024-01-29 22:36:37 | [diff] [blame] | 200 | if (dtSym.has<DerivedTypeDetails>()) { |
| 201 | if (dtSym.scope()) { |
| 202 | HarvestInitializerSymbols(set, *dtSym.scope()); |
| 203 | } |
| 204 | } else { |
| 205 | CHECK(dtSym.has<UseErrorDetails>()); |
Peter Klausler | 7f54266 | 2024-01-25 22:53:52 | [diff] [blame] | 206 | } |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 207 | } else if (IsNamedConstant(*symbol) || scope.IsDerivedType()) { |
| 208 | if (const auto *object{symbol->detailsIf<ObjectEntityDetails>()}) { |
| 209 | if (object->init()) { |
| 210 | for (SymbolRef ref : evaluate::CollectSymbols(*object->init())) { |
| 211 | set.emplace(*ref); |
| 212 | } |
| 213 | } |
| 214 | } else if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) { |
| 215 | if (proc->init() && *proc->init()) { |
| 216 | set.emplace(**proc->init()); |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | void ModFileWriter::PrepareRenamings(const Scope &scope) { |
| 224 | SourceOrderedSymbolSet symbolsInInits; |
| 225 | HarvestInitializerSymbols(symbolsInInits, scope); |
| 226 | for (SymbolRef s : symbolsInInits) { |
| 227 | const Scope *sMod{FindModuleContaining(s->owner())}; |
| 228 | if (!sMod) { |
| 229 | continue; |
| 230 | } |
| 231 | SourceName rename{s->name()}; |
| 232 | if (const Symbol * found{scope.FindSymbol(s->name())}) { |
| 233 | if (found == &*s) { |
| 234 | continue; // available in scope |
| 235 | } |
| 236 | if (const auto *generic{found->detailsIf<GenericDetails>()}) { |
| 237 | if (generic->derivedType() == &*s || generic->specific() == &*s) { |
| 238 | continue; |
| 239 | } |
| 240 | } else if (found->has<UseDetails>()) { |
| 241 | if (&found->GetUltimate() == &*s) { |
| 242 | continue; // already use-associated with same name |
| 243 | } |
| 244 | } |
| 245 | if (&s->owner() != &found->owner()) { // Symbol needs renaming |
| 246 | rename = scope.context().SaveTempName( |
| 247 | DEREF(sMod->symbol()).name().ToString() + "$" + |
| 248 | s->name().ToString()); |
| 249 | } |
| 250 | } |
| 251 | // Symbol is used in this scope but not visible under its name |
| 252 | if (sMod->parent().IsIntrinsicModules()) { |
| 253 | uses_ << "use,intrinsic::"; |
| 254 | } else { |
| 255 | uses_ << "use "; |
| 256 | } |
| 257 | uses_ << DEREF(sMod->symbol()).name() << ",only:"; |
| 258 | if (rename != s->name()) { |
| 259 | uses_ << rename << "=>"; |
| 260 | } |
| 261 | uses_ << s->name() << '\n'; |
| 262 | useExtraAttrs_ << "private::" << rename << '\n'; |
| 263 | renamings_.emplace(&*s, rename); |
| 264 | } |
| 265 | } |
| 266 | |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 267 | // Put out the visible symbols from scope. |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 268 | void ModFileWriter::PutSymbols(const Scope &scope) { |
Tim Keith | 86f59de | 2020-12-02 23:13:49 | [diff] [blame] | 269 | SymbolVector sorted; |
| 270 | SymbolVector uses; |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 271 | PrepareRenamings(scope); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 272 | UnorderedSymbolSet modules; |
| 273 | CollectSymbols(scope, sorted, uses, renamings_, modules); |
| 274 | // Write module files for dependencies first so that their |
| 275 | // hashes are known. |
| 276 | for (auto ref : modules) { |
| 277 | Write(*ref); |
| 278 | needs_ << ModHeader::need |
| 279 | << CheckSumString(ref->get<ModuleDetails>().moduleFileHash().value()) |
| 280 | << (ref->owner().IsIntrinsicModules() ? " i " : " n ") |
| 281 | << ref->name().ToString() << '\n'; |
| 282 | } |
Tim Keith | 86f59de | 2020-12-02 23:13:49 | [diff] [blame] | 283 | std::string buf; // stuff after CONTAINS in derived type |
| 284 | llvm::raw_string_ostream typeBindings{buf}; |
| 285 | for (const Symbol &symbol : sorted) { |
peter klausler | d60a022 | 2021-08-10 17:22:39 | [diff] [blame] | 286 | if (!symbol.test(Symbol::Flag::CompilerCreated)) { |
| 287 | PutSymbol(typeBindings, symbol); |
| 288 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 289 | } |
Tim Keith | 86f59de | 2020-12-02 23:13:49 | [diff] [blame] | 290 | for (const Symbol &symbol : uses) { |
| 291 | PutUse(symbol); |
| 292 | } |
peter klausler | d60a022 | 2021-08-10 17:22:39 | [diff] [blame] | 293 | for (const auto &set : scope.equivalenceSets()) { |
| 294 | if (!set.empty() && |
| 295 | !set.front().symbol.test(Symbol::Flag::CompilerCreated)) { |
| 296 | char punctuation{'('}; |
| 297 | decls_ << "equivalence"; |
| 298 | for (const auto &object : set) { |
| 299 | decls_ << punctuation << object.AsFortran(); |
| 300 | punctuation = ','; |
| 301 | } |
| 302 | decls_ << ")\n"; |
| 303 | } |
| 304 | } |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 305 | CHECK(typeBindings.str().empty()); |
| 306 | } |
| 307 | |
| 308 | // Emit components in order |
| 309 | bool ModFileWriter::PutComponents(const Symbol &typeSymbol) { |
| 310 | const auto &scope{DEREF(typeSymbol.scope())}; |
| 311 | std::string buf; // stuff after CONTAINS in derived type |
| 312 | llvm::raw_string_ostream typeBindings{buf}; |
| 313 | UnorderedSymbolSet emitted; |
| 314 | SymbolVector symbols{scope.GetSymbols()}; |
| 315 | // Emit type parameters first |
| 316 | for (const Symbol &symbol : symbols) { |
| 317 | if (symbol.has<TypeParamDetails>()) { |
| 318 | PutSymbol(typeBindings, symbol); |
| 319 | emitted.emplace(symbol); |
| 320 | } |
| 321 | } |
| 322 | // Emit components in component order. |
| 323 | const auto &details{typeSymbol.get<DerivedTypeDetails>()}; |
| 324 | for (SourceName name : details.componentNames()) { |
| 325 | auto iter{scope.find(name)}; |
| 326 | if (iter != scope.end()) { |
| 327 | const Symbol &component{*iter->second}; |
| 328 | if (!component.test(Symbol::Flag::ParentComp)) { |
| 329 | PutSymbol(typeBindings, component); |
| 330 | } |
| 331 | emitted.emplace(component); |
| 332 | } |
| 333 | } |
| 334 | // Emit remaining symbols from the type's scope |
| 335 | for (const Symbol &symbol : symbols) { |
| 336 | if (emitted.find(symbol) == emitted.end()) { |
| 337 | PutSymbol(typeBindings, symbol); |
| 338 | } |
| 339 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 340 | if (auto str{typeBindings.str()}; !str.empty()) { |
| 341 | CHECK(scope.IsDerivedType()); |
| 342 | decls_ << "contains\n" << str; |
peter klausler | 37b2e2b | 2020-09-30 20:34:23 | [diff] [blame] | 343 | return true; |
| 344 | } else { |
| 345 | return false; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 346 | } |
| 347 | } |
| 348 | |
Slava Zakharin | 1db42fa | 2023-09-25 16:35:43 | [diff] [blame] | 349 | // Return the symbol's attributes that should be written |
| 350 | // into the mod file. |
| 351 | static Attrs getSymbolAttrsToWrite(const Symbol &symbol) { |
| 352 | // Is SAVE attribute is implicit, it should be omitted |
| 353 | // to not violate F202x C862 for a common block member. |
| 354 | return symbol.attrs() & ~(symbol.implicitAttrs() & Attrs{Attr::SAVE}); |
| 355 | } |
| 356 | |
peter klausler | 4864d9f | 2021-01-13 22:12:23 | [diff] [blame] | 357 | static llvm::raw_ostream &PutGenericName( |
| 358 | llvm::raw_ostream &os, const Symbol &symbol) { |
| 359 | if (IsGenericDefinedOp(symbol)) { |
| 360 | return os << "operator(" << symbol.name() << ')'; |
| 361 | } else { |
| 362 | return os << symbol.name(); |
| 363 | } |
| 364 | } |
| 365 | |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 366 | // Emit a symbol to decls_, except for bindings in a derived type (type-bound |
| 367 | // procedures, type-bound generics, final procedures) which go to typeBindings. |
| 368 | void ModFileWriter::PutSymbol( |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 369 | llvm::raw_ostream &typeBindings, const Symbol &symbol) { |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 370 | common::visit( |
| 371 | common::visitors{ |
| 372 | [&](const ModuleDetails &) { /* should be current module */ }, |
| 373 | [&](const DerivedTypeDetails &) { PutDerivedType(symbol); }, |
| 374 | [&](const SubprogramDetails &) { PutSubprogram(symbol); }, |
| 375 | [&](const GenericDetails &x) { |
| 376 | if (symbol.owner().IsDerivedType()) { |
| 377 | // generic binding |
| 378 | for (const Symbol &proc : x.specificProcs()) { |
| 379 | PutGenericName(typeBindings << "generic::", symbol) |
| 380 | << "=>" << proc.name() << '\n'; |
| 381 | } |
| 382 | } else { |
| 383 | PutGeneric(symbol); |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 384 | } |
| 385 | }, |
| 386 | [&](const UseDetails &) { PutUse(symbol); }, |
| 387 | [](const UseErrorDetails &) {}, |
| 388 | [&](const ProcBindingDetails &x) { |
| 389 | bool deferred{symbol.attrs().test(Attr::DEFERRED)}; |
| 390 | typeBindings << "procedure"; |
| 391 | if (deferred) { |
| 392 | typeBindings << '(' << x.symbol().name() << ')'; |
| 393 | } |
| 394 | PutPassName(typeBindings, x.passName()); |
| 395 | auto attrs{symbol.attrs()}; |
| 396 | if (x.passName()) { |
| 397 | attrs.reset(Attr::PASS); |
| 398 | } |
| 399 | PutAttrs(typeBindings, attrs); |
| 400 | typeBindings << "::" << symbol.name(); |
| 401 | if (!deferred && x.symbol().name() != symbol.name()) { |
| 402 | typeBindings << "=>" << x.symbol().name(); |
| 403 | } |
| 404 | typeBindings << '\n'; |
| 405 | }, |
| 406 | [&](const NamelistDetails &x) { |
| 407 | decls_ << "namelist/" << symbol.name(); |
| 408 | char sep{'/'}; |
| 409 | for (const Symbol &object : x.objects()) { |
| 410 | decls_ << sep << object.name(); |
| 411 | sep = ','; |
| 412 | } |
| 413 | decls_ << '\n'; |
Peter Klausler | 4b7428e | 2022-11-17 21:34:40 | [diff] [blame] | 414 | if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { |
| 415 | decls_ << "private::" << symbol.name() << '\n'; |
| 416 | } |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 417 | }, |
| 418 | [&](const CommonBlockDetails &x) { |
| 419 | decls_ << "common/" << symbol.name(); |
| 420 | char sep = '/'; |
| 421 | for (const auto &object : x.objects()) { |
| 422 | decls_ << sep << object->name(); |
| 423 | sep = ','; |
| 424 | } |
| 425 | decls_ << '\n'; |
| 426 | if (symbol.attrs().test(Attr::BIND_C)) { |
Slava Zakharin | 1db42fa | 2023-09-25 16:35:43 | [diff] [blame] | 427 | PutAttrs(decls_, getSymbolAttrsToWrite(symbol), x.bindName(), |
Peter Klausler | 69e2665 | 2023-02-28 19:58:30 | [diff] [blame] | 428 | x.isExplicitBindName(), ""s); |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 429 | decls_ << "::/" << symbol.name() << "/\n"; |
| 430 | } |
| 431 | }, |
| 432 | [](const HostAssocDetails &) {}, |
| 433 | [](const MiscDetails &) {}, |
| 434 | [&](const auto &) { |
| 435 | PutEntity(decls_, symbol); |
Valentin Clement | 22f63b5 | 2023-08-04 21:01:45 | [diff] [blame] | 436 | PutDirective(decls_, symbol); |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 437 | }, |
| 438 | }, |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 439 | symbol.details()); |
| 440 | } |
| 441 | |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 442 | void ModFileWriter::PutDerivedType( |
| 443 | const Symbol &typeSymbol, const Scope *scope) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 444 | auto &details{typeSymbol.get<DerivedTypeDetails>()}; |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 445 | if (details.isDECStructure()) { |
| 446 | PutDECStructure(typeSymbol, scope); |
| 447 | return; |
| 448 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 449 | PutAttrs(decls_ << "type", typeSymbol.attrs()); |
| 450 | if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) { |
| 451 | decls_ << ",extends(" << extends->name() << ')'; |
| 452 | } |
| 453 | decls_ << "::" << typeSymbol.name(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 454 | if (!details.paramNames().empty()) { |
| 455 | char sep{'('}; |
| 456 | for (const auto &name : details.paramNames()) { |
| 457 | decls_ << sep << name; |
| 458 | sep = ','; |
| 459 | } |
| 460 | decls_ << ')'; |
| 461 | } |
| 462 | decls_ << '\n'; |
| 463 | if (details.sequence()) { |
| 464 | decls_ << "sequence\n"; |
| 465 | } |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 466 | bool contains{PutComponents(typeSymbol)}; |
peter klausler | 37b2e2b | 2020-09-30 20:34:23 | [diff] [blame] | 467 | if (!details.finals().empty()) { |
| 468 | const char *sep{contains ? "final::" : "contains\nfinal::"}; |
| 469 | for (const auto &pair : details.finals()) { |
| 470 | decls_ << sep << pair.second->name(); |
| 471 | sep = ","; |
| 472 | } |
| 473 | if (*sep == ',') { |
| 474 | decls_ << '\n'; |
| 475 | } |
| 476 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 477 | decls_ << "end type\n"; |
| 478 | } |
| 479 | |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 480 | void ModFileWriter::PutDECStructure( |
| 481 | const Symbol &typeSymbol, const Scope *scope) { |
| 482 | if (emittedDECStructures_.find(typeSymbol) != emittedDECStructures_.end()) { |
| 483 | return; |
| 484 | } |
| 485 | if (!scope && context_.IsTempName(typeSymbol.name().ToString())) { |
| 486 | return; // defer until used |
| 487 | } |
| 488 | emittedDECStructures_.insert(typeSymbol); |
| 489 | decls_ << "structure "; |
| 490 | if (!context_.IsTempName(typeSymbol.name().ToString())) { |
| 491 | decls_ << typeSymbol.name(); |
| 492 | } |
| 493 | if (scope && scope->kind() == Scope::Kind::DerivedType) { |
| 494 | // Nested STRUCTURE: emit entity declarations right now |
| 495 | // on the STRUCTURE statement. |
| 496 | bool any{false}; |
| 497 | for (const auto &ref : scope->GetSymbols()) { |
| 498 | const auto *object{ref->detailsIf<ObjectEntityDetails>()}; |
| 499 | if (object && object->type() && |
| 500 | object->type()->category() == DeclTypeSpec::TypeDerived && |
| 501 | &object->type()->derivedTypeSpec().typeSymbol() == &typeSymbol) { |
| 502 | if (any) { |
| 503 | decls_ << ','; |
| 504 | } else { |
| 505 | any = true; |
| 506 | } |
| 507 | decls_ << ref->name(); |
| 508 | PutShape(decls_, object->shape(), '(', ')'); |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 509 | PutInit(decls_, *ref, object->init(), nullptr, renamings_); |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 510 | emittedDECFields_.insert(*ref); |
| 511 | } else if (any) { |
| 512 | break; // any later use of this structure will use RECORD/str/ |
| 513 | } |
| 514 | } |
| 515 | } |
| 516 | decls_ << '\n'; |
| 517 | PutComponents(typeSymbol); |
| 518 | decls_ << "end structure\n"; |
| 519 | } |
| 520 | |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 521 | // Attributes that may be in a subprogram prefix |
| 522 | static const Attrs subprogramPrefixAttrs{Attr::ELEMENTAL, Attr::IMPURE, |
| 523 | Attr::MODULE, Attr::NON_RECURSIVE, Attr::PURE, Attr::RECURSIVE}; |
| 524 | |
Valentin Clement | c8ad802 | 2024-01-11 05:26:53 | [diff] [blame] | 525 | static void PutOpenACCDeviceTypeRoutineInfo( |
| 526 | llvm::raw_ostream &os, const OpenACCRoutineDeviceTypeInfo &info) { |
| 527 | if (info.isSeq()) { |
| 528 | os << " seq"; |
| 529 | } |
| 530 | if (info.isGang()) { |
| 531 | os << " gang"; |
| 532 | if (info.gangDim() > 0) { |
| 533 | os << "(dim: " << info.gangDim() << ")"; |
| 534 | } |
| 535 | } |
| 536 | if (info.isVector()) { |
| 537 | os << " vector"; |
| 538 | } |
| 539 | if (info.isWorker()) { |
| 540 | os << " worker"; |
| 541 | } |
| 542 | if (info.bindName()) { |
| 543 | os << " bind(" << *info.bindName() << ")"; |
| 544 | } |
| 545 | } |
| 546 | |
Valentin Clement | 22209a6 | 2023-08-23 15:56:34 | [diff] [blame] | 547 | static void PutOpenACCRoutineInfo( |
| 548 | llvm::raw_ostream &os, const SubprogramDetails &details) { |
| 549 | for (auto info : details.openACCRoutineInfos()) { |
| 550 | os << "!$acc routine"; |
Valentin Clement | c8ad802 | 2024-01-11 05:26:53 | [diff] [blame] | 551 | |
| 552 | PutOpenACCDeviceTypeRoutineInfo(os, info); |
| 553 | |
Valentin Clement | 22209a6 | 2023-08-23 15:56:34 | [diff] [blame] | 554 | if (info.isNohost()) { |
| 555 | os << " nohost"; |
| 556 | } |
Valentin Clement | c8ad802 | 2024-01-11 05:26:53 | [diff] [blame] | 557 | |
| 558 | for (auto dtype : info.deviceTypeInfos()) { |
| 559 | os << " device_type("; |
| 560 | if (dtype.dType() == common::OpenACCDeviceType::Star) { |
| 561 | os << "*"; |
| 562 | } else { |
| 563 | os << parser::ToLowerCaseLetters(common::EnumToString(dtype.dType())); |
| 564 | } |
| 565 | os << ")"; |
| 566 | |
| 567 | PutOpenACCDeviceTypeRoutineInfo(os, dtype); |
Valentin Clement | 22209a6 | 2023-08-23 15:56:34 | [diff] [blame] | 568 | } |
Valentin Clement | c8ad802 | 2024-01-11 05:26:53 | [diff] [blame] | 569 | |
Valentin Clement | 22209a6 | 2023-08-23 15:56:34 | [diff] [blame] | 570 | os << "\n"; |
| 571 | } |
| 572 | } |
| 573 | |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 574 | void ModFileWriter::PutSubprogram(const Symbol &symbol) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 575 | auto &details{symbol.get<SubprogramDetails>()}; |
Peter Klausler | b67984d | 2022-06-09 23:06:23 | [diff] [blame] | 576 | if (const Symbol * interface{details.moduleInterface()}) { |
Peter Klausler | bb7e31b | 2022-12-01 19:41:40 | [diff] [blame] | 577 | const Scope *module{FindModuleContaining(interface->owner())}; |
| 578 | if (module && module != &symbol.owner()) { |
| 579 | // Interface is in ancestor module |
| 580 | } else { |
| 581 | PutSubprogram(*interface); |
| 582 | } |
Peter Klausler | b67984d | 2022-06-09 23:06:23 | [diff] [blame] | 583 | } |
| 584 | auto attrs{symbol.attrs()}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 585 | Attrs bindAttrs{}; |
| 586 | if (attrs.test(Attr::BIND_C)) { |
| 587 | // bind(c) is a suffix, not prefix |
| 588 | bindAttrs.set(Attr::BIND_C, true); |
| 589 | attrs.set(Attr::BIND_C, false); |
| 590 | } |
Tim Keith | d55627d | 2020-12-28 16:50:30 | [diff] [blame] | 591 | bool isAbstract{attrs.test(Attr::ABSTRACT)}; |
| 592 | if (isAbstract) { |
| 593 | attrs.set(Attr::ABSTRACT, false); |
| 594 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 595 | Attrs prefixAttrs{subprogramPrefixAttrs & attrs}; |
| 596 | // emit any non-prefix attributes in an attribute statement |
| 597 | attrs &= ~subprogramPrefixAttrs; |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 598 | std::string ssBuf; |
| 599 | llvm::raw_string_ostream ss{ssBuf}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 600 | PutAttrs(ss, attrs); |
| 601 | if (!ss.str().empty()) { |
| 602 | decls_ << ss.str().substr(1) << "::" << symbol.name() << '\n'; |
| 603 | } |
| 604 | bool isInterface{details.isInterface()}; |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 605 | llvm::raw_ostream &os{isInterface ? decls_ : contains_}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 606 | if (isInterface) { |
Tim Keith | d55627d | 2020-12-28 16:50:30 | [diff] [blame] | 607 | os << (isAbstract ? "abstract " : "") << "interface\n"; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 608 | } |
Peter Klausler | 69e2665 | 2023-02-28 19:58:30 | [diff] [blame] | 609 | PutAttrs(os, prefixAttrs, nullptr, false, ""s, " "s); |
Peter Klausler | 27f7180 | 2023-05-06 22:03:39 | [diff] [blame] | 610 | if (auto attrs{details.cudaSubprogramAttrs()}) { |
| 611 | if (*attrs == common::CUDASubprogramAttrs::HostDevice) { |
| 612 | os << "attributes(host,device) "; |
| 613 | } else { |
| 614 | PutLower(os << "attributes(", common::EnumToString(*attrs)) << ") "; |
| 615 | } |
| 616 | if (!details.cudaLaunchBounds().empty()) { |
| 617 | os << "launch_bounds"; |
| 618 | char sep{'('}; |
| 619 | for (auto x : details.cudaLaunchBounds()) { |
| 620 | os << sep << x; |
| 621 | sep = ','; |
| 622 | } |
| 623 | os << ") "; |
| 624 | } |
| 625 | if (!details.cudaClusterDims().empty()) { |
| 626 | os << "cluster_dims"; |
| 627 | char sep{'('}; |
| 628 | for (auto x : details.cudaClusterDims()) { |
| 629 | os << sep << x; |
| 630 | sep = ','; |
| 631 | } |
| 632 | os << ") "; |
| 633 | } |
| 634 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 635 | os << (details.isFunction() ? "function " : "subroutine "); |
| 636 | os << symbol.name() << '('; |
| 637 | int n = 0; |
| 638 | for (const auto &dummy : details.dummyArgs()) { |
| 639 | if (n++ > 0) { |
| 640 | os << ','; |
| 641 | } |
Pete Steinfeld | 3ed2909 | 2020-06-18 14:05:08 | [diff] [blame] | 642 | if (dummy) { |
| 643 | os << dummy->name(); |
| 644 | } else { |
| 645 | os << "*"; |
| 646 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 647 | } |
| 648 | os << ')'; |
Peter Klausler | 69e2665 | 2023-02-28 19:58:30 | [diff] [blame] | 649 | PutAttrs(os, bindAttrs, details.bindName(), details.isExplicitBindName(), |
| 650 | " "s, ""s); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 651 | if (details.isFunction()) { |
| 652 | const Symbol &result{details.result()}; |
| 653 | if (result.name() != symbol.name()) { |
| 654 | os << " result(" << result.name() << ')'; |
| 655 | } |
| 656 | } |
| 657 | os << '\n'; |
peter klausler | c42f631 | 2020-03-19 23:31:10 | [diff] [blame] | 658 | // walk symbols, collect ones needed for interface |
| 659 | const Scope &scope{ |
| 660 | details.entryScope() ? *details.entryScope() : DEREF(symbol.scope())}; |
| 661 | SubprogramSymbolCollector collector{symbol, scope}; |
| 662 | collector.Collect(); |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 663 | std::string typeBindingsBuf; |
| 664 | llvm::raw_string_ostream typeBindings{typeBindingsBuf}; |
peter klausler | c42f631 | 2020-03-19 23:31:10 | [diff] [blame] | 665 | ModFileWriter writer{context_}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 666 | for (const Symbol &need : collector.symbols()) { |
| 667 | writer.PutSymbol(typeBindings, need); |
| 668 | } |
| 669 | CHECK(typeBindings.str().empty()); |
| 670 | os << writer.uses_.str(); |
| 671 | for (const SourceName &import : collector.imports()) { |
| 672 | decls_ << "import::" << import << "\n"; |
| 673 | } |
| 674 | os << writer.decls_.str(); |
Valentin Clement | 22209a6 | 2023-08-23 15:56:34 | [diff] [blame] | 675 | PutOpenACCRoutineInfo(os, details); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 676 | os << "end\n"; |
| 677 | if (isInterface) { |
| 678 | os << "end interface\n"; |
| 679 | } |
| 680 | } |
| 681 | |
| 682 | static bool IsIntrinsicOp(const Symbol &symbol) { |
| 683 | if (const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()}) { |
| 684 | return details->kind().IsIntrinsicOperator(); |
| 685 | } else { |
| 686 | return false; |
| 687 | } |
| 688 | } |
| 689 | |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 690 | void ModFileWriter::PutGeneric(const Symbol &symbol) { |
Tim Keith | 86f59de | 2020-12-02 23:13:49 | [diff] [blame] | 691 | const auto &genericOwner{symbol.owner()}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 692 | auto &details{symbol.get<GenericDetails>()}; |
| 693 | PutGenericName(decls_ << "interface ", symbol) << '\n'; |
| 694 | for (const Symbol &specific : details.specificProcs()) { |
Tim Keith | 86f59de | 2020-12-02 23:13:49 | [diff] [blame] | 695 | if (specific.owner() == genericOwner) { |
| 696 | decls_ << "procedure::" << specific.name() << '\n'; |
| 697 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 698 | } |
| 699 | decls_ << "end interface\n"; |
Peter Klausler | 4b7428e | 2022-11-17 21:34:40 | [diff] [blame] | 700 | if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 701 | PutGenericName(decls_ << "private::", symbol) << '\n'; |
| 702 | } |
| 703 | } |
| 704 | |
| 705 | void ModFileWriter::PutUse(const Symbol &symbol) { |
| 706 | auto &details{symbol.get<UseDetails>()}; |
| 707 | auto &use{details.symbol()}; |
Peter Klausler | 15faac9 | 2022-05-30 19:47:32 | [diff] [blame] | 708 | const Symbol &module{GetUsedModule(details)}; |
| 709 | if (use.owner().parent().IsIntrinsicModules()) { |
| 710 | uses_ << "use,intrinsic::"; |
| 711 | } else { |
| 712 | uses_ << "use "; |
| 713 | } |
| 714 | uses_ << module.name() << ",only:"; |
| 715 | PutGenericName(uses_, symbol); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 716 | // Can have intrinsic op with different local-name and use-name |
| 717 | // (e.g. `operator(<)` and `operator(.lt.)`) but rename is not allowed |
| 718 | if (!IsIntrinsicOp(symbol) && use.name() != symbol.name()) { |
| 719 | PutGenericName(uses_ << "=>", use); |
| 720 | } |
| 721 | uses_ << '\n'; |
| 722 | PutUseExtraAttr(Attr::VOLATILE, symbol, use); |
| 723 | PutUseExtraAttr(Attr::ASYNCHRONOUS, symbol, use); |
Peter Klausler | 4b7428e | 2022-11-17 21:34:40 | [diff] [blame] | 724 | if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { |
peter klausler | 4864d9f | 2021-01-13 22:12:23 | [diff] [blame] | 725 | PutGenericName(useExtraAttrs_ << "private::", symbol) << '\n'; |
| 726 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 727 | } |
| 728 | |
| 729 | // We have "USE local => use" in this module. If attr was added locally |
| 730 | // (i.e. on local but not on use), also write it out in the mod file. |
| 731 | void ModFileWriter::PutUseExtraAttr( |
| 732 | Attr attr, const Symbol &local, const Symbol &use) { |
| 733 | if (local.attrs().test(attr) && !use.attrs().test(attr)) { |
| 734 | PutAttr(useExtraAttrs_, attr) << "::"; |
| 735 | useExtraAttrs_ << local.name() << '\n'; |
| 736 | } |
| 737 | } |
| 738 | |
peter klausler | 4864d9f | 2021-01-13 22:12:23 | [diff] [blame] | 739 | static inline SourceName NameInModuleFile(const Symbol &symbol) { |
Peter Klausler | a3e9d3c | 2023-08-04 21:37:34 | [diff] [blame] | 740 | if (const auto *use{symbol.detailsIf<UseDetails>()}) { |
peter klausler | 4864d9f | 2021-01-13 22:12:23 | [diff] [blame] | 741 | if (use->symbol().attrs().test(Attr::PRIVATE)) { |
| 742 | // Avoid the use in sorting of names created to access private |
| 743 | // specific procedures as a result of generic resolution; |
| 744 | // they're not in the cooked source. |
| 745 | return use->symbol().name(); |
| 746 | } |
| 747 | } |
| 748 | return symbol.name(); |
| 749 | } |
| 750 | |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 751 | // Collect the symbols of this scope sorted by their original order, not name. |
Peter Klausler | a3e9d3c | 2023-08-04 21:37:34 | [diff] [blame] | 752 | // Generics and namelists are exceptions: they are sorted after other symbols. |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 753 | void CollectSymbols(const Scope &scope, SymbolVector &sorted, |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 754 | SymbolVector &uses, std::map<const Symbol *, SourceName> &renamings, |
| 755 | UnorderedSymbolSet &modules) { |
Peter Klausler | a3e9d3c | 2023-08-04 21:37:34 | [diff] [blame] | 756 | SymbolVector namelist, generics; |
Tim Keith | c353ebb | 2020-04-22 22:39:24 | [diff] [blame] | 757 | auto symbols{scope.GetSymbols()}; |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 758 | std::size_t commonSize{scope.commonBlocks().size()}; |
Tim Keith | c353ebb | 2020-04-22 22:39:24 | [diff] [blame] | 759 | sorted.reserve(symbols.size() + commonSize); |
| 760 | for (SymbolRef symbol : symbols) { |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 761 | const auto *generic{symbol->detailsIf<GenericDetails>()}; |
| 762 | if (generic) { |
| 763 | uses.insert(uses.end(), generic->uses().begin(), generic->uses().end()); |
| 764 | for (auto ref : generic->uses()) { |
| 765 | modules.insert(GetUsedModule(ref->get<UseDetails>())); |
| 766 | } |
| 767 | } else if (const auto *use{symbol->detailsIf<UseDetails>()}) { |
| 768 | modules.insert(GetUsedModule(*use)); |
| 769 | } |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 770 | if (symbol->test(Symbol::Flag::ParentComp)) { |
| 771 | } else if (symbol->has<NamelistDetails>()) { |
| 772 | namelist.push_back(symbol); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 773 | } else if (generic) { |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 774 | if (generic->specific() && |
| 775 | &generic->specific()->owner() == &symbol->owner()) { |
| 776 | sorted.push_back(*generic->specific()); |
| 777 | } else if (generic->derivedType() && |
| 778 | &generic->derivedType()->owner() == &symbol->owner()) { |
| 779 | sorted.push_back(*generic->derivedType()); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 780 | } |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 781 | generics.push_back(symbol); |
| 782 | } else { |
| 783 | sorted.push_back(symbol); |
| 784 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 785 | } |
Tim Keith | d55627d | 2020-12-28 16:50:30 | [diff] [blame] | 786 | // Sort most symbols by name: use of Symbol::ReplaceName ensures the source |
| 787 | // location of a symbol's name is the first "real" use. |
Peter Klausler | a3e9d3c | 2023-08-04 21:37:34 | [diff] [blame] | 788 | auto sorter{[](SymbolRef x, SymbolRef y) { |
| 789 | return NameInModuleFile(*x).begin() < NameInModuleFile(*y).begin(); |
| 790 | }}; |
| 791 | std::sort(sorted.begin(), sorted.end(), sorter); |
| 792 | std::sort(generics.begin(), generics.end(), sorter); |
| 793 | sorted.insert(sorted.end(), generics.begin(), generics.end()); |
Tim Keith | c353ebb | 2020-04-22 22:39:24 | [diff] [blame] | 794 | sorted.insert(sorted.end(), namelist.begin(), namelist.end()); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 795 | for (const auto &pair : scope.commonBlocks()) { |
Tim Keith | c353ebb | 2020-04-22 22:39:24 | [diff] [blame] | 796 | sorted.push_back(*pair.second); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 797 | } |
peter klausler | 0d8331c | 2021-03-18 17:26:23 | [diff] [blame] | 798 | std::sort( |
| 799 | sorted.end() - commonSize, sorted.end(), SymbolSourcePositionCompare{}); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 800 | } |
| 801 | |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 802 | void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol) { |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 803 | common::visit( |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 804 | common::visitors{ |
| 805 | [&](const ObjectEntityDetails &) { PutObjectEntity(os, symbol); }, |
| 806 | [&](const ProcEntityDetails &) { PutProcEntity(os, symbol); }, |
| 807 | [&](const TypeParamDetails &) { PutTypeParam(os, symbol); }, |
| 808 | [&](const auto &) { |
| 809 | common::die("PutEntity: unexpected details: %s", |
| 810 | DetailsToString(symbol.details()).c_str()); |
| 811 | }, |
| 812 | }, |
| 813 | symbol.details()); |
| 814 | } |
| 815 | |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 816 | void PutShapeSpec(llvm::raw_ostream &os, const ShapeSpec &x) { |
Peter Klausler | 44bc97c | 2021-11-26 21:26:50 | [diff] [blame] | 817 | if (x.lbound().isStar()) { |
| 818 | CHECK(x.ubound().isStar()); |
| 819 | os << ".."; // assumed rank |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 820 | } else { |
Peter Klausler | 44bc97c | 2021-11-26 21:26:50 | [diff] [blame] | 821 | if (!x.lbound().isColon()) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 822 | PutBound(os, x.lbound()); |
| 823 | } |
| 824 | os << ':'; |
Peter Klausler | 44bc97c | 2021-11-26 21:26:50 | [diff] [blame] | 825 | if (!x.ubound().isColon()) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 826 | PutBound(os, x.ubound()); |
| 827 | } |
| 828 | } |
| 829 | } |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 830 | void PutShape( |
| 831 | llvm::raw_ostream &os, const ArraySpec &shape, char open, char close) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 832 | if (!shape.empty()) { |
| 833 | os << open; |
| 834 | bool first{true}; |
| 835 | for (const auto &shapeSpec : shape) { |
| 836 | if (first) { |
| 837 | first = false; |
| 838 | } else { |
| 839 | os << ','; |
| 840 | } |
| 841 | PutShapeSpec(os, shapeSpec); |
| 842 | } |
| 843 | os << close; |
| 844 | } |
| 845 | } |
| 846 | |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 847 | void ModFileWriter::PutObjectEntity( |
| 848 | llvm::raw_ostream &os, const Symbol &symbol) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 849 | auto &details{symbol.get<ObjectEntityDetails>()}; |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 850 | if (details.type() && |
| 851 | details.type()->category() == DeclTypeSpec::TypeDerived) { |
| 852 | const Symbol &typeSymbol{details.type()->derivedTypeSpec().typeSymbol()}; |
| 853 | if (typeSymbol.get<DerivedTypeDetails>().isDECStructure()) { |
| 854 | PutDerivedType(typeSymbol, &symbol.owner()); |
| 855 | if (emittedDECFields_.find(symbol) != emittedDECFields_.end()) { |
| 856 | return; // symbol was emitted on STRUCTURE statement |
| 857 | } |
| 858 | } |
| 859 | } |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 860 | PutEntity( |
| 861 | os, symbol, [&]() { PutType(os, DEREF(symbol.GetType())); }, |
Slava Zakharin | 1db42fa | 2023-09-25 16:35:43 | [diff] [blame] | 862 | getSymbolAttrsToWrite(symbol)); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 863 | PutShape(os, details.shape(), '(', ')'); |
| 864 | PutShape(os, details.coshape(), '[', ']'); |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 865 | PutInit(os, symbol, details.init(), details.unanalyzedPDTComponentInit(), |
| 866 | renamings_); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 867 | os << '\n'; |
Peter Klausler | 864cb2a | 2023-04-10 18:05:03 | [diff] [blame] | 868 | if (auto tkr{GetIgnoreTKR(symbol)}; !tkr.empty()) { |
| 869 | os << "!dir$ ignore_tkr("; |
| 870 | tkr.IterateOverMembers([&](common::IgnoreTKR tkr) { |
| 871 | switch (tkr) { |
| 872 | SWITCH_COVERS_ALL_CASES |
| 873 | case common::IgnoreTKR::Type: |
| 874 | os << 't'; |
| 875 | break; |
| 876 | case common::IgnoreTKR::Kind: |
| 877 | os << 'k'; |
| 878 | break; |
| 879 | case common::IgnoreTKR::Rank: |
| 880 | os << 'r'; |
| 881 | break; |
| 882 | case common::IgnoreTKR::Device: |
| 883 | os << 'd'; |
| 884 | break; |
| 885 | case common::IgnoreTKR::Managed: |
| 886 | os << 'm'; |
| 887 | break; |
| 888 | case common::IgnoreTKR::Contiguous: |
| 889 | os << 'c'; |
| 890 | break; |
| 891 | } |
| 892 | }); |
| 893 | os << ") " << symbol.name() << '\n'; |
| 894 | } |
Peter Klausler | 27f7180 | 2023-05-06 22:03:39 | [diff] [blame] | 895 | if (auto attr{details.cudaDataAttr()}) { |
| 896 | PutLower(os << "attributes(", common::EnumToString(*attr)) |
| 897 | << ") " << symbol.name() << '\n'; |
| 898 | } |
kkwli | 602e509 | 2023-09-12 20:51:43 | [diff] [blame] | 899 | if (symbol.test(Fortran::semantics::Symbol::Flag::CrayPointer)) { |
| 900 | if (!symbol.owner().crayPointers().empty()) { |
| 901 | for (const auto &[pointee, pointer] : symbol.owner().crayPointers()) { |
| 902 | if (pointer == symbol) { |
| 903 | os << "pointer(" << symbol.name() << "," << pointee << ")\n"; |
| 904 | } |
| 905 | } |
| 906 | } |
| 907 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 908 | } |
| 909 | |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 910 | void ModFileWriter::PutProcEntity(llvm::raw_ostream &os, const Symbol &symbol) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 911 | if (symbol.attrs().test(Attr::INTRINSIC)) { |
| 912 | os << "intrinsic::" << symbol.name() << '\n'; |
Peter Klausler | 4b7428e | 2022-11-17 21:34:40 | [diff] [blame] | 913 | if (!isSubmodule_ && symbol.attrs().test(Attr::PRIVATE)) { |
peter klausler | 8f16101 | 2021-04-07 20:21:10 | [diff] [blame] | 914 | os << "private::" << symbol.name() << '\n'; |
| 915 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 916 | return; |
| 917 | } |
| 918 | const auto &details{symbol.get<ProcEntityDetails>()}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 919 | Attrs attrs{symbol.attrs()}; |
| 920 | if (details.passName()) { |
| 921 | attrs.reset(Attr::PASS); |
| 922 | } |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 923 | PutEntity( |
| 924 | os, symbol, |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 925 | [&]() { |
| 926 | os << "procedure("; |
Peter Klausler | 83ca78d | 2024-03-05 20:00:46 | [diff] [blame] | 927 | if (details.rawProcInterface()) { |
| 928 | os << details.rawProcInterface()->name(); |
Peter Klausler | 635656f | 2022-12-16 17:54:55 | [diff] [blame] | 929 | } else if (details.type()) { |
| 930 | PutType(os, *details.type()); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 931 | } |
| 932 | os << ')'; |
| 933 | PutPassName(os, details.passName()); |
| 934 | }, |
| 935 | attrs); |
| 936 | os << '\n'; |
| 937 | } |
| 938 | |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 939 | void PutPassName( |
| 940 | llvm::raw_ostream &os, const std::optional<SourceName> &passName) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 941 | if (passName) { |
| 942 | os << ",pass(" << *passName << ')'; |
| 943 | } |
| 944 | } |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 945 | |
| 946 | void ModFileWriter::PutTypeParam(llvm::raw_ostream &os, const Symbol &symbol) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 947 | auto &details{symbol.get<TypeParamDetails>()}; |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 948 | PutEntity( |
| 949 | os, symbol, |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 950 | [&]() { |
| 951 | PutType(os, DEREF(symbol.GetType())); |
| 952 | PutLower(os << ',', common::EnumToString(details.attr())); |
| 953 | }, |
| 954 | symbol.attrs()); |
| 955 | PutInit(os, details.init()); |
| 956 | os << '\n'; |
| 957 | } |
| 958 | |
Peter Klausler | 9e7eef9 | 2022-04-13 17:39:16 | [diff] [blame] | 959 | void PutInit(llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init, |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 960 | const parser::Expr *unanalyzed, |
| 961 | const std::map<const Symbol *, SourceName> &renamings) { |
| 962 | if (IsNamedConstant(symbol) || symbol.owner().IsDerivedType()) { |
Peter Klausler | 9e7eef9 | 2022-04-13 17:39:16 | [diff] [blame] | 963 | const char *assign{symbol.attrs().test(Attr::POINTER) ? "=>" : "="}; |
| 964 | if (unanalyzed) { |
| 965 | parser::Unparse(os << assign, *unanalyzed); |
| 966 | } else if (init) { |
Peter Klausler | 1bea034 | 2023-10-31 19:17:00 | [diff] [blame] | 967 | if (const auto *dtConst{ |
| 968 | evaluate::UnwrapExpr<evaluate::Constant<evaluate::SomeDerived>>( |
| 969 | *init)}) { |
| 970 | const Symbol &dtSym{dtConst->result().derivedTypeSpec().typeSymbol()}; |
| 971 | if (auto iter{renamings.find(&dtSym)}; iter != renamings.end()) { |
| 972 | // Initializer is a constant whose derived type's name has |
| 973 | // been brought into scope from a module under a new name |
| 974 | // to avoid a conflict. |
| 975 | dtConst->AsFortran(os << assign, &iter->second); |
| 976 | return; |
| 977 | } |
| 978 | } |
Peter Klausler | 9e7eef9 | 2022-04-13 17:39:16 | [diff] [blame] | 979 | init->AsFortran(os << assign); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 980 | } |
| 981 | } |
| 982 | } |
| 983 | |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 984 | void PutInit(llvm::raw_ostream &os, const MaybeIntExpr &init) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 985 | if (init) { |
| 986 | init->AsFortran(os << '='); |
| 987 | } |
| 988 | } |
| 989 | |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 990 | void PutBound(llvm::raw_ostream &os, const Bound &x) { |
Peter Klausler | 44bc97c | 2021-11-26 21:26:50 | [diff] [blame] | 991 | if (x.isStar()) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 992 | os << '*'; |
Peter Klausler | 44bc97c | 2021-11-26 21:26:50 | [diff] [blame] | 993 | } else if (x.isColon()) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 994 | os << ':'; |
| 995 | } else { |
| 996 | x.GetExplicit()->AsFortran(os); |
| 997 | } |
| 998 | } |
| 999 | |
| 1000 | // Write an entity (object or procedure) declaration. |
| 1001 | // writeType is called to write out the type. |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 1002 | void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol, |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1003 | std::function<void()> writeType, Attrs attrs) { |
| 1004 | writeType(); |
Peter Klausler | 69e2665 | 2023-02-28 19:58:30 | [diff] [blame] | 1005 | PutAttrs(os, attrs, symbol.GetBindName(), symbol.GetIsExplicitBindName()); |
Peter Klausler | c14cf92 | 2021-12-18 00:48:16 | [diff] [blame] | 1006 | if (symbol.owner().kind() == Scope::Kind::DerivedType && |
| 1007 | context_.IsTempName(symbol.name().ToString())) { |
| 1008 | os << "::%FILL"; |
| 1009 | } else { |
| 1010 | os << "::" << symbol.name(); |
| 1011 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1012 | } |
| 1013 | |
| 1014 | // Put out each attribute to os, surrounded by `before` and `after` and |
| 1015 | // mapped to lower case. |
Peter Klausler | 4b7428e | 2022-11-17 21:34:40 | [diff] [blame] | 1016 | llvm::raw_ostream &ModFileWriter::PutAttrs(llvm::raw_ostream &os, Attrs attrs, |
Peter Klausler | 69e2665 | 2023-02-28 19:58:30 | [diff] [blame] | 1017 | const std::string *bindName, bool isExplicitBindName, std::string before, |
| 1018 | std::string after) const { |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 1019 | attrs.set(Attr::PUBLIC, false); // no need to write PUBLIC |
| 1020 | attrs.set(Attr::EXTERNAL, false); // no need to write EXTERNAL |
Peter Klausler | 4b7428e | 2022-11-17 21:34:40 | [diff] [blame] | 1021 | if (isSubmodule_) { |
| 1022 | attrs.set(Attr::PRIVATE, false); |
| 1023 | } |
Peter Klausler | 69e2665 | 2023-02-28 19:58:30 | [diff] [blame] | 1024 | if (bindName || isExplicitBindName) { |
| 1025 | os << before << "bind(c"; |
| 1026 | if (isExplicitBindName) { |
| 1027 | os << ",name=\"" << (bindName ? *bindName : ""s) << '"'; |
| 1028 | } |
| 1029 | os << ')' << after; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1030 | attrs.set(Attr::BIND_C, false); |
| 1031 | } |
| 1032 | for (std::size_t i{0}; i < Attr_enumSize; ++i) { |
| 1033 | Attr attr{static_cast<Attr>(i)}; |
| 1034 | if (attrs.test(attr)) { |
| 1035 | PutAttr(os << before, attr) << after; |
| 1036 | } |
| 1037 | } |
| 1038 | return os; |
| 1039 | } |
| 1040 | |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 1041 | llvm::raw_ostream &PutAttr(llvm::raw_ostream &os, Attr attr) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1042 | return PutLower(os, AttrToString(attr)); |
| 1043 | } |
| 1044 | |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 1045 | llvm::raw_ostream &PutType(llvm::raw_ostream &os, const DeclTypeSpec &type) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1046 | return PutLower(os, type.AsFortran()); |
| 1047 | } |
| 1048 | |
Peter Klausler | bcba39a5 | 2022-11-11 01:29:29 | [diff] [blame] | 1049 | llvm::raw_ostream &PutLower(llvm::raw_ostream &os, std::string_view str) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1050 | for (char c : str) { |
| 1051 | os << parser::ToLowerCaseLetter(c); |
| 1052 | } |
| 1053 | return os; |
| 1054 | } |
| 1055 | |
Valentin Clement | 68f3610 | 2023-08-04 21:42:38 | [diff] [blame] | 1056 | void PutOpenACCDirective(llvm::raw_ostream &os, const Symbol &symbol) { |
Valentin Clement | 22f63b5 | 2023-08-04 21:01:45 | [diff] [blame] | 1057 | if (symbol.test(Symbol::Flag::AccDeclare)) { |
| 1058 | os << "!$acc declare "; |
| 1059 | if (symbol.test(Symbol::Flag::AccCopy)) { |
| 1060 | os << "copy"; |
Valentin Clement | a749b32 | 2023-08-07 16:52:44 | [diff] [blame] | 1061 | } else if (symbol.test(Symbol::Flag::AccCopyIn) || |
| 1062 | symbol.test(Symbol::Flag::AccCopyInReadOnly)) { |
Valentin Clement | 22f63b5 | 2023-08-04 21:01:45 | [diff] [blame] | 1063 | os << "copyin"; |
| 1064 | } else if (symbol.test(Symbol::Flag::AccCopyOut)) { |
| 1065 | os << "copyout"; |
| 1066 | } else if (symbol.test(Symbol::Flag::AccCreate)) { |
| 1067 | os << "create"; |
| 1068 | } else if (symbol.test(Symbol::Flag::AccPresent)) { |
| 1069 | os << "present"; |
| 1070 | } else if (symbol.test(Symbol::Flag::AccDevicePtr)) { |
| 1071 | os << "deviceptr"; |
| 1072 | } else if (symbol.test(Symbol::Flag::AccDeviceResident)) { |
| 1073 | os << "device_resident"; |
| 1074 | } else if (symbol.test(Symbol::Flag::AccLink)) { |
| 1075 | os << "link"; |
| 1076 | } |
Valentin Clement | a749b32 | 2023-08-07 16:52:44 | [diff] [blame] | 1077 | os << "("; |
| 1078 | if (symbol.test(Symbol::Flag::AccCopyInReadOnly)) { |
| 1079 | os << "readonly: "; |
| 1080 | } |
| 1081 | os << symbol.name() << ")\n"; |
Valentin Clement | 22f63b5 | 2023-08-04 21:01:45 | [diff] [blame] | 1082 | } |
| 1083 | } |
| 1084 | |
Valentin Clement | 68f3610 | 2023-08-04 21:42:38 | [diff] [blame] | 1085 | void PutOpenMPDirective(llvm::raw_ostream &os, const Symbol &symbol) { |
| 1086 | if (symbol.test(Symbol::Flag::OmpThreadprivate)) { |
| 1087 | os << "!$omp threadprivate(" << symbol.name() << ")\n"; |
| 1088 | } |
| 1089 | } |
| 1090 | |
| 1091 | void ModFileWriter::PutDirective(llvm::raw_ostream &os, const Symbol &symbol) { |
| 1092 | PutOpenACCDirective(os, symbol); |
| 1093 | PutOpenMPDirective(os, symbol); |
| 1094 | } |
| 1095 | |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1096 | struct Temp { |
Steve Scalpone | 6110630 | 2020-03-05 15:09:29 | [diff] [blame] | 1097 | Temp(int fd, std::string path) : fd{fd}, path{path} {} |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1098 | Temp(Temp &&t) : fd{std::exchange(t.fd, -1)}, path{std::move(t.path)} {} |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1099 | ~Temp() { |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1100 | if (fd >= 0) { |
Steve Scalpone | 6110630 | 2020-03-05 15:09:29 | [diff] [blame] | 1101 | llvm::sys::fs::file_t native{llvm::sys::fs::convertFDToNativeFile(fd)}; |
| 1102 | llvm::sys::fs::closeFile(native); |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1103 | llvm::sys::fs::remove(path.c_str()); |
| 1104 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1105 | } |
Steve Scalpone | 6110630 | 2020-03-05 15:09:29 | [diff] [blame] | 1106 | int fd; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1107 | std::string path; |
| 1108 | }; |
| 1109 | |
| 1110 | // Create a temp file in the same directory and with the same suffix as path. |
| 1111 | // Return an open file descriptor and its path. |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1112 | static llvm::ErrorOr<Temp> MkTemp(const std::string &path) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1113 | auto length{path.length()}; |
| 1114 | auto dot{path.find_last_of("./")}; |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1115 | std::string suffix{ |
| 1116 | dot < length && path[dot] == '.' ? path.substr(dot + 1) : ""}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1117 | CHECK(length > suffix.length() && |
| 1118 | path.substr(length - suffix.length()) == suffix); |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1119 | auto prefix{path.substr(0, length - suffix.length())}; |
Steve Scalpone | 6110630 | 2020-03-05 15:09:29 | [diff] [blame] | 1120 | int fd; |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1121 | llvm::SmallString<16> tempPath; |
| 1122 | if (std::error_code err{llvm::sys::fs::createUniqueFile( |
| 1123 | prefix + "%%%%%%" + suffix, fd, tempPath)}) { |
| 1124 | return err; |
| 1125 | } |
| 1126 | return Temp{fd, tempPath.c_str()}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1127 | } |
| 1128 | |
| 1129 | // Write the module file at path, prepending header. If an error occurs, |
| 1130 | // return errno, otherwise 0. |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1131 | static std::error_code WriteFile(const std::string &path, |
| 1132 | const std::string &contents, ModuleCheckSumType &checkSum, bool debug) { |
| 1133 | checkSum = ComputeCheckSum(contents); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1134 | auto header{std::string{ModHeader::bom} + ModHeader::magic + |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1135 | CheckSumString(checkSum) + ModHeader::terminator}; |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1136 | if (debug) { |
| 1137 | llvm::dbgs() << "Processing module " << path << ": "; |
| 1138 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1139 | if (FileContentsMatch(path, header, contents)) { |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1140 | if (debug) { |
| 1141 | llvm::dbgs() << "module unchanged, not writing\n"; |
| 1142 | } |
| 1143 | return {}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1144 | } |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1145 | llvm::ErrorOr<Temp> temp{MkTemp(path)}; |
| 1146 | if (!temp) { |
| 1147 | return temp.getError(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1148 | } |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1149 | llvm::raw_fd_ostream writer(temp->fd, /*shouldClose=*/false); |
| 1150 | writer << header; |
| 1151 | writer << contents; |
| 1152 | writer.flush(); |
| 1153 | if (writer.has_error()) { |
| 1154 | return writer.error(); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1155 | } |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1156 | if (debug) { |
| 1157 | llvm::dbgs() << "module written\n"; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1158 | } |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1159 | return llvm::sys::fs::rename(temp->path, path); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1160 | } |
| 1161 | |
| 1162 | // Return true if the stream matches what we would write for the mod file. |
| 1163 | static bool FileContentsMatch(const std::string &path, |
| 1164 | const std::string &header, const std::string &contents) { |
| 1165 | std::size_t hsize{header.size()}; |
| 1166 | std::size_t csize{contents.size()}; |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1167 | auto buf_or{llvm::MemoryBuffer::getFile(path)}; |
| 1168 | if (!buf_or) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1169 | return false; |
| 1170 | } |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1171 | auto buf = std::move(buf_or.get()); |
| 1172 | if (buf->getBufferSize() != hsize + csize) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1173 | return false; |
| 1174 | } |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1175 | if (!std::equal(header.begin(), header.end(), buf->getBufferStart(), |
| 1176 | buf->getBufferStart() + hsize)) { |
| 1177 | return false; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1178 | } |
David Truby | 0855c45 | 2020-02-25 15:59:50 | [diff] [blame] | 1179 | |
| 1180 | return std::equal(contents.begin(), contents.end(), |
| 1181 | buf->getBufferStart() + hsize, buf->getBufferEnd()); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1182 | } |
| 1183 | |
| 1184 | // Compute a simple hash of the contents of a module file and |
| 1185 | // return it as a string of hex digits. |
| 1186 | // This uses the Fowler-Noll-Vo hash function. |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1187 | static ModuleCheckSumType ComputeCheckSum(const std::string_view &contents) { |
| 1188 | ModuleCheckSumType hash{0xcbf29ce484222325ull}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1189 | for (char c : contents) { |
| 1190 | hash ^= c & 0xff; |
| 1191 | hash *= 0x100000001b3; |
| 1192 | } |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1193 | return hash; |
| 1194 | } |
| 1195 | |
| 1196 | static std::string CheckSumString(ModuleCheckSumType hash) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1197 | static const char *digits = "0123456789abcdef"; |
| 1198 | std::string result(ModHeader::sumLen, '0'); |
| 1199 | for (size_t i{ModHeader::sumLen}; hash != 0; hash >>= 4) { |
| 1200 | result[--i] = digits[hash & 0xf]; |
| 1201 | } |
| 1202 | return result; |
| 1203 | } |
| 1204 | |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1205 | std::optional<ModuleCheckSumType> ExtractCheckSum(const std::string_view &str) { |
| 1206 | if (str.size() == ModHeader::sumLen) { |
| 1207 | ModuleCheckSumType hash{0}; |
| 1208 | for (size_t j{0}; j < ModHeader::sumLen; ++j) { |
| 1209 | hash <<= 4; |
| 1210 | char ch{str.at(j)}; |
| 1211 | if (ch >= '0' && ch <= '9') { |
| 1212 | hash += ch - '0'; |
| 1213 | } else if (ch >= 'a' && ch <= 'f') { |
| 1214 | hash += ch - 'a' + 10; |
| 1215 | } else { |
| 1216 | return std::nullopt; |
| 1217 | } |
| 1218 | } |
| 1219 | return hash; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1220 | } |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1221 | return std::nullopt; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1222 | } |
| 1223 | |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1224 | static std::optional<ModuleCheckSumType> VerifyHeader( |
| 1225 | llvm::ArrayRef<char> content) { |
| 1226 | std::string_view sv{content.data(), content.size()}; |
| 1227 | if (sv.substr(0, ModHeader::magicLen) != ModHeader::magic) { |
| 1228 | return std::nullopt; |
| 1229 | } |
| 1230 | ModuleCheckSumType checkSum{ComputeCheckSum(sv.substr(ModHeader::len))}; |
| 1231 | std::string_view expectSum{sv.substr(ModHeader::magicLen, ModHeader::sumLen)}; |
| 1232 | if (auto extracted{ExtractCheckSum(expectSum)}; |
| 1233 | extracted && *extracted == checkSum) { |
| 1234 | return checkSum; |
| 1235 | } else { |
| 1236 | return std::nullopt; |
| 1237 | } |
| 1238 | } |
| 1239 | |
| 1240 | static void GetModuleDependences( |
| 1241 | ModuleDependences &dependences, llvm::ArrayRef<char> content) { |
| 1242 | std::size_t limit{content.size()}; |
| 1243 | std::string_view str{content.data(), limit}; |
| 1244 | for (std::size_t j{ModHeader::len}; |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1245 | str.substr(j, ModHeader::needLen) == ModHeader::need; ++j) { |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1246 | j += 7; |
| 1247 | auto checkSum{ExtractCheckSum(str.substr(j, ModHeader::sumLen))}; |
| 1248 | if (!checkSum) { |
| 1249 | break; |
| 1250 | } |
| 1251 | j += ModHeader::sumLen; |
| 1252 | bool intrinsic{false}; |
| 1253 | if (str.substr(j, 3) == " i ") { |
| 1254 | intrinsic = true; |
| 1255 | } else if (str.substr(j, 3) != " n ") { |
| 1256 | break; |
| 1257 | } |
| 1258 | j += 3; |
| 1259 | std::size_t start{j}; |
| 1260 | for (; j < limit && str.at(j) != '\n'; ++j) { |
| 1261 | } |
| 1262 | if (j > start && j < limit && str.at(j) == '\n') { |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1263 | std::string depModName{str.substr(start, j - start)}; |
| 1264 | dependences.AddDependence(std::move(depModName), intrinsic, *checkSum); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1265 | } else { |
| 1266 | break; |
| 1267 | } |
| 1268 | } |
| 1269 | } |
| 1270 | |
| 1271 | Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic, |
| 1272 | Scope *ancestor, bool silent) { |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 1273 | std::string ancestorName; // empty for module |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1274 | const Symbol *notAModule{nullptr}; |
Peter Klausler | 9f33dd7 | 2022-05-11 21:13:50 | [diff] [blame] | 1275 | bool fatalError{false}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1276 | if (ancestor) { |
| 1277 | if (auto *scope{ancestor->FindSubmodule(name)}) { |
| 1278 | return scope; |
| 1279 | } |
| 1280 | ancestorName = ancestor->GetName().value().ToString(); |
Peter Klausler | dcbfabb | 2022-08-16 21:16:29 | [diff] [blame] | 1281 | } |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1282 | auto requiredHash{context_.moduleDependences().GetRequiredHash( |
| 1283 | name.ToString(), isIntrinsic.value_or(false))}; |
Peter Klausler | dcbfabb | 2022-08-16 21:16:29 | [diff] [blame] | 1284 | if (!isIntrinsic.value_or(false) && !ancestor) { |
| 1285 | // Already present in the symbol table as a usable non-intrinsic module? |
| 1286 | auto it{context_.globalScope().find(name)}; |
| 1287 | if (it != context_.globalScope().end()) { |
| 1288 | Scope *scope{it->second->scope()}; |
| 1289 | if (scope->kind() == Scope::Kind::Module) { |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1290 | for (const Symbol *found{scope->symbol()}; found;) { |
| 1291 | if (const auto *module{found->detailsIf<ModuleDetails>()}) { |
| 1292 | if (!requiredHash || |
| 1293 | *requiredHash == |
| 1294 | module->moduleFileHash().value_or(*requiredHash)) { |
| 1295 | return const_cast<Scope *>(found->scope()); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1296 | } |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1297 | found = module->previous(); // same name, distinct hash |
| 1298 | } else { |
| 1299 | notAModule = found; |
| 1300 | break; |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1301 | } |
| 1302 | } |
Peter Klausler | dcbfabb | 2022-08-16 21:16:29 | [diff] [blame] | 1303 | } else { |
| 1304 | notAModule = scope->symbol(); |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1305 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1306 | } |
| 1307 | } |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1308 | if (notAModule) { |
| 1309 | // USE, NON_INTRINSIC global name isn't a module? |
| 1310 | fatalError = isIntrinsic.has_value(); |
| 1311 | } |
Peter Klausler | dcbfabb | 2022-08-16 21:16:29 | [diff] [blame] | 1312 | auto path{ModFileName(name, ancestorName, context_.moduleFileSuffix())}; |
peter klausler | 92a5419 | 2020-08-31 19:22:24 | [diff] [blame] | 1313 | parser::Parsing parsing{context_.allCookedSources()}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1314 | parser::Options options; |
| 1315 | options.isModuleFile = true; |
| 1316 | options.features.Enable(common::LanguageFeature::BackslashEscapes); |
Peixin-Qiao | 2cbd4fc | 2022-04-09 05:52:31 | [diff] [blame] | 1317 | options.features.Enable(common::LanguageFeature::OpenMP); |
Peter Klausler | 27f7180 | 2023-05-06 22:03:39 | [diff] [blame] | 1318 | options.features.Enable(common::LanguageFeature::CUDA); |
Peter Klausler | 9f33dd7 | 2022-05-11 21:13:50 | [diff] [blame] | 1319 | if (!isIntrinsic.value_or(false) && !notAModule) { |
Peter Klausler | dcbfabb | 2022-08-16 21:16:29 | [diff] [blame] | 1320 | // The search for this module file will scan non-intrinsic module |
| 1321 | // directories. If a directory is in both the intrinsic and non-intrinsic |
| 1322 | // directory lists, the intrinsic module directory takes precedence. |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1323 | options.searchDirectories = context_.searchDirectories(); |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1324 | for (const auto &dir : context_.intrinsicModuleDirectories()) { |
Shao-Ce SUN | f95bdff | 2023-01-31 16:24:43 | [diff] [blame] | 1325 | options.searchDirectories.erase( |
| 1326 | std::remove(options.searchDirectories.begin(), |
| 1327 | options.searchDirectories.end(), dir), |
| 1328 | options.searchDirectories.end()); |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1329 | } |
Peter Klausler | 15faac9 | 2022-05-30 19:47:32 | [diff] [blame] | 1330 | options.searchDirectories.insert(options.searchDirectories.begin(), "."s); |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1331 | } |
Peter Klausler | dcbfabb | 2022-08-16 21:16:29 | [diff] [blame] | 1332 | bool foundNonIntrinsicModuleFile{false}; |
| 1333 | if (!isIntrinsic) { |
| 1334 | std::list<std::string> searchDirs; |
| 1335 | for (const auto &d : options.searchDirectories) { |
| 1336 | searchDirs.push_back(d); |
| 1337 | } |
| 1338 | foundNonIntrinsicModuleFile = |
| 1339 | parser::LocateSourceFile(path, searchDirs).has_value(); |
| 1340 | } |
| 1341 | if (isIntrinsic.value_or(!foundNonIntrinsicModuleFile)) { |
| 1342 | // Explicitly intrinsic, or not specified and not found in the search |
| 1343 | // path; see whether it's already in the symbol table as an intrinsic |
| 1344 | // module. |
| 1345 | auto it{context_.intrinsicModulesScope().find(name)}; |
| 1346 | if (it != context_.intrinsicModulesScope().end()) { |
| 1347 | return it->second->scope(); |
| 1348 | } |
| 1349 | } |
| 1350 | // We don't have this module in the symbol table yet. |
| 1351 | // Find its module file and parse it. Define or extend the search |
| 1352 | // path with intrinsic module directories, if appropriate. |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1353 | if (isIntrinsic.value_or(true)) { |
| 1354 | for (const auto &dir : context_.intrinsicModuleDirectories()) { |
| 1355 | options.searchDirectories.push_back(dir); |
| 1356 | } |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1357 | if (!requiredHash) { |
| 1358 | requiredHash = |
| 1359 | context_.moduleDependences().GetRequiredHash(name.ToString(), true); |
| 1360 | } |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1361 | } |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1362 | |
| 1363 | // Look for the right module file if its hash is known |
| 1364 | if (requiredHash && !fatalError) { |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1365 | for (const std::string &maybe : |
| 1366 | parser::LocateSourceFileAll(path, options.searchDirectories)) { |
| 1367 | if (const auto *srcFile{context_.allCookedSources().allSources().OpenPath( |
| 1368 | maybe, llvm::errs())}) { |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1369 | if (auto checkSum{VerifyHeader(srcFile->content())}; |
| 1370 | checkSum && *checkSum == *requiredHash) { |
| 1371 | path = maybe; |
| 1372 | break; |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1373 | } |
| 1374 | } |
| 1375 | } |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1376 | } |
Peter Klausler | 9f33dd7 | 2022-05-11 21:13:50 | [diff] [blame] | 1377 | const auto *sourceFile{fatalError ? nullptr : parsing.Prescan(path, options)}; |
| 1378 | if (fatalError || parsing.messages().AnyFatalError()) { |
peter klausler | 52711fb | 2021-09-21 23:06:30 | [diff] [blame] | 1379 | if (!silent) { |
Peter Klausler | 9f33dd7 | 2022-05-11 21:13:50 | [diff] [blame] | 1380 | if (notAModule) { |
| 1381 | // Module is not explicitly INTRINSIC, and there's already a global |
| 1382 | // symbol of the same name that is not a module. |
| 1383 | context_.SayWithDecl( |
| 1384 | *notAModule, name, "'%s' is not a module"_err_en_US, name); |
| 1385 | } else { |
| 1386 | for (auto &msg : parsing.messages().messages()) { |
| 1387 | std::string str{msg.ToString()}; |
| 1388 | Say(name, ancestorName, |
| 1389 | parser::MessageFixedText{str.c_str(), str.size(), msg.severity()}, |
| 1390 | path); |
| 1391 | } |
peter klausler | 52711fb | 2021-09-21 23:06:30 | [diff] [blame] | 1392 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1393 | } |
| 1394 | return nullptr; |
| 1395 | } |
| 1396 | CHECK(sourceFile); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1397 | std::optional<ModuleCheckSumType> checkSum{ |
| 1398 | VerifyHeader(sourceFile->content())}; |
| 1399 | if (!checkSum) { |
Peter Klausler | a53967c | 2022-03-07 21:57:37 | [diff] [blame] | 1400 | Say(name, ancestorName, "File has invalid checksum: %s"_warn_en_US, |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1401 | sourceFile->path()); |
| 1402 | return nullptr; |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1403 | } else if (requiredHash && *requiredHash != *checkSum) { |
| 1404 | Say(name, ancestorName, |
| 1405 | "File is not the right module file for %s"_warn_en_US, |
| 1406 | "'"s + name.ToString() + "': "s + sourceFile->path()); |
| 1407 | return nullptr; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1408 | } |
Caroline Concatto | 8670e49 | 2020-02-28 15:11:03 | [diff] [blame] | 1409 | llvm::raw_null_ostream NullStream; |
| 1410 | parsing.Parse(NullStream); |
Peter Klausler | f4bb211 | 2022-04-25 23:00:01 | [diff] [blame] | 1411 | std::optional<parser::Program> &parsedProgram{parsing.parseTree()}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1412 | if (!parsing.messages().empty() || !parsing.consumedWholeFile() || |
Peter Klausler | f4bb211 | 2022-04-25 23:00:01 | [diff] [blame] | 1413 | !parsedProgram) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1414 | Say(name, ancestorName, "Module file is corrupt: %s"_err_en_US, |
| 1415 | sourceFile->path()); |
| 1416 | return nullptr; |
| 1417 | } |
Peter Klausler | f4bb211 | 2022-04-25 23:00:01 | [diff] [blame] | 1418 | parser::Program &parseTree{context_.SaveParseTree(std::move(*parsedProgram))}; |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 1419 | Scope *parentScope; // the scope this module/submodule goes into |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1420 | if (!isIntrinsic.has_value()) { |
| 1421 | for (const auto &dir : context_.intrinsicModuleDirectories()) { |
| 1422 | if (sourceFile->path().size() > dir.size() && |
| 1423 | sourceFile->path().find(dir) == 0) { |
| 1424 | isIntrinsic = true; |
| 1425 | break; |
| 1426 | } |
| 1427 | } |
| 1428 | } |
| 1429 | Scope &topScope{isIntrinsic.value_or(false) ? context_.intrinsicModulesScope() |
| 1430 | : context_.globalScope()}; |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1431 | Symbol *moduleSymbol{nullptr}; |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1432 | const Symbol *previousModuleSymbol{nullptr}; |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1433 | if (!ancestor) { // module, not submodule |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1434 | parentScope = &topScope; |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1435 | auto pair{parentScope->try_emplace(name, UnknownDetails{})}; |
| 1436 | if (!pair.second) { |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1437 | // There is already a global symbol or intrinsic module of the same name. |
| 1438 | previousModuleSymbol = &*pair.first->second; |
| 1439 | if (const auto *details{ |
| 1440 | previousModuleSymbol->detailsIf<ModuleDetails>()}) { |
| 1441 | if (!details->moduleFileHash().has_value()) { |
| 1442 | return nullptr; |
| 1443 | } |
| 1444 | } else { |
| 1445 | return nullptr; |
| 1446 | } |
| 1447 | CHECK(parentScope->erase(name) != 0); |
| 1448 | pair = parentScope->try_emplace(name, UnknownDetails{}); |
| 1449 | CHECK(pair.second); |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1450 | } |
| 1451 | moduleSymbol = &*pair.first->second; |
| 1452 | moduleSymbol->set(Symbol::Flag::ModFile); |
Peter Klausler | f4bb211 | 2022-04-25 23:00:01 | [diff] [blame] | 1453 | } else if (std::optional<SourceName> parent{GetSubmoduleParent(parseTree)}) { |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1454 | // submodule with submodule parent |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1455 | parentScope = Read(*parent, false /*not intrinsic*/, ancestor, silent); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1456 | } else { |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1457 | // submodule with module parent |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1458 | parentScope = ancestor; |
| 1459 | } |
Peter Klausler | 7350625 | 2022-05-24 22:06:12 | [diff] [blame] | 1460 | // Process declarations from the module file |
Peter Klausler | 7350625 | 2022-05-24 22:06:12 | [diff] [blame] | 1461 | bool wasInModuleFile{context_.foldingContext().inModuleFile()}; |
| 1462 | context_.foldingContext().set_inModuleFile(true); |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1463 | GetModuleDependences(context_.moduleDependences(), sourceFile->content()); |
Peter Klausler | f4bb211 | 2022-04-25 23:00:01 | [diff] [blame] | 1464 | ResolveNames(context_, parseTree, topScope); |
Peter Klausler | 7350625 | 2022-05-24 22:06:12 | [diff] [blame] | 1465 | context_.foldingContext().set_inModuleFile(wasInModuleFile); |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1466 | if (!moduleSymbol) { |
| 1467 | // Submodule symbols' storage are owned by their parents' scopes, |
| 1468 | // but their names are not in their parents' dictionaries -- we |
| 1469 | // don't want to report bogus errors about clashes between submodule |
| 1470 | // names and other objects in the parent scopes. |
| 1471 | if (Scope * submoduleScope{ancestor->FindSubmodule(name)}) { |
| 1472 | moduleSymbol = submoduleScope->symbol(); |
| 1473 | if (moduleSymbol) { |
| 1474 | moduleSymbol->set(Symbol::Flag::ModFile); |
| 1475 | } |
| 1476 | } |
Peter Klausler | 52a1346 | 2022-01-26 17:54:58 | [diff] [blame] | 1477 | } |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1478 | if (moduleSymbol) { |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1479 | CHECK(moduleSymbol->test(Symbol::Flag::ModFile)); |
Peter Klausler | 5661188 | 2024-03-13 21:42:40 | [diff] [blame] | 1480 | auto &details{moduleSymbol->get<ModuleDetails>()}; |
| 1481 | details.set_moduleFileHash(checkSum.value()); |
| 1482 | details.set_previous(previousModuleSymbol); |
Peter Klausler | e200b0e | 2023-10-16 21:15:40 | [diff] [blame] | 1483 | if (isIntrinsic.value_or(false)) { |
| 1484 | moduleSymbol->attrs().set(Attr::INTRINSIC); |
| 1485 | } |
| 1486 | return moduleSymbol->scope(); |
| 1487 | } else { |
| 1488 | return nullptr; |
| 1489 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1490 | } |
| 1491 | |
Peter Klausler | f7a15e0 | 2024-03-01 21:58:36 | [diff] [blame] | 1492 | parser::Message &ModFileReader::Say(SourceName name, |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1493 | const std::string &ancestor, parser::MessageFixedText &&msg, |
| 1494 | const std::string &arg) { |
peter klausler | 0bfa4ac | 2021-02-11 00:20:59 | [diff] [blame] | 1495 | return context_.Say(name, "Cannot read module file for %s: %s"_err_en_US, |
| 1496 | parser::MessageFormattedText{ancestor.empty() |
| 1497 | ? "module '%s'"_en_US |
| 1498 | : "submodule '%s' of module '%s'"_en_US, |
| 1499 | name, ancestor} |
| 1500 | .MoveString(), |
| 1501 | parser::MessageFormattedText{std::move(msg), arg}.MoveString()); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1502 | } |
| 1503 | |
| 1504 | // program was read from a .mod file for a submodule; return the name of the |
| 1505 | // submodule's parent submodule, nullptr if none. |
| 1506 | static std::optional<SourceName> GetSubmoduleParent( |
| 1507 | const parser::Program &program) { |
| 1508 | CHECK(program.v.size() == 1); |
| 1509 | auto &unit{program.v.front()}; |
| 1510 | auto &submod{std::get<common::Indirection<parser::Submodule>>(unit.u)}; |
| 1511 | auto &stmt{ |
| 1512 | std::get<parser::Statement<parser::SubmoduleStmt>>(submod.value().t)}; |
| 1513 | auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)}; |
| 1514 | if (auto &parent{std::get<std::optional<parser::Name>>(parentId.t)}) { |
| 1515 | return parent->source; |
| 1516 | } else { |
| 1517 | return std::nullopt; |
| 1518 | } |
| 1519 | } |
| 1520 | |
| 1521 | void SubprogramSymbolCollector::Collect() { |
| 1522 | const auto &details{symbol_.get<SubprogramDetails>()}; |
| 1523 | isInterface_ = details.isInterface(); |
| 1524 | for (const Symbol *dummyArg : details.dummyArgs()) { |
Pete Steinfeld | 3ed2909 | 2020-06-18 14:05:08 | [diff] [blame] | 1525 | if (dummyArg) { |
| 1526 | DoSymbol(*dummyArg); |
| 1527 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1528 | } |
| 1529 | if (details.isFunction()) { |
| 1530 | DoSymbol(details.result()); |
| 1531 | } |
| 1532 | for (const auto &pair : scope_) { |
| 1533 | const Symbol &symbol{*pair.second}; |
| 1534 | if (const auto *useDetails{symbol.detailsIf<UseDetails>()}) { |
Peter Klausler | 665d415 | 2022-02-25 21:54:44 | [diff] [blame] | 1535 | const Symbol &ultimate{useDetails->symbol().GetUltimate()}; |
| 1536 | bool needed{useSet_.count(ultimate) > 0}; |
| 1537 | if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { |
| 1538 | // The generic may not be needed itself, but the specific procedure |
| 1539 | // &/or derived type that it shadows may be needed. |
| 1540 | const Symbol *spec{generic->specific()}; |
| 1541 | const Symbol *dt{generic->derivedType()}; |
| 1542 | needed = needed || (spec && useSet_.count(*spec) > 0) || |
| 1543 | (dt && useSet_.count(*dt) > 0); |
Peter Klausler | b67984d | 2022-06-09 23:06:23 | [diff] [blame] | 1544 | } else if (const auto *subp{ultimate.detailsIf<SubprogramDetails>()}) { |
| 1545 | const Symbol *interface { subp->moduleInterface() }; |
| 1546 | needed = needed || (interface && useSet_.count(*interface) > 0); |
Peter Klausler | 665d415 | 2022-02-25 21:54:44 | [diff] [blame] | 1547 | } |
| 1548 | if (needed) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1549 | need_.push_back(symbol); |
| 1550 | } |
Emil Kieri | b85922c | 2022-03-15 17:40:06 | [diff] [blame] | 1551 | } else if (symbol.has<SubprogramDetails>()) { |
| 1552 | // An internal subprogram is needed if it is used as interface |
| 1553 | // for a dummy or return value procedure. |
| 1554 | bool needed{false}; |
| 1555 | const auto hasInterface{[&symbol](const Symbol *s) -> bool { |
| 1556 | // Is 's' a procedure with interface 'symbol'? |
| 1557 | if (s) { |
| 1558 | if (const auto *sDetails{s->detailsIf<ProcEntityDetails>()}) { |
Peter Klausler | 635656f | 2022-12-16 17:54:55 | [diff] [blame] | 1559 | if (sDetails->procInterface() == &symbol) { |
Emil Kieri | b85922c | 2022-03-15 17:40:06 | [diff] [blame] | 1560 | return true; |
| 1561 | } |
| 1562 | } |
| 1563 | } |
| 1564 | return false; |
| 1565 | }}; |
| 1566 | for (const Symbol *dummyArg : details.dummyArgs()) { |
| 1567 | needed = needed || hasInterface(dummyArg); |
| 1568 | } |
| 1569 | needed = |
| 1570 | needed || (details.isFunction() && hasInterface(&details.result())); |
| 1571 | if (needed && needSet_.insert(symbol).second) { |
| 1572 | need_.push_back(symbol); |
| 1573 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1574 | } |
| 1575 | } |
| 1576 | } |
| 1577 | |
| 1578 | void SubprogramSymbolCollector::DoSymbol(const Symbol &symbol) { |
| 1579 | DoSymbol(symbol.name(), symbol); |
| 1580 | } |
| 1581 | |
| 1582 | // Do symbols this one depends on; then add to need_ |
| 1583 | void SubprogramSymbolCollector::DoSymbol( |
| 1584 | const SourceName &name, const Symbol &symbol) { |
| 1585 | const auto &scope{symbol.owner()}; |
| 1586 | if (scope != scope_ && !scope.IsDerivedType()) { |
| 1587 | if (scope != scope_.parent()) { |
| 1588 | useSet_.insert(symbol); |
| 1589 | } |
| 1590 | if (NeedImport(name, symbol)) { |
| 1591 | imports_.insert(name); |
| 1592 | } |
| 1593 | return; |
| 1594 | } |
| 1595 | if (!needSet_.insert(symbol).second) { |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 1596 | return; // already done |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1597 | } |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 1598 | common::visit(common::visitors{ |
| 1599 | [this](const ObjectEntityDetails &details) { |
| 1600 | for (const ShapeSpec &spec : details.shape()) { |
| 1601 | DoBound(spec.lbound()); |
| 1602 | DoBound(spec.ubound()); |
| 1603 | } |
| 1604 | for (const ShapeSpec &spec : details.coshape()) { |
| 1605 | DoBound(spec.lbound()); |
| 1606 | DoBound(spec.ubound()); |
| 1607 | } |
| 1608 | if (const Symbol * commonBlock{details.commonBlock()}) { |
| 1609 | DoSymbol(*commonBlock); |
| 1610 | } |
| 1611 | }, |
| 1612 | [this](const CommonBlockDetails &details) { |
| 1613 | for (const auto &object : details.objects()) { |
| 1614 | DoSymbol(*object); |
| 1615 | } |
| 1616 | }, |
Peter Klausler | df3e5f1 | 2022-08-25 17:22:10 | [diff] [blame] | 1617 | [this](const ProcEntityDetails &details) { |
Peter Klausler | 83ca78d | 2024-03-05 20:00:46 | [diff] [blame] | 1618 | if (details.rawProcInterface()) { |
| 1619 | DoSymbol(*details.rawProcInterface()); |
Peter Klausler | 635656f | 2022-12-16 17:54:55 | [diff] [blame] | 1620 | } else { |
| 1621 | DoType(details.type()); |
Peter Klausler | df3e5f1 | 2022-08-25 17:22:10 | [diff] [blame] | 1622 | } |
Peter Klausler | df3e5f1 | 2022-08-25 17:22:10 | [diff] [blame] | 1623 | }, |
Peter Klausler | d0708e6 | 2024-01-15 19:37:46 | [diff] [blame] | 1624 | [this](const ProcBindingDetails &details) { |
| 1625 | DoSymbol(details.symbol()); |
| 1626 | }, |
Peter Klausler | cd03e96 | 2022-03-23 21:05:50 | [diff] [blame] | 1627 | [](const auto &) {}, |
| 1628 | }, |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1629 | symbol.details()); |
| 1630 | if (!symbol.has<UseDetails>()) { |
| 1631 | DoType(symbol.GetType()); |
| 1632 | } |
| 1633 | if (!scope.IsDerivedType()) { |
| 1634 | need_.push_back(symbol); |
| 1635 | } |
| 1636 | } |
| 1637 | |
| 1638 | void SubprogramSymbolCollector::DoType(const DeclTypeSpec *type) { |
| 1639 | if (!type) { |
| 1640 | return; |
| 1641 | } |
| 1642 | switch (type->category()) { |
| 1643 | case DeclTypeSpec::Numeric: |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 1644 | case DeclTypeSpec::Logical: |
| 1645 | break; // nothing to do |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1646 | case DeclTypeSpec::Character: |
| 1647 | DoParamValue(type->characterTypeSpec().length()); |
| 1648 | break; |
| 1649 | default: |
| 1650 | if (const DerivedTypeSpec * derived{type->AsDerived()}) { |
| 1651 | const auto &typeSymbol{derived->typeSymbol()}; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1652 | for (const auto &pair : derived->parameters()) { |
| 1653 | DoParamValue(pair.second); |
| 1654 | } |
Peter Klausler | d0708e6 | 2024-01-15 19:37:46 | [diff] [blame] | 1655 | // The components of the type (including its parent component, if |
| 1656 | // any) matter to IMPORT symbol collection only for derived types |
| 1657 | // defined in the subprogram. |
| 1658 | if (typeSymbol.owner() == scope_) { |
| 1659 | if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) { |
| 1660 | DoSymbol(extends->name(), extends->typeSymbol()); |
| 1661 | } |
| 1662 | for (const auto &pair : *typeSymbol.scope()) { |
| 1663 | DoSymbol(*pair.second); |
| 1664 | } |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1665 | } |
Peter Klausler | d0708e6 | 2024-01-15 19:37:46 | [diff] [blame] | 1666 | DoSymbol(derived->name(), typeSymbol); |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1667 | } |
| 1668 | } |
| 1669 | } |
| 1670 | |
| 1671 | void SubprogramSymbolCollector::DoBound(const Bound &bound) { |
| 1672 | if (const MaybeSubscriptIntExpr & expr{bound.GetExplicit()}) { |
| 1673 | DoExpr(*expr); |
| 1674 | } |
| 1675 | } |
| 1676 | void SubprogramSymbolCollector::DoParamValue(const ParamValue ¶mValue) { |
| 1677 | if (const auto &expr{paramValue.GetExplicit()}) { |
| 1678 | DoExpr(*expr); |
| 1679 | } |
| 1680 | } |
| 1681 | |
| 1682 | // Do we need a IMPORT of this symbol into an interface block? |
| 1683 | bool SubprogramSymbolCollector::NeedImport( |
| 1684 | const SourceName &name, const Symbol &symbol) { |
| 1685 | if (!isInterface_) { |
| 1686 | return false; |
Peter Klausler | 9e855a6 | 2022-12-02 15:19:49 | [diff] [blame] | 1687 | } else if (IsSeparateModuleProcedureInterface(&symbol_)) { |
| 1688 | return false; // IMPORT needed only for external and dummy procedure |
| 1689 | // interfaces |
Peter Klausler | df3e5f1 | 2022-08-25 17:22:10 | [diff] [blame] | 1690 | } else if (&symbol == scope_.symbol()) { |
| 1691 | return false; |
peter klausler | 4864d9f | 2021-01-13 22:12:23 | [diff] [blame] | 1692 | } else if (symbol.owner().Contains(scope_)) { |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1693 | return true; |
Peter Klausler | 9e855a6 | 2022-12-02 15:19:49 | [diff] [blame] | 1694 | } else if (const Symbol *found{scope_.FindSymbol(name)}) { |
peter klausler | 4864d9f | 2021-01-13 22:12:23 | [diff] [blame] | 1695 | // detect import from ancestor of use-associated symbol |
| 1696 | return found->has<UseDetails>() && found->owner() != scope_; |
| 1697 | } else { |
Peter Klausler | d0708e6 | 2024-01-15 19:37:46 | [diff] [blame] | 1698 | // "found" can be null in the case of a use-associated derived type's |
| 1699 | // parent type |
peter klausler | 4864d9f | 2021-01-13 22:12:23 | [diff] [blame] | 1700 | CHECK(symbol.has<DerivedTypeDetails>()); |
| 1701 | return false; |
CarolineConcatto | 64ab330 | 2020-02-25 15:11:52 | [diff] [blame] | 1702 | } |
| 1703 | } |
| 1704 | |
Tim Keith | 1f87900 | 2020-03-29 04:00:16 | [diff] [blame] | 1705 | } // namespace Fortran::semantics |