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 };
45 
46 static std::optional<SourceName> GetSubmoduleParent(const parser::Program &);
47 static void CollectSymbols(const Scope &, SymbolVector &, SymbolVector &);
48 static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &);
49 static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &,
50     const parser::Expr *);
51 static void PutInit(llvm::raw_ostream &, const MaybeIntExpr &);
52 static void PutBound(llvm::raw_ostream &, const Bound &);
53 static void PutShapeSpec(llvm::raw_ostream &, const ShapeSpec &);
54 static void PutShape(
55     llvm::raw_ostream &, const ArraySpec &, char open, char close);
56 llvm::raw_ostream &PutAttrs(llvm::raw_ostream &, Attrs,
57     const std::string * = nullptr, std::string before = ","s,
58     std::string after = ""s);
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 &, const std::string &);
63 static std::error_code WriteFile(
64     const std::string &, const std::string &, bool = true);
65 static bool FileContentsMatch(
66     const std::string &, const std::string &, const std::string &);
67 static std::string CheckSum(const std::string_view &);
68 
69 // Collect symbols needed for a subprogram interface
70 class SubprogramSymbolCollector {
71 public:
72   SubprogramSymbolCollector(const Symbol &symbol, const Scope &scope)
73       : symbol_{symbol}, scope_{scope} {}
74   const SymbolVector &symbols() const { return need_; }
75   const std::set<SourceName> &imports() const { return imports_; }
76   void Collect();
77 
78 private:
79   const Symbol &symbol_;
80   const Scope &scope_;
81   bool isInterface_{false};
82   SymbolVector need_; // symbols that are needed
83   UnorderedSymbolSet needSet_; // symbols already in need_
84   UnorderedSymbolSet useSet_; // use-associations that might be needed
85   std::set<SourceName> imports_; // imports from host that are needed
86 
87   void DoSymbol(const Symbol &);
88   void DoSymbol(const SourceName &, const Symbol &);
89   void DoType(const DeclTypeSpec *);
90   void DoBound(const Bound &);
91   void DoParamValue(const ParamValue &);
92   bool NeedImport(const SourceName &, const Symbol &);
93 
94   template <typename T> void DoExpr(evaluate::Expr<T> expr) {
95     for (const Symbol &symbol : evaluate::CollectSymbols(expr)) {
96       DoSymbol(symbol);
97     }
98   }
99 };
100 
101 bool ModFileWriter::WriteAll() {
102   // this flag affects character literals: force it to be consistent
103   auto restorer{
104       common::ScopedSet(parser::useHexadecimalEscapeSequences, false)};
105   WriteAll(context_.globalScope());
106   return !context_.AnyFatalError();
107 }
108 
109 void ModFileWriter::WriteAll(const Scope &scope) {
110   for (const auto &child : scope.children()) {
111     WriteOne(child);
112   }
113 }
114 
115 void ModFileWriter::WriteOne(const Scope &scope) {
116   if (scope.kind() == Scope::Kind::Module) {
117     auto *symbol{scope.symbol()};
118     if (!symbol->test(Symbol::Flag::ModFile)) {
119       Write(*symbol);
120     }
121     WriteAll(scope); // write out submodules
122   }
123 }
124 
125 // Construct the name of a module file. Non-empty ancestorName means submodule.
126 static std::string ModFileName(const SourceName &name,
127     const std::string &ancestorName, const std::string &suffix) {
128   std::string result{name.ToString() + suffix};
129   return ancestorName.empty() ? result : ancestorName + '-' + result;
130 }
131 
132 // Write the module file for symbol, which must be a module or submodule.
133 void ModFileWriter::Write(const Symbol &symbol) {
134   auto *ancestor{symbol.get<ModuleDetails>().ancestor()};
135   auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s};
136   auto path{context_.moduleDirectory() + '/' +
137       ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())};
138   PutSymbols(DEREF(symbol.scope()));
139   if (std::error_code error{
140           WriteFile(path, GetAsString(symbol), context_.debugModuleWriter())}) {
141     context_.Say(
142         symbol.name(), "Error writing %s: %s"_err_en_US, path, error.message());
143   }
144 }
145 
146 // Return the entire body of the module file
147 // and clear saved uses, decls, and contains.
148 std::string ModFileWriter::GetAsString(const Symbol &symbol) {
149   std::string buf;
150   llvm::raw_string_ostream all{buf};
151   auto &details{symbol.get<ModuleDetails>()};
152   if (!details.isSubmodule()) {
153     all << "module " << symbol.name();
154   } else {
155     auto *parent{details.parent()->symbol()};
156     auto *ancestor{details.ancestor()->symbol()};
157     all << "submodule(" << ancestor->name();
158     if (parent != ancestor) {
159       all << ':' << parent->name();
160     }
161     all << ") " << symbol.name();
162   }
163   all << '\n' << uses_.str();
164   uses_.str().clear();
165   all << useExtraAttrs_.str();
166   useExtraAttrs_.str().clear();
167   all << decls_.str();
168   decls_.str().clear();
169   auto str{contains_.str()};
170   contains_.str().clear();
171   if (!str.empty()) {
172     all << "contains\n" << str;
173   }
174   all << "end\n";
175   return all.str();
176 }
177 
178 // Put out the visible symbols from scope.
179 void ModFileWriter::PutSymbols(const Scope &scope) {
180   SymbolVector sorted;
181   SymbolVector uses;
182   CollectSymbols(scope, sorted, uses);
183   std::string buf; // stuff after CONTAINS in derived type
184   llvm::raw_string_ostream typeBindings{buf};
185   for (const Symbol &symbol : sorted) {
186     if (!symbol.test(Symbol::Flag::CompilerCreated)) {
187       PutSymbol(typeBindings, symbol);
188     }
189   }
190   for (const Symbol &symbol : uses) {
191     PutUse(symbol);
192   }
193   for (const auto &set : scope.equivalenceSets()) {
194     if (!set.empty() &&
195         !set.front().symbol.test(Symbol::Flag::CompilerCreated)) {
196       char punctuation{'('};
197       decls_ << "equivalence";
198       for (const auto &object : set) {
199         decls_ << punctuation << object.AsFortran();
200         punctuation = ',';
201       }
202       decls_ << ")\n";
203     }
204   }
205   CHECK(typeBindings.str().empty());
206 }
207 
208 // Emit components in order
209 bool ModFileWriter::PutComponents(const Symbol &typeSymbol) {
210   const auto &scope{DEREF(typeSymbol.scope())};
211   std::string buf; // stuff after CONTAINS in derived type
212   llvm::raw_string_ostream typeBindings{buf};
213   UnorderedSymbolSet emitted;
214   SymbolVector symbols{scope.GetSymbols()};
215   // Emit type parameters first
216   for (const Symbol &symbol : symbols) {
217     if (symbol.has<TypeParamDetails>()) {
218       PutSymbol(typeBindings, symbol);
219       emitted.emplace(symbol);
220     }
221   }
222   // Emit components in component order.
223   const auto &details{typeSymbol.get<DerivedTypeDetails>()};
224   for (SourceName name : details.componentNames()) {
225     auto iter{scope.find(name)};
226     if (iter != scope.end()) {
227       const Symbol &component{*iter->second};
228       if (!component.test(Symbol::Flag::ParentComp)) {
229         PutSymbol(typeBindings, component);
230       }
231       emitted.emplace(component);
232     }
233   }
234   // Emit remaining symbols from the type's scope
235   for (const Symbol &symbol : symbols) {
236     if (emitted.find(symbol) == emitted.end()) {
237       PutSymbol(typeBindings, symbol);
238     }
239   }
240   if (auto str{typeBindings.str()}; !str.empty()) {
241     CHECK(scope.IsDerivedType());
242     decls_ << "contains\n" << str;
243     return true;
244   } else {
245     return false;
246   }
247 }
248 
249 static llvm::raw_ostream &PutGenericName(
250     llvm::raw_ostream &os, const Symbol &symbol) {
251   if (IsGenericDefinedOp(symbol)) {
252     return os << "operator(" << symbol.name() << ')';
253   } else {
254     return os << symbol.name();
255   }
256 }
257 
258 // Emit a symbol to decls_, except for bindings in a derived type (type-bound
259 // procedures, type-bound generics, final procedures) which go to typeBindings.
260 void ModFileWriter::PutSymbol(
261     llvm::raw_ostream &typeBindings, const Symbol &symbol) {
262   common::visit(
263       common::visitors{
264           [&](const ModuleDetails &) { /* should be current module */ },
265           [&](const DerivedTypeDetails &) { PutDerivedType(symbol); },
266           [&](const SubprogramDetails &) { PutSubprogram(symbol); },
267           [&](const GenericDetails &x) {
268             if (symbol.owner().IsDerivedType()) {
269               // generic binding
270               for (const Symbol &proc : x.specificProcs()) {
271                 PutGenericName(typeBindings << "generic::", symbol)
272                     << "=>" << proc.name() << '\n';
273               }
274             } else {
275               PutGeneric(symbol);
276               if (x.specific()) {
277                 PutSymbol(typeBindings, *x.specific());
278               }
279               if (x.derivedType()) {
280                 PutSymbol(typeBindings, *x.derivedType());
281               }
282             }
283           },
284           [&](const UseDetails &) { PutUse(symbol); },
285           [](const UseErrorDetails &) {},
286           [&](const ProcBindingDetails &x) {
287             bool deferred{symbol.attrs().test(Attr::DEFERRED)};
288             typeBindings << "procedure";
289             if (deferred) {
290               typeBindings << '(' << x.symbol().name() << ')';
291             }
292             PutPassName(typeBindings, x.passName());
293             auto attrs{symbol.attrs()};
294             if (x.passName()) {
295               attrs.reset(Attr::PASS);
296             }
297             PutAttrs(typeBindings, attrs);
298             typeBindings << "::" << symbol.name();
299             if (!deferred && x.symbol().name() != symbol.name()) {
300               typeBindings << "=>" << x.symbol().name();
301             }
302             typeBindings << '\n';
303           },
304           [&](const NamelistDetails &x) {
305             decls_ << "namelist/" << symbol.name();
306             char sep{'/'};
307             for (const Symbol &object : x.objects()) {
308               decls_ << sep << object.name();
309               sep = ',';
310             }
311             decls_ << '\n';
312           },
313           [&](const CommonBlockDetails &x) {
314             decls_ << "common/" << symbol.name();
315             char sep = '/';
316             for (const auto &object : x.objects()) {
317               decls_ << sep << object->name();
318               sep = ',';
319             }
320             decls_ << '\n';
321             if (symbol.attrs().test(Attr::BIND_C)) {
322               PutAttrs(decls_, symbol.attrs(), x.bindName(), ""s);
323               decls_ << "::/" << symbol.name() << "/\n";
324             }
325           },
326           [](const HostAssocDetails &) {},
327           [](const MiscDetails &) {},
328           [&](const auto &) {
329             PutEntity(decls_, symbol);
330             if (symbol.test(Symbol::Flag::OmpThreadprivate)) {
331               decls_ << "!$omp threadprivate(" << symbol.name() << ")\n";
332             }
333           },
334       },
335       symbol.details());
336 }
337 
338 void ModFileWriter::PutDerivedType(
339     const Symbol &typeSymbol, const Scope *scope) {
340   auto &details{typeSymbol.get<DerivedTypeDetails>()};
341   if (details.isDECStructure()) {
342     PutDECStructure(typeSymbol, scope);
343     return;
344   }
345   PutAttrs(decls_ << "type", typeSymbol.attrs());
346   if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) {
347     decls_ << ",extends(" << extends->name() << ')';
348   }
349   decls_ << "::" << typeSymbol.name();
350   if (!details.paramNames().empty()) {
351     char sep{'('};
352     for (const auto &name : details.paramNames()) {
353       decls_ << sep << name;
354       sep = ',';
355     }
356     decls_ << ')';
357   }
358   decls_ << '\n';
359   if (details.sequence()) {
360     decls_ << "sequence\n";
361   }
362   bool contains{PutComponents(typeSymbol)};
363   if (!details.finals().empty()) {
364     const char *sep{contains ? "final::" : "contains\nfinal::"};
365     for (const auto &pair : details.finals()) {
366       decls_ << sep << pair.second->name();
367       sep = ",";
368     }
369     if (*sep == ',') {
370       decls_ << '\n';
371     }
372   }
373   decls_ << "end type\n";
374 }
375 
376 void ModFileWriter::PutDECStructure(
377     const Symbol &typeSymbol, const Scope *scope) {
378   if (emittedDECStructures_.find(typeSymbol) != emittedDECStructures_.end()) {
379     return;
380   }
381   if (!scope && context_.IsTempName(typeSymbol.name().ToString())) {
382     return; // defer until used
383   }
384   emittedDECStructures_.insert(typeSymbol);
385   decls_ << "structure ";
386   if (!context_.IsTempName(typeSymbol.name().ToString())) {
387     decls_ << typeSymbol.name();
388   }
389   if (scope && scope->kind() == Scope::Kind::DerivedType) {
390     // Nested STRUCTURE: emit entity declarations right now
391     // on the STRUCTURE statement.
392     bool any{false};
393     for (const auto &ref : scope->GetSymbols()) {
394       const auto *object{ref->detailsIf<ObjectEntityDetails>()};
395       if (object && object->type() &&
396           object->type()->category() == DeclTypeSpec::TypeDerived &&
397           &object->type()->derivedTypeSpec().typeSymbol() == &typeSymbol) {
398         if (any) {
399           decls_ << ',';
400         } else {
401           any = true;
402         }
403         decls_ << ref->name();
404         PutShape(decls_, object->shape(), '(', ')');
405         PutInit(decls_, *ref, object->init(), nullptr);
406         emittedDECFields_.insert(*ref);
407       } else if (any) {
408         break; // any later use of this structure will use RECORD/str/
409       }
410     }
411   }
412   decls_ << '\n';
413   PutComponents(typeSymbol);
414   decls_ << "end structure\n";
415 }
416 
417 // Attributes that may be in a subprogram prefix
418 static const Attrs subprogramPrefixAttrs{Attr::ELEMENTAL, Attr::IMPURE,
419     Attr::MODULE, Attr::NON_RECURSIVE, Attr::PURE, Attr::RECURSIVE};
420 
421 void ModFileWriter::PutSubprogram(const Symbol &symbol) {
422   auto attrs{symbol.attrs()};
423   auto &details{symbol.get<SubprogramDetails>()};
424   Attrs bindAttrs{};
425   if (attrs.test(Attr::BIND_C)) {
426     // bind(c) is a suffix, not prefix
427     bindAttrs.set(Attr::BIND_C, true);
428     attrs.set(Attr::BIND_C, false);
429   }
430   bool isAbstract{attrs.test(Attr::ABSTRACT)};
431   if (isAbstract) {
432     attrs.set(Attr::ABSTRACT, false);
433   }
434   Attrs prefixAttrs{subprogramPrefixAttrs & attrs};
435   // emit any non-prefix attributes in an attribute statement
436   attrs &= ~subprogramPrefixAttrs;
437   std::string ssBuf;
438   llvm::raw_string_ostream ss{ssBuf};
439   PutAttrs(ss, attrs);
440   if (!ss.str().empty()) {
441     decls_ << ss.str().substr(1) << "::" << symbol.name() << '\n';
442   }
443   bool isInterface{details.isInterface()};
444   llvm::raw_ostream &os{isInterface ? decls_ : contains_};
445   if (isInterface) {
446     os << (isAbstract ? "abstract " : "") << "interface\n";
447   }
448   PutAttrs(os, prefixAttrs, nullptr, ""s, " "s);
449   os << (details.isFunction() ? "function " : "subroutine ");
450   os << symbol.name() << '(';
451   int n = 0;
452   for (const auto &dummy : details.dummyArgs()) {
453     if (n++ > 0) {
454       os << ',';
455     }
456     if (dummy) {
457       os << dummy->name();
458     } else {
459       os << "*";
460     }
461   }
462   os << ')';
463   PutAttrs(os, bindAttrs, details.bindName(), " "s, ""s);
464   if (details.isFunction()) {
465     const Symbol &result{details.result()};
466     if (result.name() != symbol.name()) {
467       os << " result(" << result.name() << ')';
468     }
469   }
470   os << '\n';
471 
472   // walk symbols, collect ones needed for interface
473   const Scope &scope{
474       details.entryScope() ? *details.entryScope() : DEREF(symbol.scope())};
475   SubprogramSymbolCollector collector{symbol, scope};
476   collector.Collect();
477   std::string typeBindingsBuf;
478   llvm::raw_string_ostream typeBindings{typeBindingsBuf};
479   ModFileWriter writer{context_};
480   for (const Symbol &need : collector.symbols()) {
481     writer.PutSymbol(typeBindings, need);
482   }
483   CHECK(typeBindings.str().empty());
484   os << writer.uses_.str();
485   for (const SourceName &import : collector.imports()) {
486     decls_ << "import::" << import << "\n";
487   }
488   os << writer.decls_.str();
489   os << "end\n";
490   if (isInterface) {
491     os << "end interface\n";
492   }
493 }
494 
495 static bool IsIntrinsicOp(const Symbol &symbol) {
496   if (const auto *details{symbol.GetUltimate().detailsIf<GenericDetails>()}) {
497     return details->kind().IsIntrinsicOperator();
498   } else {
499     return false;
500   }
501 }
502 
503 void ModFileWriter::PutGeneric(const Symbol &symbol) {
504   const auto &genericOwner{symbol.owner()};
505   auto &details{symbol.get<GenericDetails>()};
506   PutGenericName(decls_ << "interface ", symbol) << '\n';
507   for (const Symbol &specific : details.specificProcs()) {
508     if (specific.owner() == genericOwner) {
509       decls_ << "procedure::" << specific.name() << '\n';
510     }
511   }
512   decls_ << "end interface\n";
513   if (symbol.attrs().test(Attr::PRIVATE)) {
514     PutGenericName(decls_ << "private::", symbol) << '\n';
515   }
516 }
517 
518 void ModFileWriter::PutUse(const Symbol &symbol) {
519   auto &details{symbol.get<UseDetails>()};
520   auto &use{details.symbol()};
521   const Symbol &module{GetUsedModule(details)};
522   if (use.owner().parent().IsIntrinsicModules()) {
523     uses_ << "use,intrinsic::";
524   } else {
525     uses_ << "use ";
526   }
527   uses_ << module.name() << ",only:";
528   PutGenericName(uses_, symbol);
529   // Can have intrinsic op with different local-name and use-name
530   // (e.g. `operator(<)` and `operator(.lt.)`) but rename is not allowed
531   if (!IsIntrinsicOp(symbol) && use.name() != symbol.name()) {
532     PutGenericName(uses_ << "=>", use);
533   }
534   uses_ << '\n';
535   PutUseExtraAttr(Attr::VOLATILE, symbol, use);
536   PutUseExtraAttr(Attr::ASYNCHRONOUS, symbol, use);
537   if (symbol.attrs().test(Attr::PRIVATE)) {
538     PutGenericName(useExtraAttrs_ << "private::", symbol) << '\n';
539   }
540 }
541 
542 // We have "USE local => use" in this module. If attr was added locally
543 // (i.e. on local but not on use), also write it out in the mod file.
544 void ModFileWriter::PutUseExtraAttr(
545     Attr attr, const Symbol &local, const Symbol &use) {
546   if (local.attrs().test(attr) && !use.attrs().test(attr)) {
547     PutAttr(useExtraAttrs_, attr) << "::";
548     useExtraAttrs_ << local.name() << '\n';
549   }
550 }
551 
552 // When a generic interface has the same name as a derived type
553 // in the same scope, the generic shadows the derived type.
554 // If the derived type were declared first, emit the generic
555 // interface at the position of derived type's declaration.
556 // (ReplaceName() is not used for this purpose because doing so
557 // would confusingly position error messages pertaining to the generic
558 // interface upon the derived type's declaration.)
559 static inline SourceName NameInModuleFile(const Symbol &symbol) {
560   if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
561     if (const auto *derivedTypeOverload{generic->derivedType()}) {
562       if (derivedTypeOverload->name().begin() < symbol.name().begin()) {
563         return derivedTypeOverload->name();
564       }
565     }
566   } else if (const auto *use{symbol.detailsIf<UseDetails>()}) {
567     if (use->symbol().attrs().test(Attr::PRIVATE)) {
568       // Avoid the use in sorting of names created to access private
569       // specific procedures as a result of generic resolution;
570       // they're not in the cooked source.
571       return use->symbol().name();
572     }
573   }
574   return symbol.name();
575 }
576 
577 // Collect the symbols of this scope sorted by their original order, not name.
578 // Namelists are an exception: they are sorted after other symbols.
579 void CollectSymbols(
580     const Scope &scope, SymbolVector &sorted, SymbolVector &uses) {
581   SymbolVector namelist;
582   std::size_t commonSize{scope.commonBlocks().size()};
583   auto symbols{scope.GetSymbols()};
584   sorted.reserve(symbols.size() + commonSize);
585   for (SymbolRef symbol : symbols) {
586     if (!symbol->test(Symbol::Flag::ParentComp)) {
587       if (symbol->has<NamelistDetails>()) {
588         namelist.push_back(symbol);
589       } else {
590         sorted.push_back(symbol);
591       }
592       if (const auto *details{symbol->detailsIf<GenericDetails>()}) {
593         uses.insert(uses.end(), details->uses().begin(), details->uses().end());
594       }
595     }
596   }
597   // Sort most symbols by name: use of Symbol::ReplaceName ensures the source
598   // location of a symbol's name is the first "real" use.
599   std::sort(sorted.begin(), sorted.end(), [](SymbolRef x, SymbolRef y) {
600     return NameInModuleFile(x).begin() < NameInModuleFile(y).begin();
601   });
602   sorted.insert(sorted.end(), namelist.begin(), namelist.end());
603   for (const auto &pair : scope.commonBlocks()) {
604     sorted.push_back(*pair.second);
605   }
606   std::sort(
607       sorted.end() - commonSize, sorted.end(), SymbolSourcePositionCompare{});
608 }
609 
610 void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol) {
611   common::visit(
612       common::visitors{
613           [&](const ObjectEntityDetails &) { PutObjectEntity(os, symbol); },
614           [&](const ProcEntityDetails &) { PutProcEntity(os, symbol); },
615           [&](const TypeParamDetails &) { PutTypeParam(os, symbol); },
616           [&](const auto &) {
617             common::die("PutEntity: unexpected details: %s",
618                 DetailsToString(symbol.details()).c_str());
619           },
620       },
621       symbol.details());
622 }
623 
624 void PutShapeSpec(llvm::raw_ostream &os, const ShapeSpec &x) {
625   if (x.lbound().isStar()) {
626     CHECK(x.ubound().isStar());
627     os << ".."; // assumed rank
628   } else {
629     if (!x.lbound().isColon()) {
630       PutBound(os, x.lbound());
631     }
632     os << ':';
633     if (!x.ubound().isColon()) {
634       PutBound(os, x.ubound());
635     }
636   }
637 }
638 void PutShape(
639     llvm::raw_ostream &os, const ArraySpec &shape, char open, char close) {
640   if (!shape.empty()) {
641     os << open;
642     bool first{true};
643     for (const auto &shapeSpec : shape) {
644       if (first) {
645         first = false;
646       } else {
647         os << ',';
648       }
649       PutShapeSpec(os, shapeSpec);
650     }
651     os << close;
652   }
653 }
654 
655 void ModFileWriter::PutObjectEntity(
656     llvm::raw_ostream &os, const Symbol &symbol) {
657   auto &details{symbol.get<ObjectEntityDetails>()};
658   if (details.type() &&
659       details.type()->category() == DeclTypeSpec::TypeDerived) {
660     const Symbol &typeSymbol{details.type()->derivedTypeSpec().typeSymbol()};
661     if (typeSymbol.get<DerivedTypeDetails>().isDECStructure()) {
662       PutDerivedType(typeSymbol, &symbol.owner());
663       if (emittedDECFields_.find(symbol) != emittedDECFields_.end()) {
664         return; // symbol was emitted on STRUCTURE statement
665       }
666     }
667   }
668   PutEntity(
669       os, symbol, [&]() { PutType(os, DEREF(symbol.GetType())); },
670       symbol.attrs());
671   PutShape(os, details.shape(), '(', ')');
672   PutShape(os, details.coshape(), '[', ']');
673   PutInit(os, symbol, details.init(), details.unanalyzedPDTComponentInit());
674   os << '\n';
675 }
676 
677 void ModFileWriter::PutProcEntity(llvm::raw_ostream &os, const Symbol &symbol) {
678   if (symbol.attrs().test(Attr::INTRINSIC)) {
679     os << "intrinsic::" << symbol.name() << '\n';
680     if (symbol.attrs().test(Attr::PRIVATE)) {
681       os << "private::" << symbol.name() << '\n';
682     }
683     return;
684   }
685   const auto &details{symbol.get<ProcEntityDetails>()};
686   const ProcInterface &interface{details.interface()};
687   Attrs attrs{symbol.attrs()};
688   if (details.passName()) {
689     attrs.reset(Attr::PASS);
690   }
691   PutEntity(
692       os, symbol,
693       [&]() {
694         os << "procedure(";
695         if (interface.symbol()) {
696           os << interface.symbol()->name();
697         } else if (interface.type()) {
698           PutType(os, *interface.type());
699         }
700         os << ')';
701         PutPassName(os, details.passName());
702       },
703       attrs);
704   os << '\n';
705 }
706 
707 void PutPassName(
708     llvm::raw_ostream &os, const std::optional<SourceName> &passName) {
709   if (passName) {
710     os << ",pass(" << *passName << ')';
711   }
712 }
713 
714 void ModFileWriter::PutTypeParam(llvm::raw_ostream &os, const Symbol &symbol) {
715   auto &details{symbol.get<TypeParamDetails>()};
716   PutEntity(
717       os, symbol,
718       [&]() {
719         PutType(os, DEREF(symbol.GetType()));
720         PutLower(os << ',', common::EnumToString(details.attr()));
721       },
722       symbol.attrs());
723   PutInit(os, details.init());
724   os << '\n';
725 }
726 
727 void PutInit(llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init,
728     const parser::Expr *unanalyzed) {
729   if (symbol.attrs().test(Attr::PARAMETER) || symbol.owner().IsDerivedType()) {
730     const char *assign{symbol.attrs().test(Attr::POINTER) ? "=>" : "="};
731     if (unanalyzed) {
732       parser::Unparse(os << assign, *unanalyzed);
733     } else if (init) {
734       init->AsFortran(os << assign);
735     }
736   }
737 }
738 
739 void PutInit(llvm::raw_ostream &os, const MaybeIntExpr &init) {
740   if (init) {
741     init->AsFortran(os << '=');
742   }
743 }
744 
745 void PutBound(llvm::raw_ostream &os, const Bound &x) {
746   if (x.isStar()) {
747     os << '*';
748   } else if (x.isColon()) {
749     os << ':';
750   } else {
751     x.GetExplicit()->AsFortran(os);
752   }
753 }
754 
755 // Write an entity (object or procedure) declaration.
756 // writeType is called to write out the type.
757 void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol,
758     std::function<void()> writeType, Attrs attrs) {
759   writeType();
760   PutAttrs(os, attrs, symbol.GetBindName());
761   if (symbol.owner().kind() == Scope::Kind::DerivedType &&
762       context_.IsTempName(symbol.name().ToString())) {
763     os << "::%FILL";
764   } else {
765     os << "::" << symbol.name();
766   }
767 }
768 
769 // Put out each attribute to os, surrounded by `before` and `after` and
770 // mapped to lower case.
771 llvm::raw_ostream &PutAttrs(llvm::raw_ostream &os, Attrs attrs,
772     const std::string *bindName, std::string before, std::string after) {
773   attrs.set(Attr::PUBLIC, false); // no need to write PUBLIC
774   attrs.set(Attr::EXTERNAL, false); // no need to write EXTERNAL
775   if (bindName) {
776     os << before << "bind(c, name=\"" << *bindName << "\")" << after;
777     attrs.set(Attr::BIND_C, false);
778   }
779   for (std::size_t i{0}; i < Attr_enumSize; ++i) {
780     Attr attr{static_cast<Attr>(i)};
781     if (attrs.test(attr)) {
782       PutAttr(os << before, attr) << after;
783     }
784   }
785   return os;
786 }
787 
788 llvm::raw_ostream &PutAttr(llvm::raw_ostream &os, Attr attr) {
789   return PutLower(os, AttrToString(attr));
790 }
791 
792 llvm::raw_ostream &PutType(llvm::raw_ostream &os, const DeclTypeSpec &type) {
793   return PutLower(os, type.AsFortran());
794 }
795 
796 llvm::raw_ostream &PutLower(llvm::raw_ostream &os, const std::string &str) {
797   for (char c : str) {
798     os << parser::ToLowerCaseLetter(c);
799   }
800   return os;
801 }
802 
803 struct Temp {
804   Temp(int fd, std::string path) : fd{fd}, path{path} {}
805   Temp(Temp &&t) : fd{std::exchange(t.fd, -1)}, path{std::move(t.path)} {}
806   ~Temp() {
807     if (fd >= 0) {
808       llvm::sys::fs::file_t native{llvm::sys::fs::convertFDToNativeFile(fd)};
809       llvm::sys::fs::closeFile(native);
810       llvm::sys::fs::remove(path.c_str());
811     }
812   }
813   int fd;
814   std::string path;
815 };
816 
817 // Create a temp file in the same directory and with the same suffix as path.
818 // Return an open file descriptor and its path.
819 static llvm::ErrorOr<Temp> MkTemp(const std::string &path) {
820   auto length{path.length()};
821   auto dot{path.find_last_of("./")};
822   std::string suffix{
823       dot < length && path[dot] == '.' ? path.substr(dot + 1) : ""};
824   CHECK(length > suffix.length() &&
825       path.substr(length - suffix.length()) == suffix);
826   auto prefix{path.substr(0, length - suffix.length())};
827   int fd;
828   llvm::SmallString<16> tempPath;
829   if (std::error_code err{llvm::sys::fs::createUniqueFile(
830           prefix + "%%%%%%" + suffix, fd, tempPath)}) {
831     return err;
832   }
833   return Temp{fd, tempPath.c_str()};
834 }
835 
836 // Write the module file at path, prepending header. If an error occurs,
837 // return errno, otherwise 0.
838 static std::error_code WriteFile(
839     const std::string &path, const std::string &contents, bool debug) {
840   auto header{std::string{ModHeader::bom} + ModHeader::magic +
841       CheckSum(contents) + ModHeader::terminator};
842   if (debug) {
843     llvm::dbgs() << "Processing module " << path << ": ";
844   }
845   if (FileContentsMatch(path, header, contents)) {
846     if (debug) {
847       llvm::dbgs() << "module unchanged, not writing\n";
848     }
849     return {};
850   }
851   llvm::ErrorOr<Temp> temp{MkTemp(path)};
852   if (!temp) {
853     return temp.getError();
854   }
855   llvm::raw_fd_ostream writer(temp->fd, /*shouldClose=*/false);
856   writer << header;
857   writer << contents;
858   writer.flush();
859   if (writer.has_error()) {
860     return writer.error();
861   }
862   if (debug) {
863     llvm::dbgs() << "module written\n";
864   }
865   return llvm::sys::fs::rename(temp->path, path);
866 }
867 
868 // Return true if the stream matches what we would write for the mod file.
869 static bool FileContentsMatch(const std::string &path,
870     const std::string &header, const std::string &contents) {
871   std::size_t hsize{header.size()};
872   std::size_t csize{contents.size()};
873   auto buf_or{llvm::MemoryBuffer::getFile(path)};
874   if (!buf_or) {
875     return false;
876   }
877   auto buf = std::move(buf_or.get());
878   if (buf->getBufferSize() != hsize + csize) {
879     return false;
880   }
881   if (!std::equal(header.begin(), header.end(), buf->getBufferStart(),
882           buf->getBufferStart() + hsize)) {
883     return false;
884   }
885 
886   return std::equal(contents.begin(), contents.end(),
887       buf->getBufferStart() + hsize, buf->getBufferEnd());
888 }
889 
890 // Compute a simple hash of the contents of a module file and
891 // return it as a string of hex digits.
892 // This uses the Fowler-Noll-Vo hash function.
893 static std::string CheckSum(const std::string_view &contents) {
894   std::uint64_t hash{0xcbf29ce484222325ull};
895   for (char c : contents) {
896     hash ^= c & 0xff;
897     hash *= 0x100000001b3;
898   }
899   static const char *digits = "0123456789abcdef";
900   std::string result(ModHeader::sumLen, '0');
901   for (size_t i{ModHeader::sumLen}; hash != 0; hash >>= 4) {
902     result[--i] = digits[hash & 0xf];
903   }
904   return result;
905 }
906 
907 static bool VerifyHeader(llvm::ArrayRef<char> content) {
908   std::string_view sv{content.data(), content.size()};
909   if (sv.substr(0, ModHeader::magicLen) != ModHeader::magic) {
910     return false;
911   }
912   std::string_view expectSum{sv.substr(ModHeader::magicLen, ModHeader::sumLen)};
913   std::string actualSum{CheckSum(sv.substr(ModHeader::len))};
914   return expectSum == actualSum;
915 }
916 
917 Scope *ModFileReader::Read(const SourceName &name,
918     std::optional<bool> isIntrinsic, Scope *ancestor, bool silent) {
919   std::string ancestorName; // empty for module
920   Symbol *notAModule{nullptr};
921   bool fatalError{false};
922   if (ancestor) {
923     if (auto *scope{ancestor->FindSubmodule(name)}) {
924       return scope;
925     }
926     ancestorName = ancestor->GetName().value().ToString();
927   } else {
928     if (!isIntrinsic.value_or(false)) {
929       auto it{context_.globalScope().find(name)};
930       if (it != context_.globalScope().end()) {
931         Scope *scope{it->second->scope()};
932         if (scope->kind() == Scope::Kind::Module) {
933           return scope;
934         } else {
935           notAModule = scope->symbol();
936           // USE, NON_INTRINSIC global name isn't a module?
937           fatalError = isIntrinsic.has_value();
938         }
939       }
940     }
941     if (isIntrinsic.value_or(true)) {
942       auto it{context_.intrinsicModulesScope().find(name)};
943       if (it != context_.intrinsicModulesScope().end()) {
944         return it->second->scope();
945       }
946     }
947   }
948   parser::Parsing parsing{context_.allCookedSources()};
949   parser::Options options;
950   options.isModuleFile = true;
951   options.features.Enable(common::LanguageFeature::BackslashEscapes);
952   options.features.Enable(common::LanguageFeature::OpenMP);
953   if (!isIntrinsic.value_or(false) && !notAModule) {
954     // Scan non-intrinsic module directories
955     options.searchDirectories = context_.searchDirectories();
956     // If a directory is in both lists, the intrinsic module directory
957     // takes precedence.
958     for (const auto &dir : context_.intrinsicModuleDirectories()) {
959       std::remove(options.searchDirectories.begin(),
960           options.searchDirectories.end(), dir);
961     }
962     options.searchDirectories.insert(options.searchDirectories.begin(), "."s);
963   }
964   if (isIntrinsic.value_or(true)) {
965     for (const auto &dir : context_.intrinsicModuleDirectories()) {
966       options.searchDirectories.push_back(dir);
967     }
968   }
969   auto path{ModFileName(name, ancestorName, context_.moduleFileSuffix())};
970   const auto *sourceFile{fatalError ? nullptr : parsing.Prescan(path, options)};
971   if (fatalError || parsing.messages().AnyFatalError()) {
972     if (!silent) {
973       if (notAModule) {
974         // Module is not explicitly INTRINSIC, and there's already a global
975         // symbol of the same name that is not a module.
976         context_.SayWithDecl(
977             *notAModule, name, "'%s' is not a module"_err_en_US, name);
978       } else {
979         for (auto &msg : parsing.messages().messages()) {
980           std::string str{msg.ToString()};
981           Say(name, ancestorName,
982               parser::MessageFixedText{str.c_str(), str.size(), msg.severity()},
983               path);
984         }
985       }
986     }
987     return nullptr;
988   }
989   CHECK(sourceFile);
990   if (!VerifyHeader(sourceFile->content())) {
991     Say(name, ancestorName, "File has invalid checksum: %s"_warn_en_US,
992         sourceFile->path());
993     return nullptr;
994   }
995   llvm::raw_null_ostream NullStream;
996   parsing.Parse(NullStream);
997   std::optional<parser::Program> &parsedProgram{parsing.parseTree()};
998   if (!parsing.messages().empty() || !parsing.consumedWholeFile() ||
999       !parsedProgram) {
1000     Say(name, ancestorName, "Module file is corrupt: %s"_err_en_US,
1001         sourceFile->path());
1002     return nullptr;
1003   }
1004   parser::Program &parseTree{context_.SaveParseTree(std::move(*parsedProgram))};
1005   Scope *parentScope; // the scope this module/submodule goes into
1006   if (!isIntrinsic.has_value()) {
1007     for (const auto &dir : context_.intrinsicModuleDirectories()) {
1008       if (sourceFile->path().size() > dir.size() &&
1009           sourceFile->path().find(dir) == 0) {
1010         isIntrinsic = true;
1011         break;
1012       }
1013     }
1014   }
1015   Scope &topScope{isIntrinsic.value_or(false) ? context_.intrinsicModulesScope()
1016                                               : context_.globalScope()};
1017   if (!ancestor) {
1018     parentScope = &topScope;
1019   } else if (std::optional<SourceName> parent{GetSubmoduleParent(parseTree)}) {
1020     parentScope = Read(*parent, false /*not intrinsic*/, ancestor, silent);
1021   } else {
1022     parentScope = ancestor;
1023   }
1024   auto pair{parentScope->try_emplace(name, UnknownDetails{})};
1025   if (!pair.second) {
1026     return nullptr;
1027   }
1028   // Process declarations from the module file
1029   Symbol &modSymbol{*pair.first->second};
1030   modSymbol.set(Symbol::Flag::ModFile);
1031   bool wasInModuleFile{context_.foldingContext().inModuleFile()};
1032   context_.foldingContext().set_inModuleFile(true);
1033   ResolveNames(context_, parseTree, topScope);
1034   context_.foldingContext().set_inModuleFile(wasInModuleFile);
1035   CHECK(modSymbol.has<ModuleDetails>());
1036   CHECK(modSymbol.test(Symbol::Flag::ModFile));
1037   if (isIntrinsic.value_or(false)) {
1038     modSymbol.attrs().set(Attr::INTRINSIC);
1039   }
1040   return modSymbol.scope();
1041 }
1042 
1043 parser::Message &ModFileReader::Say(const SourceName &name,
1044     const std::string &ancestor, parser::MessageFixedText &&msg,
1045     const std::string &arg) {
1046   return context_.Say(name, "Cannot read module file for %s: %s"_err_en_US,
1047       parser::MessageFormattedText{ancestor.empty()
1048               ? "module '%s'"_en_US
1049               : "submodule '%s' of module '%s'"_en_US,
1050           name, ancestor}
1051           .MoveString(),
1052       parser::MessageFormattedText{std::move(msg), arg}.MoveString());
1053 }
1054 
1055 // program was read from a .mod file for a submodule; return the name of the
1056 // submodule's parent submodule, nullptr if none.
1057 static std::optional<SourceName> GetSubmoduleParent(
1058     const parser::Program &program) {
1059   CHECK(program.v.size() == 1);
1060   auto &unit{program.v.front()};
1061   auto &submod{std::get<common::Indirection<parser::Submodule>>(unit.u)};
1062   auto &stmt{
1063       std::get<parser::Statement<parser::SubmoduleStmt>>(submod.value().t)};
1064   auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)};
1065   if (auto &parent{std::get<std::optional<parser::Name>>(parentId.t)}) {
1066     return parent->source;
1067   } else {
1068     return std::nullopt;
1069   }
1070 }
1071 
1072 void SubprogramSymbolCollector::Collect() {
1073   const auto &details{symbol_.get<SubprogramDetails>()};
1074   isInterface_ = details.isInterface();
1075   for (const Symbol *dummyArg : details.dummyArgs()) {
1076     if (dummyArg) {
1077       DoSymbol(*dummyArg);
1078     }
1079   }
1080   if (details.isFunction()) {
1081     DoSymbol(details.result());
1082   }
1083   for (const auto &pair : scope_) {
1084     const Symbol &symbol{*pair.second};
1085     if (const auto *useDetails{symbol.detailsIf<UseDetails>()}) {
1086       const Symbol &ultimate{useDetails->symbol().GetUltimate()};
1087       bool needed{useSet_.count(ultimate) > 0};
1088       if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) {
1089         // The generic may not be needed itself, but the specific procedure
1090         // &/or derived type that it shadows may be needed.
1091         const Symbol *spec{generic->specific()};
1092         const Symbol *dt{generic->derivedType()};
1093         needed = needed || (spec && useSet_.count(*spec) > 0) ||
1094             (dt && useSet_.count(*dt) > 0);
1095       }
1096       if (needed) {
1097         need_.push_back(symbol);
1098       }
1099     } else if (symbol.has<SubprogramDetails>()) {
1100       // An internal subprogram is needed if it is used as interface
1101       // for a dummy or return value procedure.
1102       bool needed{false};
1103       const auto hasInterface{[&symbol](const Symbol *s) -> bool {
1104         // Is 's' a procedure with interface 'symbol'?
1105         if (s) {
1106           if (const auto *sDetails{s->detailsIf<ProcEntityDetails>()}) {
1107             const ProcInterface &sInterface{sDetails->interface()};
1108             if (sInterface.symbol() == &symbol) {
1109               return true;
1110             }
1111           }
1112         }
1113         return false;
1114       }};
1115       for (const Symbol *dummyArg : details.dummyArgs()) {
1116         needed = needed || hasInterface(dummyArg);
1117       }
1118       needed =
1119           needed || (details.isFunction() && hasInterface(&details.result()));
1120       if (needed && needSet_.insert(symbol).second) {
1121         need_.push_back(symbol);
1122       }
1123     }
1124   }
1125 }
1126 
1127 void SubprogramSymbolCollector::DoSymbol(const Symbol &symbol) {
1128   DoSymbol(symbol.name(), symbol);
1129 }
1130 
1131 // Do symbols this one depends on; then add to need_
1132 void SubprogramSymbolCollector::DoSymbol(
1133     const SourceName &name, const Symbol &symbol) {
1134   const auto &scope{symbol.owner()};
1135   if (scope != scope_ && !scope.IsDerivedType()) {
1136     if (scope != scope_.parent()) {
1137       useSet_.insert(symbol);
1138     }
1139     if (NeedImport(name, symbol)) {
1140       imports_.insert(name);
1141     }
1142     return;
1143   }
1144   if (!needSet_.insert(symbol).second) {
1145     return; // already done
1146   }
1147   common::visit(common::visitors{
1148                     [this](const ObjectEntityDetails &details) {
1149                       for (const ShapeSpec &spec : details.shape()) {
1150                         DoBound(spec.lbound());
1151                         DoBound(spec.ubound());
1152                       }
1153                       for (const ShapeSpec &spec : details.coshape()) {
1154                         DoBound(spec.lbound());
1155                         DoBound(spec.ubound());
1156                       }
1157                       if (const Symbol * commonBlock{details.commonBlock()}) {
1158                         DoSymbol(*commonBlock);
1159                       }
1160                     },
1161                     [this](const CommonBlockDetails &details) {
1162                       for (const auto &object : details.objects()) {
1163                         DoSymbol(*object);
1164                       }
1165                     },
1166                     [](const auto &) {},
1167                 },
1168       symbol.details());
1169   if (!symbol.has<UseDetails>()) {
1170     DoType(symbol.GetType());
1171   }
1172   if (!scope.IsDerivedType()) {
1173     need_.push_back(symbol);
1174   }
1175 }
1176 
1177 void SubprogramSymbolCollector::DoType(const DeclTypeSpec *type) {
1178   if (!type) {
1179     return;
1180   }
1181   switch (type->category()) {
1182   case DeclTypeSpec::Numeric:
1183   case DeclTypeSpec::Logical:
1184     break; // nothing to do
1185   case DeclTypeSpec::Character:
1186     DoParamValue(type->characterTypeSpec().length());
1187     break;
1188   default:
1189     if (const DerivedTypeSpec * derived{type->AsDerived()}) {
1190       const auto &typeSymbol{derived->typeSymbol()};
1191       if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) {
1192         DoSymbol(extends->name(), extends->typeSymbol());
1193       }
1194       for (const auto &pair : derived->parameters()) {
1195         DoParamValue(pair.second);
1196       }
1197       for (const auto &pair : *typeSymbol.scope()) {
1198         const Symbol &comp{*pair.second};
1199         DoSymbol(comp);
1200       }
1201       DoSymbol(derived->name(), derived->typeSymbol());
1202     }
1203   }
1204 }
1205 
1206 void SubprogramSymbolCollector::DoBound(const Bound &bound) {
1207   if (const MaybeSubscriptIntExpr & expr{bound.GetExplicit()}) {
1208     DoExpr(*expr);
1209   }
1210 }
1211 void SubprogramSymbolCollector::DoParamValue(const ParamValue &paramValue) {
1212   if (const auto &expr{paramValue.GetExplicit()}) {
1213     DoExpr(*expr);
1214   }
1215 }
1216 
1217 // Do we need a IMPORT of this symbol into an interface block?
1218 bool SubprogramSymbolCollector::NeedImport(
1219     const SourceName &name, const Symbol &symbol) {
1220   if (!isInterface_) {
1221     return false;
1222   } else if (symbol.owner().Contains(scope_)) {
1223     return true;
1224   } else if (const Symbol * found{scope_.FindSymbol(name)}) {
1225     // detect import from ancestor of use-associated symbol
1226     return found->has<UseDetails>() && found->owner() != scope_;
1227   } else {
1228     // "found" can be null in the case of a use-associated derived type's parent
1229     // type
1230     CHECK(symbol.has<DerivedTypeDetails>());
1231     return false;
1232   }
1233 }
1234 
1235 } // namespace Fortran::semantics
1236