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