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