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/Semantics/scope.h"
16 #include "flang/Semantics/semantics.h"
17 #include "flang/Semantics/symbol.h"
18 #include "flang/Semantics/tools.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include <algorithm>
23 #include <fstream>
24 #include <set>
25 #include <string_view>
26 #include <vector>
27 
28 namespace Fortran::semantics {
29 
30 using namespace parser::literals;
31 
32 // The first line of a file that identifies it as a .mod file.
33 // The first three bytes are a Unicode byte order mark that ensures
34 // that the module file is decoded as UTF-8 even if source files
35 // are using another encoding.
36 struct ModHeader {
37   static constexpr const char bom[3 + 1]{"\xef\xbb\xbf"};
38   static constexpr int magicLen{13};
39   static constexpr int sumLen{16};
40   static constexpr const char magic[magicLen + 1]{"!mod$ v1 sum:"};
41   static constexpr char terminator{'\n'};
42   static constexpr int len{magicLen + 1 + sumLen};
43 };
44 
45 static std::optional<SourceName> GetSubmoduleParent(const parser::Program &);
46 static SymbolVector CollectSymbols(const Scope &);
47 static void PutEntity(llvm::raw_ostream &, const Symbol &);
48 static void PutObjectEntity(llvm::raw_ostream &, const Symbol &);
49 static void PutProcEntity(llvm::raw_ostream &, const Symbol &);
50 static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &);
51 static void PutTypeParam(llvm::raw_ostream &, const Symbol &);
52 static void PutEntity(
53     llvm::raw_ostream &, const Symbol &, std::function<void()>, Attrs);
54 static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &);
55 static void PutInit(llvm::raw_ostream &, const MaybeIntExpr &);
56 static void PutBound(llvm::raw_ostream &, const Bound &);
57 static llvm::raw_ostream &PutAttrs(llvm::raw_ostream &, Attrs,
58     const MaybeExpr & = std::nullopt, std::string before = ","s,
59     std::string after = ""s);
60 
61 static llvm::raw_ostream &PutAttr(llvm::raw_ostream &, Attr);
62 static llvm::raw_ostream &PutType(llvm::raw_ostream &, const DeclTypeSpec &);
63 static llvm::raw_ostream &PutLower(llvm::raw_ostream &, const std::string &);
64 static std::error_code WriteFile(
65     const std::string &, const std::string &, bool = true);
66 static bool FileContentsMatch(
67     const std::string &, const std::string &, const std::string &);
68 static std::string CheckSum(const std::string_view &);
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   SymbolSet needSet_; // symbols already in need_
85   SymbolSet 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   auto *ancestor{symbol.get<ModuleDetails>().ancestor()};
136   auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s};
137   auto path{context_.moduleDirectory() + '/' +
138       ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())};
139   PutSymbols(DEREF(symbol.scope()));
140   if (std::error_code error{
141           WriteFile(path, GetAsString(symbol), context_.debugModuleWriter())}) {
142     context_.Say(
143         symbol.name(), "Error writing %s: %s"_err_en_US, path, error.message());
144   }
145 }
146 
147 // Return the entire body of the module file
148 // and clear saved uses, decls, and contains.
149 std::string ModFileWriter::GetAsString(const Symbol &symbol) {
150   std::string buf;
151   llvm::raw_string_ostream all{buf};
152   auto &details{symbol.get<ModuleDetails>()};
153   if (!details.isSubmodule()) {
154     all << "module " << symbol.name();
155   } else {
156     auto *parent{details.parent()->symbol()};
157     auto *ancestor{details.ancestor()->symbol()};
158     all << "submodule(" << ancestor->name();
159     if (parent != ancestor) {
160       all << ':' << parent->name();
161     }
162     all << ") " << symbol.name();
163   }
164   all << '\n' << uses_.str();
165   uses_.str().clear();
166   all << useExtraAttrs_.str();
167   useExtraAttrs_.str().clear();
168   all << decls_.str();
169   decls_.str().clear();
170   auto str{contains_.str()};
171   contains_.str().clear();
172   if (!str.empty()) {
173     all << "contains\n" << str;
174   }
175   all << "end\n";
176   return all.str();
177 }
178 
179 // Put out the visible symbols from scope.
180 void ModFileWriter::PutSymbols(const Scope &scope) {
181   std::string buf;
182   llvm::raw_string_ostream typeBindings{
183       buf}; // stuff after CONTAINS in derived type
184   for (const Symbol &symbol : CollectSymbols(scope)) {
185     PutSymbol(typeBindings, symbol);
186   }
187   if (auto str{typeBindings.str()}; !str.empty()) {
188     CHECK(scope.IsDerivedType());
189     decls_ << "contains\n" << str;
190   }
191 }
192 
193 // Emit a symbol to decls_, except for bindings in a derived type (type-bound
194 // procedures, type-bound generics, final procedures) which go to typeBindings.
195 void ModFileWriter::PutSymbol(
196     llvm::raw_ostream &typeBindings, const Symbol &symbol) {
197   std::visit(common::visitors{
198                  [&](const ModuleDetails &) { /* should be current module */ },
199                  [&](const DerivedTypeDetails &) { PutDerivedType(symbol); },
200                  [&](const SubprogramDetails &) { PutSubprogram(symbol); },
201                  [&](const GenericDetails &x) {
202                    if (symbol.owner().IsDerivedType()) {
203                      // generic binding
204                      for (const Symbol &proc : x.specificProcs()) {
205                        typeBindings << "generic::" << symbol.name() << "=>"
206                                     << proc.name() << '\n';
207                      }
208                    } else {
209                      PutGeneric(symbol);
210                      if (x.specific()) {
211                        PutSymbol(typeBindings, *x.specific());
212                      }
213                      if (x.derivedType()) {
214                        PutSymbol(typeBindings, *x.derivedType());
215                      }
216                    }
217                  },
218                  [&](const UseDetails &) { PutUse(symbol); },
219                  [](const UseErrorDetails &) {},
220                  [&](const ProcBindingDetails &x) {
221                    bool deferred{symbol.attrs().test(Attr::DEFERRED)};
222                    typeBindings << "procedure";
223                    if (deferred) {
224                      typeBindings << '(' << x.symbol().name() << ')';
225                    }
226                    PutPassName(typeBindings, x.passName());
227                    auto attrs{symbol.attrs()};
228                    if (x.passName()) {
229                      attrs.reset(Attr::PASS);
230                    }
231                    PutAttrs(typeBindings, attrs);
232                    typeBindings << "::" << symbol.name();
233                    if (!deferred && x.symbol().name() != symbol.name()) {
234                      typeBindings << "=>" << x.symbol().name();
235                    }
236                    typeBindings << '\n';
237                  },
238                  [&](const NamelistDetails &x) {
239                    decls_ << "namelist/" << symbol.name();
240                    char sep{'/'};
241                    for (const Symbol &object : x.objects()) {
242                      decls_ << sep << object.name();
243                      sep = ',';
244                    }
245                    decls_ << '\n';
246                  },
247                  [&](const CommonBlockDetails &x) {
248                    decls_ << "common/" << symbol.name();
249                    char sep = '/';
250                    for (const auto &object : x.objects()) {
251                      decls_ << sep << object->name();
252                      sep = ',';
253                    }
254                    decls_ << '\n';
255                    if (symbol.attrs().test(Attr::BIND_C)) {
256                      PutAttrs(decls_, symbol.attrs(), x.bindName(), ""s);
257                      decls_ << "::/" << symbol.name() << "/\n";
258                    }
259                  },
260                  [&](const FinalProcDetails &) {
261                    typeBindings << "final::" << symbol.name() << '\n';
262                  },
263                  [](const HostAssocDetails &) {},
264                  [](const MiscDetails &) {},
265                  [&](const auto &) { PutEntity(decls_, symbol); },
266              },
267       symbol.details());
268 }
269 
270 void ModFileWriter::PutDerivedType(const Symbol &typeSymbol) {
271   auto &details{typeSymbol.get<DerivedTypeDetails>()};
272   PutAttrs(decls_ << "type", typeSymbol.attrs());
273   if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) {
274     decls_ << ",extends(" << extends->name() << ')';
275   }
276   decls_ << "::" << typeSymbol.name();
277   auto &typeScope{*typeSymbol.scope()};
278   if (!details.paramNames().empty()) {
279     char sep{'('};
280     for (const auto &name : details.paramNames()) {
281       decls_ << sep << name;
282       sep = ',';
283     }
284     decls_ << ')';
285   }
286   decls_ << '\n';
287   if (details.sequence()) {
288     decls_ << "sequence\n";
289   }
290   PutSymbols(typeScope);
291   decls_ << "end type\n";
292 }
293 
294 // Attributes that may be in a subprogram prefix
295 static const Attrs subprogramPrefixAttrs{Attr::ELEMENTAL, Attr::IMPURE,
296     Attr::MODULE, Attr::NON_RECURSIVE, Attr::PURE, Attr::RECURSIVE};
297 
298 void ModFileWriter::PutSubprogram(const Symbol &symbol) {
299   auto attrs{symbol.attrs()};
300   auto &details{symbol.get<SubprogramDetails>()};
301   Attrs bindAttrs{};
302   if (attrs.test(Attr::BIND_C)) {
303     // bind(c) is a suffix, not prefix
304     bindAttrs.set(Attr::BIND_C, true);
305     attrs.set(Attr::BIND_C, false);
306   }
307   Attrs prefixAttrs{subprogramPrefixAttrs & attrs};
308   // emit any non-prefix attributes in an attribute statement
309   attrs &= ~subprogramPrefixAttrs;
310   std::string ssBuf;
311   llvm::raw_string_ostream ss{ssBuf};
312   PutAttrs(ss, attrs);
313   if (!ss.str().empty()) {
314     decls_ << ss.str().substr(1) << "::" << symbol.name() << '\n';
315   }
316   bool isInterface{details.isInterface()};
317   llvm::raw_ostream &os{isInterface ? decls_ : contains_};
318   if (isInterface) {
319     os << "interface\n";
320   }
321   PutAttrs(os, prefixAttrs, std::nullopt, ""s, " "s);
322   os << (details.isFunction() ? "function " : "subroutine ");
323   os << symbol.name() << '(';
324   int n = 0;
325   for (const auto &dummy : details.dummyArgs()) {
326     if (n++ > 0) {
327       os << ',';
328     }
329     if (dummy) {
330       os << dummy->name();
331     } else {
332       os << "*";
333     }
334   }
335   os << ')';
336   PutAttrs(os, bindAttrs, details.bindName(), " "s, ""s);
337   if (details.isFunction()) {
338     const Symbol &result{details.result()};
339     if (result.name() != symbol.name()) {
340       os << " result(" << result.name() << ')';
341     }
342   }
343   os << '\n';
344 
345   // walk symbols, collect ones needed for interface
346   const Scope &scope{
347       details.entryScope() ? *details.entryScope() : DEREF(symbol.scope())};
348   SubprogramSymbolCollector collector{symbol, scope};
349   collector.Collect();
350   std::string typeBindingsBuf;
351   llvm::raw_string_ostream typeBindings{typeBindingsBuf};
352   ModFileWriter writer{context_};
353   for (const Symbol &need : collector.symbols()) {
354     writer.PutSymbol(typeBindings, need);
355   }
356   CHECK(typeBindings.str().empty());
357   os << writer.uses_.str();
358   for (const SourceName &import : collector.imports()) {
359     decls_ << "import::" << import << "\n";
360   }
361   os << writer.decls_.str();
362   os << "end\n";
363   if (isInterface) {
364     os << "end interface\n";
365   }
366 }
367 
368 static bool IsIntrinsicOp(const Symbol &symbol) {
369   if (const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()}) {
370     return details->kind().IsIntrinsicOperator();
371   } else {
372     return false;
373   }
374 }
375 
376 static llvm::raw_ostream &PutGenericName(
377     llvm::raw_ostream &os, const Symbol &symbol) {
378   if (IsGenericDefinedOp(symbol)) {
379     return os << "operator(" << symbol.name() << ')';
380   } else {
381     return os << symbol.name();
382   }
383 }
384 
385 void ModFileWriter::PutGeneric(const Symbol &symbol) {
386   auto &details{symbol.get<GenericDetails>()};
387   PutGenericName(decls_ << "interface ", symbol) << '\n';
388   for (const Symbol &specific : details.specificProcs()) {
389     decls_ << "procedure::" << specific.name() << '\n';
390   }
391   decls_ << "end interface\n";
392   if (symbol.attrs().test(Attr::PRIVATE)) {
393     PutGenericName(decls_ << "private::", symbol) << '\n';
394   }
395 }
396 
397 void ModFileWriter::PutUse(const Symbol &symbol) {
398   auto &details{symbol.get<UseDetails>()};
399   auto &use{details.symbol()};
400   uses_ << "use " << GetUsedModule(details).name();
401   PutGenericName(uses_ << ",only:", symbol);
402   // Can have intrinsic op with different local-name and use-name
403   // (e.g. `operator(<)` and `operator(.lt.)`) but rename is not allowed
404   if (!IsIntrinsicOp(symbol) && use.name() != symbol.name()) {
405     PutGenericName(uses_ << "=>", use);
406   }
407   uses_ << '\n';
408   PutUseExtraAttr(Attr::VOLATILE, symbol, use);
409   PutUseExtraAttr(Attr::ASYNCHRONOUS, symbol, use);
410 }
411 
412 // We have "USE local => use" in this module. If attr was added locally
413 // (i.e. on local but not on use), also write it out in the mod file.
414 void ModFileWriter::PutUseExtraAttr(
415     Attr attr, const Symbol &local, const Symbol &use) {
416   if (local.attrs().test(attr) && !use.attrs().test(attr)) {
417     PutAttr(useExtraAttrs_, attr) << "::";
418     useExtraAttrs_ << local.name() << '\n';
419   }
420 }
421 
422 // Collect the symbols of this scope sorted by their original order, not name.
423 // Namelists are an exception: they are sorted after other symbols.
424 SymbolVector CollectSymbols(const Scope &scope) {
425   SymbolVector sorted;
426   SymbolVector namelist;
427   std::size_t commonSize{scope.commonBlocks().size()};
428   auto symbols{scope.GetSymbols()};
429   sorted.reserve(symbols.size() + commonSize);
430   for (SymbolRef symbol : symbols) {
431     if (!symbol->test(Symbol::Flag::ParentComp)) {
432       if (symbol->has<NamelistDetails>()) {
433         namelist.push_back(symbol);
434       } else {
435         sorted.push_back(symbol);
436       }
437     }
438   }
439   sorted.insert(sorted.end(), namelist.begin(), namelist.end());
440   for (const auto &pair : scope.commonBlocks()) {
441     sorted.push_back(*pair.second);
442   }
443   std::sort(sorted.end() - commonSize, sorted.end());
444   return sorted;
445 }
446 
447 void PutEntity(llvm::raw_ostream &os, const Symbol &symbol) {
448   std::visit(
449       common::visitors{
450           [&](const ObjectEntityDetails &) { PutObjectEntity(os, symbol); },
451           [&](const ProcEntityDetails &) { PutProcEntity(os, symbol); },
452           [&](const TypeParamDetails &) { PutTypeParam(os, symbol); },
453           [&](const auto &) {
454             common::die("PutEntity: unexpected details: %s",
455                 DetailsToString(symbol.details()).c_str());
456           },
457       },
458       symbol.details());
459 }
460 
461 void PutShapeSpec(llvm::raw_ostream &os, const ShapeSpec &x) {
462   if (x.lbound().isAssumed()) {
463     CHECK(x.ubound().isAssumed());
464     os << "..";
465   } else {
466     if (!x.lbound().isDeferred()) {
467       PutBound(os, x.lbound());
468     }
469     os << ':';
470     if (!x.ubound().isDeferred()) {
471       PutBound(os, x.ubound());
472     }
473   }
474 }
475 void PutShape(
476     llvm::raw_ostream &os, const ArraySpec &shape, char open, char close) {
477   if (!shape.empty()) {
478     os << open;
479     bool first{true};
480     for (const auto &shapeSpec : shape) {
481       if (first) {
482         first = false;
483       } else {
484         os << ',';
485       }
486       PutShapeSpec(os, shapeSpec);
487     }
488     os << close;
489   }
490 }
491 
492 void PutObjectEntity(llvm::raw_ostream &os, const Symbol &symbol) {
493   auto &details{symbol.get<ObjectEntityDetails>()};
494   PutEntity(
495       os, symbol, [&]() { PutType(os, DEREF(symbol.GetType())); },
496       symbol.attrs());
497   PutShape(os, details.shape(), '(', ')');
498   PutShape(os, details.coshape(), '[', ']');
499   PutInit(os, symbol, details.init());
500   os << '\n';
501 }
502 
503 void PutProcEntity(llvm::raw_ostream &os, const Symbol &symbol) {
504   if (symbol.attrs().test(Attr::INTRINSIC)) {
505     os << "intrinsic::" << symbol.name() << '\n';
506     return;
507   }
508   const auto &details{symbol.get<ProcEntityDetails>()};
509   const ProcInterface &interface{details.interface()};
510   Attrs attrs{symbol.attrs()};
511   if (details.passName()) {
512     attrs.reset(Attr::PASS);
513   }
514   PutEntity(
515       os, symbol,
516       [&]() {
517         os << "procedure(";
518         if (interface.symbol()) {
519           os << interface.symbol()->name();
520         } else if (interface.type()) {
521           PutType(os, *interface.type());
522         }
523         os << ')';
524         PutPassName(os, details.passName());
525       },
526       attrs);
527   os << '\n';
528 }
529 
530 void PutPassName(
531     llvm::raw_ostream &os, const std::optional<SourceName> &passName) {
532   if (passName) {
533     os << ",pass(" << *passName << ')';
534   }
535 }
536 void PutTypeParam(llvm::raw_ostream &os, const Symbol &symbol) {
537   auto &details{symbol.get<TypeParamDetails>()};
538   PutEntity(
539       os, symbol,
540       [&]() {
541         PutType(os, DEREF(symbol.GetType()));
542         PutLower(os << ',', common::EnumToString(details.attr()));
543       },
544       symbol.attrs());
545   PutInit(os, details.init());
546   os << '\n';
547 }
548 
549 void PutInit(
550     llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init) {
551   if (init) {
552     if (symbol.attrs().test(Attr::PARAMETER) ||
553         symbol.owner().IsDerivedType()) {
554       os << (symbol.attrs().test(Attr::POINTER) ? "=>" : "=");
555       init->AsFortran(os);
556     }
557   }
558 }
559 
560 void PutInit(llvm::raw_ostream &os, const MaybeIntExpr &init) {
561   if (init) {
562     init->AsFortran(os << '=');
563   }
564 }
565 
566 void PutBound(llvm::raw_ostream &os, const Bound &x) {
567   if (x.isAssumed()) {
568     os << '*';
569   } else if (x.isDeferred()) {
570     os << ':';
571   } else {
572     x.GetExplicit()->AsFortran(os);
573   }
574 }
575 
576 // Write an entity (object or procedure) declaration.
577 // writeType is called to write out the type.
578 void PutEntity(llvm::raw_ostream &os, const Symbol &symbol,
579     std::function<void()> writeType, Attrs attrs) {
580   writeType();
581   MaybeExpr bindName;
582   std::visit(common::visitors{
583                  [&](const SubprogramDetails &x) { bindName = x.bindName(); },
584                  [&](const ObjectEntityDetails &x) { bindName = x.bindName(); },
585                  [&](const ProcEntityDetails &x) { bindName = x.bindName(); },
586                  [&](const auto &) {},
587              },
588       symbol.details());
589   PutAttrs(os, attrs, bindName);
590   os << "::" << symbol.name();
591 }
592 
593 // Put out each attribute to os, surrounded by `before` and `after` and
594 // mapped to lower case.
595 llvm::raw_ostream &PutAttrs(llvm::raw_ostream &os, Attrs attrs,
596     const MaybeExpr &bindName, std::string before, std::string after) {
597   attrs.set(Attr::PUBLIC, false); // no need to write PUBLIC
598   attrs.set(Attr::EXTERNAL, false); // no need to write EXTERNAL
599   if (bindName) {
600     bindName->AsFortran(os << before << "bind(c, name=") << ')' << after;
601     attrs.set(Attr::BIND_C, false);
602   }
603   for (std::size_t i{0}; i < Attr_enumSize; ++i) {
604     Attr attr{static_cast<Attr>(i)};
605     if (attrs.test(attr)) {
606       PutAttr(os << before, attr) << after;
607     }
608   }
609   return os;
610 }
611 
612 llvm::raw_ostream &PutAttr(llvm::raw_ostream &os, Attr attr) {
613   return PutLower(os, AttrToString(attr));
614 }
615 
616 llvm::raw_ostream &PutType(llvm::raw_ostream &os, const DeclTypeSpec &type) {
617   return PutLower(os, type.AsFortran());
618 }
619 
620 llvm::raw_ostream &PutLower(llvm::raw_ostream &os, const std::string &str) {
621   for (char c : str) {
622     os << parser::ToLowerCaseLetter(c);
623   }
624   return os;
625 }
626 
627 struct Temp {
628   Temp(int fd, std::string path) : fd{fd}, path{path} {}
629   Temp(Temp &&t) : fd{std::exchange(t.fd, -1)}, path{std::move(t.path)} {}
630   ~Temp() {
631     if (fd >= 0) {
632       llvm::sys::fs::file_t native{llvm::sys::fs::convertFDToNativeFile(fd)};
633       llvm::sys::fs::closeFile(native);
634       llvm::sys::fs::remove(path.c_str());
635     }
636   }
637   int fd;
638   std::string path;
639 };
640 
641 // Create a temp file in the same directory and with the same suffix as path.
642 // Return an open file descriptor and its path.
643 static llvm::ErrorOr<Temp> MkTemp(const std::string &path) {
644   auto length{path.length()};
645   auto dot{path.find_last_of("./")};
646   std::string suffix{
647       dot < length && path[dot] == '.' ? path.substr(dot + 1) : ""};
648   CHECK(length > suffix.length() &&
649       path.substr(length - suffix.length()) == suffix);
650   auto prefix{path.substr(0, length - suffix.length())};
651   int fd;
652   llvm::SmallString<16> tempPath;
653   if (std::error_code err{llvm::sys::fs::createUniqueFile(
654           prefix + "%%%%%%" + suffix, fd, tempPath)}) {
655     return err;
656   }
657   return Temp{fd, tempPath.c_str()};
658 }
659 
660 // Write the module file at path, prepending header. If an error occurs,
661 // return errno, otherwise 0.
662 static std::error_code WriteFile(
663     const std::string &path, const std::string &contents, bool debug) {
664   auto header{std::string{ModHeader::bom} + ModHeader::magic +
665       CheckSum(contents) + ModHeader::terminator};
666   if (debug) {
667     llvm::dbgs() << "Processing module " << path << ": ";
668   }
669   if (FileContentsMatch(path, header, contents)) {
670     if (debug) {
671       llvm::dbgs() << "module unchanged, not writing\n";
672     }
673     return {};
674   }
675   llvm::ErrorOr<Temp> temp{MkTemp(path)};
676   if (!temp) {
677     return temp.getError();
678   }
679   llvm::raw_fd_ostream writer(temp->fd, /*shouldClose=*/false);
680   writer << header;
681   writer << contents;
682   writer.flush();
683   if (writer.has_error()) {
684     return writer.error();
685   }
686   if (debug) {
687     llvm::dbgs() << "module written\n";
688   }
689   return llvm::sys::fs::rename(temp->path, path);
690 }
691 
692 // Return true if the stream matches what we would write for the mod file.
693 static bool FileContentsMatch(const std::string &path,
694     const std::string &header, const std::string &contents) {
695   std::size_t hsize{header.size()};
696   std::size_t csize{contents.size()};
697   auto buf_or{llvm::MemoryBuffer::getFile(path)};
698   if (!buf_or) {
699     return false;
700   }
701   auto buf = std::move(buf_or.get());
702   if (buf->getBufferSize() != hsize + csize) {
703     return false;
704   }
705   if (!std::equal(header.begin(), header.end(), buf->getBufferStart(),
706           buf->getBufferStart() + hsize)) {
707     return false;
708   }
709 
710   return std::equal(contents.begin(), contents.end(),
711       buf->getBufferStart() + hsize, buf->getBufferEnd());
712 }
713 
714 // Compute a simple hash of the contents of a module file and
715 // return it as a string of hex digits.
716 // This uses the Fowler-Noll-Vo hash function.
717 static std::string CheckSum(const std::string_view &contents) {
718   std::uint64_t hash{0xcbf29ce484222325ull};
719   for (char c : contents) {
720     hash ^= c & 0xff;
721     hash *= 0x100000001b3;
722   }
723   static const char *digits = "0123456789abcdef";
724   std::string result(ModHeader::sumLen, '0');
725   for (size_t i{ModHeader::sumLen}; hash != 0; hash >>= 4) {
726     result[--i] = digits[hash & 0xf];
727   }
728   return result;
729 }
730 
731 static bool VerifyHeader(llvm::ArrayRef<char> content) {
732   std::string_view sv{content.data(), content.size()};
733   if (sv.substr(0, ModHeader::magicLen) != ModHeader::magic) {
734     return false;
735   }
736   std::string_view expectSum{sv.substr(ModHeader::magicLen, ModHeader::sumLen)};
737   std::string actualSum{CheckSum(sv.substr(ModHeader::len))};
738   return expectSum == actualSum;
739 }
740 
741 Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
742   std::string ancestorName; // empty for module
743   if (ancestor) {
744     if (auto *scope{ancestor->FindSubmodule(name)}) {
745       return scope;
746     }
747     ancestorName = ancestor->GetName().value().ToString();
748   } else {
749     auto it{context_.globalScope().find(name)};
750     if (it != context_.globalScope().end()) {
751       return it->second->scope();
752     }
753   }
754   parser::Parsing parsing{context_.allCookedSources()};
755   parser::Options options;
756   options.isModuleFile = true;
757   options.features.Enable(common::LanguageFeature::BackslashEscapes);
758   options.searchDirectories = context_.searchDirectories();
759   auto path{ModFileName(name, ancestorName, context_.moduleFileSuffix())};
760   const auto *sourceFile{parsing.Prescan(path, options)};
761   if (parsing.messages().AnyFatalError()) {
762     for (auto &msg : parsing.messages().messages()) {
763       std::string str{msg.ToString()};
764       Say(name, ancestorName, parser::MessageFixedText{str.c_str(), str.size()},
765           path);
766     }
767     return nullptr;
768   }
769   CHECK(sourceFile);
770   if (!VerifyHeader(sourceFile->content())) {
771     Say(name, ancestorName, "File has invalid checksum: %s"_en_US,
772         sourceFile->path());
773     return nullptr;
774   }
775   llvm::raw_null_ostream NullStream;
776   parsing.Parse(NullStream);
777   auto &parseTree{parsing.parseTree()};
778   if (!parsing.messages().empty() || !parsing.consumedWholeFile() ||
779       !parseTree) {
780     Say(name, ancestorName, "Module file is corrupt: %s"_err_en_US,
781         sourceFile->path());
782     return nullptr;
783   }
784   Scope *parentScope; // the scope this module/submodule goes into
785   if (!ancestor) {
786     parentScope = &context_.globalScope();
787   } else if (std::optional<SourceName> parent{GetSubmoduleParent(*parseTree)}) {
788     parentScope = Read(*parent, ancestor);
789   } else {
790     parentScope = ancestor;
791   }
792   ResolveNames(context_, *parseTree);
793   const auto &it{parentScope->find(name)};
794   if (it == parentScope->end()) {
795     return nullptr;
796   }
797   auto &modSymbol{*it->second};
798   modSymbol.set(Symbol::Flag::ModFile);
799   return modSymbol.scope();
800 }
801 
802 parser::Message &ModFileReader::Say(const SourceName &name,
803     const std::string &ancestor, parser::MessageFixedText &&msg,
804     const std::string &arg) {
805   return context_
806       .Say(name,
807           ancestor.empty()
808               ? "Error reading module file for module '%s'"_err_en_US
809               : "Error reading module file for submodule '%s' of module '%s'"_err_en_US,
810           name, ancestor)
811       .Attach(name, std::move(msg), arg);
812 }
813 
814 // program was read from a .mod file for a submodule; return the name of the
815 // submodule's parent submodule, nullptr if none.
816 static std::optional<SourceName> GetSubmoduleParent(
817     const parser::Program &program) {
818   CHECK(program.v.size() == 1);
819   auto &unit{program.v.front()};
820   auto &submod{std::get<common::Indirection<parser::Submodule>>(unit.u)};
821   auto &stmt{
822       std::get<parser::Statement<parser::SubmoduleStmt>>(submod.value().t)};
823   auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)};
824   if (auto &parent{std::get<std::optional<parser::Name>>(parentId.t)}) {
825     return parent->source;
826   } else {
827     return std::nullopt;
828   }
829 }
830 
831 void SubprogramSymbolCollector::Collect() {
832   const auto &details{symbol_.get<SubprogramDetails>()};
833   isInterface_ = details.isInterface();
834   for (const Symbol *dummyArg : details.dummyArgs()) {
835     if (dummyArg) {
836       DoSymbol(*dummyArg);
837     }
838   }
839   if (details.isFunction()) {
840     DoSymbol(details.result());
841   }
842   for (const auto &pair : scope_) {
843     const Symbol &symbol{*pair.second};
844     if (const auto *useDetails{symbol.detailsIf<UseDetails>()}) {
845       if (useSet_.count(useDetails->symbol().GetUltimate()) > 0) {
846         need_.push_back(symbol);
847       }
848     }
849   }
850 }
851 
852 void SubprogramSymbolCollector::DoSymbol(const Symbol &symbol) {
853   DoSymbol(symbol.name(), symbol);
854 }
855 
856 // Do symbols this one depends on; then add to need_
857 void SubprogramSymbolCollector::DoSymbol(
858     const SourceName &name, const Symbol &symbol) {
859   const auto &scope{symbol.owner()};
860   if (scope != scope_ && !scope.IsDerivedType()) {
861     if (scope != scope_.parent()) {
862       useSet_.insert(symbol);
863     }
864     if (NeedImport(name, symbol)) {
865       imports_.insert(name);
866     }
867     return;
868   }
869   if (!needSet_.insert(symbol).second) {
870     return; // already done
871   }
872   std::visit(common::visitors{
873                  [this](const ObjectEntityDetails &details) {
874                    for (const ShapeSpec &spec : details.shape()) {
875                      DoBound(spec.lbound());
876                      DoBound(spec.ubound());
877                    }
878                    for (const ShapeSpec &spec : details.coshape()) {
879                      DoBound(spec.lbound());
880                      DoBound(spec.ubound());
881                    }
882                    if (const Symbol * commonBlock{details.commonBlock()}) {
883                      DoSymbol(*commonBlock);
884                    }
885                  },
886                  [this](const CommonBlockDetails &details) {
887                    for (const auto &object : details.objects()) {
888                      DoSymbol(*object);
889                    }
890                  },
891                  [](const auto &) {},
892              },
893       symbol.details());
894   if (!symbol.has<UseDetails>()) {
895     DoType(symbol.GetType());
896   }
897   if (!scope.IsDerivedType()) {
898     need_.push_back(symbol);
899   }
900 }
901 
902 void SubprogramSymbolCollector::DoType(const DeclTypeSpec *type) {
903   if (!type) {
904     return;
905   }
906   switch (type->category()) {
907   case DeclTypeSpec::Numeric:
908   case DeclTypeSpec::Logical:
909     break; // nothing to do
910   case DeclTypeSpec::Character:
911     DoParamValue(type->characterTypeSpec().length());
912     break;
913   default:
914     if (const DerivedTypeSpec * derived{type->AsDerived()}) {
915       const auto &typeSymbol{derived->typeSymbol()};
916       if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) {
917         DoSymbol(extends->name(), extends->typeSymbol());
918       }
919       for (const auto &pair : derived->parameters()) {
920         DoParamValue(pair.second);
921       }
922       for (const auto &pair : *typeSymbol.scope()) {
923         const Symbol &comp{*pair.second};
924         DoSymbol(comp);
925       }
926       DoSymbol(derived->name(), derived->typeSymbol());
927     }
928   }
929 }
930 
931 void SubprogramSymbolCollector::DoBound(const Bound &bound) {
932   if (const MaybeSubscriptIntExpr & expr{bound.GetExplicit()}) {
933     DoExpr(*expr);
934   }
935 }
936 void SubprogramSymbolCollector::DoParamValue(const ParamValue &paramValue) {
937   if (const auto &expr{paramValue.GetExplicit()}) {
938     DoExpr(*expr);
939   }
940 }
941 
942 // Do we need a IMPORT of this symbol into an interface block?
943 bool SubprogramSymbolCollector::NeedImport(
944     const SourceName &name, const Symbol &symbol) {
945   if (!isInterface_) {
946     return false;
947   } else if (symbol.owner() != scope_.parent()) {
948     // detect import from parent of use-associated symbol
949     // can be null in the case of a use-associated derived type's parent type
950     const auto *found{scope_.FindSymbol(name)};
951     CHECK(found || symbol.has<DerivedTypeDetails>());
952     return found && found->has<UseDetails>() && found->owner() != scope_;
953   } else {
954     return true;
955   }
956 }
957 
958 } // namespace Fortran::semantics
959