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