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