1 //===-- lib/Semantics/mod-file.cpp ----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
26 #include <string_view>
29 namespace Fortran::semantics
{
31 using namespace parser::literals
;
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.
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
};
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
&);
55 llvm::raw_ostream
&, const ArraySpec
&, char open
, char close
);
57 static llvm::raw_ostream
&PutAttr(llvm::raw_ostream
&, Attr
);
58 static llvm::raw_ostream
&PutType(llvm::raw_ostream
&, const DeclTypeSpec
&);
59 static llvm::raw_ostream
&PutLower(llvm::raw_ostream
&, std::string_view
);
60 static std::error_code
WriteFile(
61 const std::string
&, const std::string
&, bool = true);
62 static bool FileContentsMatch(
63 const std::string
&, const std::string
&, const std::string
&);
64 static std::string
CheckSum(const std::string_view
&);
66 // Collect symbols needed for a subprogram interface
67 class SubprogramSymbolCollector
{
69 SubprogramSymbolCollector(const Symbol
&symbol
, const Scope
&scope
)
70 : symbol_
{symbol
}, scope_
{scope
} {}
71 const SymbolVector
&symbols() const { return need_
; }
72 const std::set
<SourceName
> &imports() const { return imports_
; }
76 const Symbol
&symbol_
;
78 bool isInterface_
{false};
79 SymbolVector need_
; // symbols that are needed
80 UnorderedSymbolSet needSet_
; // symbols already in need_
81 UnorderedSymbolSet useSet_
; // use-associations that might be needed
82 std::set
<SourceName
> imports_
; // imports from host that are needed
84 void DoSymbol(const Symbol
&);
85 void DoSymbol(const SourceName
&, const Symbol
&);
86 void DoType(const DeclTypeSpec
*);
87 void DoBound(const Bound
&);
88 void DoParamValue(const ParamValue
&);
89 bool NeedImport(const SourceName
&, const Symbol
&);
91 template <typename T
> void DoExpr(evaluate::Expr
<T
> expr
) {
92 for (const Symbol
&symbol
: evaluate::CollectSymbols(expr
)) {
98 bool ModFileWriter::WriteAll() {
99 // this flag affects character literals: force it to be consistent
101 common::ScopedSet(parser::useHexadecimalEscapeSequences
, false)};
102 WriteAll(context_
.globalScope());
103 return !context_
.AnyFatalError();
106 void ModFileWriter::WriteAll(const Scope
&scope
) {
107 for (const auto &child
: scope
.children()) {
112 void ModFileWriter::WriteOne(const Scope
&scope
) {
113 if (scope
.kind() == Scope::Kind::Module
) {
114 auto *symbol
{scope
.symbol()};
115 if (!symbol
->test(Symbol::Flag::ModFile
)) {
118 WriteAll(scope
); // write out submodules
122 // Construct the name of a module file. Non-empty ancestorName means submodule.
123 static std::string
ModFileName(const SourceName
&name
,
124 const std::string
&ancestorName
, const std::string
&suffix
) {
125 std::string result
{name
.ToString() + suffix
};
126 return ancestorName
.empty() ? result
: ancestorName
+ '-' + result
;
129 // Write the module file for symbol, which must be a module or submodule.
130 void ModFileWriter::Write(const Symbol
&symbol
) {
131 auto *ancestor
{symbol
.get
<ModuleDetails
>().ancestor()};
132 isSubmodule_
= ancestor
!= nullptr;
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())}) {
140 symbol
.name(), "Error writing %s: %s"_err_en_US
, path
, error
.message());
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
) {
148 llvm::raw_string_ostream all
{buf
};
149 auto &details
{symbol
.get
<ModuleDetails
>()};
150 if (!details
.isSubmodule()) {
151 all
<< "module " << symbol
.name();
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();
159 all
<< ") " << symbol
.name();
161 all
<< '\n' << uses_
.str();
163 all
<< useExtraAttrs_
.str();
164 useExtraAttrs_
.str().clear();
166 decls_
.str().clear();
167 auto str
{contains_
.str()};
168 contains_
.str().clear();
170 all
<< "contains\n" << str
;
176 // Put out the visible symbols from scope.
177 void ModFileWriter::PutSymbols(const Scope
&scope
) {
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
);
188 for (const Symbol
&symbol
: uses
) {
191 for (const auto &set
: scope
.equivalenceSets()) {
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();
203 CHECK(typeBindings
.str().empty());
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
);
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
);
229 emitted
.emplace(component
);
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
);
238 if (auto str
{typeBindings
.str()}; !str
.empty()) {
239 CHECK(scope
.IsDerivedType());
240 decls_
<< "contains\n" << str
;
247 static llvm::raw_ostream
&PutGenericName(
248 llvm::raw_ostream
&os
, const Symbol
&symbol
) {
249 if (IsGenericDefinedOp(symbol
)) {
250 return os
<< "operator(" << symbol
.name() << ')';
252 return os
<< symbol
.name();
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
) {
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()) {
268 for (const Symbol
&proc
: x
.specificProcs()) {
269 PutGenericName(typeBindings
<< "generic::", symbol
)
270 << "=>" << proc
.name() << '\n';
274 if (x
.specific() && &x
.specific()->owner() == &symbol
.owner()) {
275 PutSymbol(typeBindings
, *x
.specific());
277 if (x
.derivedType() &&
278 &x
.derivedType()->owner() == &symbol
.owner()) {
279 PutSymbol(typeBindings
, *x
.derivedType());
283 [&](const UseDetails
&) { PutUse(symbol
); },
284 [](const UseErrorDetails
&) {},
285 [&](const ProcBindingDetails
&x
) {
286 bool deferred
{symbol
.attrs().test(Attr::DEFERRED
)};
287 typeBindings
<< "procedure";
289 typeBindings
<< '(' << x
.symbol().name() << ')';
291 PutPassName(typeBindings
, x
.passName());
292 auto attrs
{symbol
.attrs()};
294 attrs
.reset(Attr::PASS
);
296 PutAttrs(typeBindings
, attrs
);
297 typeBindings
<< "::" << symbol
.name();
298 if (!deferred
&& x
.symbol().name() != symbol
.name()) {
299 typeBindings
<< "=>" << x
.symbol().name();
301 typeBindings
<< '\n';
303 [&](const NamelistDetails
&x
) {
304 decls_
<< "namelist/" << symbol
.name();
306 for (const Symbol
&object
: x
.objects()) {
307 decls_
<< sep
<< object
.name();
311 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
312 decls_
<< "private::" << symbol
.name() << '\n';
315 [&](const CommonBlockDetails
&x
) {
316 decls_
<< "common/" << symbol
.name();
318 for (const auto &object
: x
.objects()) {
319 decls_
<< sep
<< object
->name();
323 if (symbol
.attrs().test(Attr::BIND_C
)) {
324 PutAttrs(decls_
, symbol
.attrs(), x
.bindName(),
325 x
.isExplicitBindName(), ""s
);
326 decls_
<< "::/" << symbol
.name() << "/\n";
329 [](const HostAssocDetails
&) {},
330 [](const MiscDetails
&) {},
332 PutEntity(decls_
, symbol
);
333 if (symbol
.test(Symbol::Flag::OmpThreadprivate
)) {
334 decls_
<< "!$omp threadprivate(" << symbol
.name() << ")\n";
341 void ModFileWriter::PutDerivedType(
342 const Symbol
&typeSymbol
, const Scope
*scope
) {
343 auto &details
{typeSymbol
.get
<DerivedTypeDetails
>()};
344 if (details
.isDECStructure()) {
345 PutDECStructure(typeSymbol
, scope
);
348 PutAttrs(decls_
<< "type", typeSymbol
.attrs());
349 if (const DerivedTypeSpec
* extends
{typeSymbol
.GetParentTypeSpec()}) {
350 decls_
<< ",extends(" << extends
->name() << ')';
352 decls_
<< "::" << typeSymbol
.name();
353 if (!details
.paramNames().empty()) {
355 for (const auto &name
: details
.paramNames()) {
356 decls_
<< sep
<< name
;
362 if (details
.sequence()) {
363 decls_
<< "sequence\n";
365 bool contains
{PutComponents(typeSymbol
)};
366 if (!details
.finals().empty()) {
367 const char *sep
{contains
? "final::" : "contains\nfinal::"};
368 for (const auto &pair
: details
.finals()) {
369 decls_
<< sep
<< pair
.second
->name();
376 decls_
<< "end type\n";
379 void ModFileWriter::PutDECStructure(
380 const Symbol
&typeSymbol
, const Scope
*scope
) {
381 if (emittedDECStructures_
.find(typeSymbol
) != emittedDECStructures_
.end()) {
384 if (!scope
&& context_
.IsTempName(typeSymbol
.name().ToString())) {
385 return; // defer until used
387 emittedDECStructures_
.insert(typeSymbol
);
388 decls_
<< "structure ";
389 if (!context_
.IsTempName(typeSymbol
.name().ToString())) {
390 decls_
<< typeSymbol
.name();
392 if (scope
&& scope
->kind() == Scope::Kind::DerivedType
) {
393 // Nested STRUCTURE: emit entity declarations right now
394 // on the STRUCTURE statement.
396 for (const auto &ref
: scope
->GetSymbols()) {
397 const auto *object
{ref
->detailsIf
<ObjectEntityDetails
>()};
398 if (object
&& object
->type() &&
399 object
->type()->category() == DeclTypeSpec::TypeDerived
&&
400 &object
->type()->derivedTypeSpec().typeSymbol() == &typeSymbol
) {
406 decls_
<< ref
->name();
407 PutShape(decls_
, object
->shape(), '(', ')');
408 PutInit(decls_
, *ref
, object
->init(), nullptr);
409 emittedDECFields_
.insert(*ref
);
411 break; // any later use of this structure will use RECORD/str/
416 PutComponents(typeSymbol
);
417 decls_
<< "end structure\n";
420 // Attributes that may be in a subprogram prefix
421 static const Attrs subprogramPrefixAttrs
{Attr::ELEMENTAL
, Attr::IMPURE
,
422 Attr::MODULE
, Attr::NON_RECURSIVE
, Attr::PURE
, Attr::RECURSIVE
};
424 void ModFileWriter::PutSubprogram(const Symbol
&symbol
) {
425 auto &details
{symbol
.get
<SubprogramDetails
>()};
426 if (const Symbol
* interface
{details
.moduleInterface()}) {
427 const Scope
*module
{FindModuleContaining(interface
->owner())};
428 if (module
&& module
!= &symbol
.owner()) {
429 // Interface is in ancestor module
431 PutSubprogram(*interface
);
434 auto attrs
{symbol
.attrs()};
436 if (attrs
.test(Attr::BIND_C
)) {
437 // bind(c) is a suffix, not prefix
438 bindAttrs
.set(Attr::BIND_C
, true);
439 attrs
.set(Attr::BIND_C
, false);
441 bool isAbstract
{attrs
.test(Attr::ABSTRACT
)};
443 attrs
.set(Attr::ABSTRACT
, false);
445 Attrs prefixAttrs
{subprogramPrefixAttrs
& attrs
};
446 // emit any non-prefix attributes in an attribute statement
447 attrs
&= ~subprogramPrefixAttrs
;
449 llvm::raw_string_ostream ss
{ssBuf
};
451 if (!ss
.str().empty()) {
452 decls_
<< ss
.str().substr(1) << "::" << symbol
.name() << '\n';
454 bool isInterface
{details
.isInterface()};
455 llvm::raw_ostream
&os
{isInterface
? decls_
: contains_
};
457 os
<< (isAbstract
? "abstract " : "") << "interface\n";
459 PutAttrs(os
, prefixAttrs
, nullptr, false, ""s
, " "s
);
460 os
<< (details
.isFunction() ? "function " : "subroutine ");
461 os
<< symbol
.name() << '(';
463 for (const auto &dummy
: details
.dummyArgs()) {
474 PutAttrs(os
, bindAttrs
, details
.bindName(), details
.isExplicitBindName(),
476 if (details
.isFunction()) {
477 const Symbol
&result
{details
.result()};
478 if (result
.name() != symbol
.name()) {
479 os
<< " result(" << result
.name() << ')';
484 // walk symbols, collect ones needed for interface
486 details
.entryScope() ? *details
.entryScope() : DEREF(symbol
.scope())};
487 SubprogramSymbolCollector collector
{symbol
, scope
};
489 std::string typeBindingsBuf
;
490 llvm::raw_string_ostream typeBindings
{typeBindingsBuf
};
491 ModFileWriter writer
{context_
};
492 for (const Symbol
&need
: collector
.symbols()) {
493 writer
.PutSymbol(typeBindings
, need
);
495 CHECK(typeBindings
.str().empty());
496 os
<< writer
.uses_
.str();
497 for (const SourceName
&import
: collector
.imports()) {
498 decls_
<< "import::" << import
<< "\n";
500 os
<< writer
.decls_
.str();
503 os
<< "end interface\n";
507 static bool IsIntrinsicOp(const Symbol
&symbol
) {
508 if (const auto *details
{symbol
.GetUltimate().detailsIf
<GenericDetails
>()}) {
509 return details
->kind().IsIntrinsicOperator();
515 void ModFileWriter::PutGeneric(const Symbol
&symbol
) {
516 const auto &genericOwner
{symbol
.owner()};
517 auto &details
{symbol
.get
<GenericDetails
>()};
518 PutGenericName(decls_
<< "interface ", symbol
) << '\n';
519 for (const Symbol
&specific
: details
.specificProcs()) {
520 if (specific
.owner() == genericOwner
) {
521 decls_
<< "procedure::" << specific
.name() << '\n';
524 decls_
<< "end interface\n";
525 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
526 PutGenericName(decls_
<< "private::", symbol
) << '\n';
530 void ModFileWriter::PutUse(const Symbol
&symbol
) {
531 auto &details
{symbol
.get
<UseDetails
>()};
532 auto &use
{details
.symbol()};
533 const Symbol
&module
{GetUsedModule(details
)};
534 if (use
.owner().parent().IsIntrinsicModules()) {
535 uses_
<< "use,intrinsic::";
539 uses_
<< module
.name() << ",only:";
540 PutGenericName(uses_
, symbol
);
541 // Can have intrinsic op with different local-name and use-name
542 // (e.g. `operator(<)` and `operator(.lt.)`) but rename is not allowed
543 if (!IsIntrinsicOp(symbol
) && use
.name() != symbol
.name()) {
544 PutGenericName(uses_
<< "=>", use
);
547 PutUseExtraAttr(Attr::VOLATILE
, symbol
, use
);
548 PutUseExtraAttr(Attr::ASYNCHRONOUS
, symbol
, use
);
549 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
550 PutGenericName(useExtraAttrs_
<< "private::", symbol
) << '\n';
554 // We have "USE local => use" in this module. If attr was added locally
555 // (i.e. on local but not on use), also write it out in the mod file.
556 void ModFileWriter::PutUseExtraAttr(
557 Attr attr
, const Symbol
&local
, const Symbol
&use
) {
558 if (local
.attrs().test(attr
) && !use
.attrs().test(attr
)) {
559 PutAttr(useExtraAttrs_
, attr
) << "::";
560 useExtraAttrs_
<< local
.name() << '\n';
564 // When a generic interface has the same name as a derived type
565 // in the same scope, the generic shadows the derived type.
566 // If the derived type were declared first, emit the generic
567 // interface at the position of derived type's declaration.
568 // (ReplaceName() is not used for this purpose because doing so
569 // would confusingly position error messages pertaining to the generic
570 // interface upon the derived type's declaration.)
571 static inline SourceName
NameInModuleFile(const Symbol
&symbol
) {
572 if (const auto *generic
{symbol
.detailsIf
<GenericDetails
>()}) {
573 if (const auto *derivedTypeOverload
{generic
->derivedType()}) {
574 if (derivedTypeOverload
->name().begin() < symbol
.name().begin()) {
575 return derivedTypeOverload
->name();
578 } else if (const auto *use
{symbol
.detailsIf
<UseDetails
>()}) {
579 if (use
->symbol().attrs().test(Attr::PRIVATE
)) {
580 // Avoid the use in sorting of names created to access private
581 // specific procedures as a result of generic resolution;
582 // they're not in the cooked source.
583 return use
->symbol().name();
586 return symbol
.name();
589 // Collect the symbols of this scope sorted by their original order, not name.
590 // Namelists are an exception: they are sorted after other symbols.
592 const Scope
&scope
, SymbolVector
&sorted
, SymbolVector
&uses
) {
593 SymbolVector namelist
;
594 std::size_t commonSize
{scope
.commonBlocks().size()};
595 auto symbols
{scope
.GetSymbols()};
596 sorted
.reserve(symbols
.size() + commonSize
);
597 for (SymbolRef symbol
: symbols
) {
598 if (!symbol
->test(Symbol::Flag::ParentComp
)) {
599 if (symbol
->has
<NamelistDetails
>()) {
600 namelist
.push_back(symbol
);
602 sorted
.push_back(symbol
);
604 if (const auto *details
{symbol
->detailsIf
<GenericDetails
>()}) {
605 uses
.insert(uses
.end(), details
->uses().begin(), details
->uses().end());
609 // Sort most symbols by name: use of Symbol::ReplaceName ensures the source
610 // location of a symbol's name is the first "real" use.
611 std::sort(sorted
.begin(), sorted
.end(), [](SymbolRef x
, SymbolRef y
) {
612 return NameInModuleFile(x
).begin() < NameInModuleFile(y
).begin();
614 sorted
.insert(sorted
.end(), namelist
.begin(), namelist
.end());
615 for (const auto &pair
: scope
.commonBlocks()) {
616 sorted
.push_back(*pair
.second
);
619 sorted
.end() - commonSize
, sorted
.end(), SymbolSourcePositionCompare
{});
622 void ModFileWriter::PutEntity(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
625 [&](const ObjectEntityDetails
&) { PutObjectEntity(os
, symbol
); },
626 [&](const ProcEntityDetails
&) { PutProcEntity(os
, symbol
); },
627 [&](const TypeParamDetails
&) { PutTypeParam(os
, symbol
); },
629 common::die("PutEntity: unexpected details: %s",
630 DetailsToString(symbol
.details()).c_str());
636 void PutShapeSpec(llvm::raw_ostream
&os
, const ShapeSpec
&x
) {
637 if (x
.lbound().isStar()) {
638 CHECK(x
.ubound().isStar());
639 os
<< ".."; // assumed rank
641 if (!x
.lbound().isColon()) {
642 PutBound(os
, x
.lbound());
645 if (!x
.ubound().isColon()) {
646 PutBound(os
, x
.ubound());
651 llvm::raw_ostream
&os
, const ArraySpec
&shape
, char open
, char close
) {
652 if (!shape
.empty()) {
655 for (const auto &shapeSpec
: shape
) {
661 PutShapeSpec(os
, shapeSpec
);
667 void ModFileWriter::PutObjectEntity(
668 llvm::raw_ostream
&os
, const Symbol
&symbol
) {
669 auto &details
{symbol
.get
<ObjectEntityDetails
>()};
670 if (details
.type() &&
671 details
.type()->category() == DeclTypeSpec::TypeDerived
) {
672 const Symbol
&typeSymbol
{details
.type()->derivedTypeSpec().typeSymbol()};
673 if (typeSymbol
.get
<DerivedTypeDetails
>().isDECStructure()) {
674 PutDerivedType(typeSymbol
, &symbol
.owner());
675 if (emittedDECFields_
.find(symbol
) != emittedDECFields_
.end()) {
676 return; // symbol was emitted on STRUCTURE statement
681 os
, symbol
, [&]() { PutType(os
, DEREF(symbol
.GetType())); },
683 PutShape(os
, details
.shape(), '(', ')');
684 PutShape(os
, details
.coshape(), '[', ']');
685 PutInit(os
, symbol
, details
.init(), details
.unanalyzedPDTComponentInit());
689 void ModFileWriter::PutProcEntity(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
690 if (symbol
.attrs().test(Attr::INTRINSIC
)) {
691 os
<< "intrinsic::" << symbol
.name() << '\n';
692 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
693 os
<< "private::" << symbol
.name() << '\n';
697 const auto &details
{symbol
.get
<ProcEntityDetails
>()};
698 Attrs attrs
{symbol
.attrs()};
699 if (details
.passName()) {
700 attrs
.reset(Attr::PASS
);
706 if (details
.procInterface()) {
707 os
<< details
.procInterface()->name();
708 } else if (details
.type()) {
709 PutType(os
, *details
.type());
712 PutPassName(os
, details
.passName());
719 llvm::raw_ostream
&os
, const std::optional
<SourceName
> &passName
) {
721 os
<< ",pass(" << *passName
<< ')';
725 void ModFileWriter::PutTypeParam(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
726 auto &details
{symbol
.get
<TypeParamDetails
>()};
730 PutType(os
, DEREF(symbol
.GetType()));
731 PutLower(os
<< ',', common::EnumToString(details
.attr()));
734 PutInit(os
, details
.init());
738 void PutInit(llvm::raw_ostream
&os
, const Symbol
&symbol
, const MaybeExpr
&init
,
739 const parser::Expr
*unanalyzed
) {
740 if (symbol
.attrs().test(Attr::PARAMETER
) || symbol
.owner().IsDerivedType()) {
741 const char *assign
{symbol
.attrs().test(Attr::POINTER
) ? "=>" : "="};
743 parser::Unparse(os
<< assign
, *unanalyzed
);
745 init
->AsFortran(os
<< assign
);
750 void PutInit(llvm::raw_ostream
&os
, const MaybeIntExpr
&init
) {
752 init
->AsFortran(os
<< '=');
756 void PutBound(llvm::raw_ostream
&os
, const Bound
&x
) {
759 } else if (x
.isColon()) {
762 x
.GetExplicit()->AsFortran(os
);
766 // Write an entity (object or procedure) declaration.
767 // writeType is called to write out the type.
768 void ModFileWriter::PutEntity(llvm::raw_ostream
&os
, const Symbol
&symbol
,
769 std::function
<void()> writeType
, Attrs attrs
) {
771 PutAttrs(os
, attrs
, symbol
.GetBindName(), symbol
.GetIsExplicitBindName());
772 if (symbol
.owner().kind() == Scope::Kind::DerivedType
&&
773 context_
.IsTempName(symbol
.name().ToString())) {
776 os
<< "::" << symbol
.name();
780 // Put out each attribute to os, surrounded by `before` and `after` and
781 // mapped to lower case.
782 llvm::raw_ostream
&ModFileWriter::PutAttrs(llvm::raw_ostream
&os
, Attrs attrs
,
783 const std::string
*bindName
, bool isExplicitBindName
, std::string before
,
784 std::string after
) const {
785 attrs
.set(Attr::PUBLIC
, false); // no need to write PUBLIC
786 attrs
.set(Attr::EXTERNAL
, false); // no need to write EXTERNAL
788 attrs
.set(Attr::PRIVATE
, false);
790 if (bindName
|| isExplicitBindName
) {
791 os
<< before
<< "bind(c";
792 if (isExplicitBindName
) {
793 os
<< ",name=\"" << (bindName
? *bindName
: ""s
) << '"';
796 attrs
.set(Attr::BIND_C
, false);
798 for (std::size_t i
{0}; i
< Attr_enumSize
; ++i
) {
799 Attr attr
{static_cast<Attr
>(i
)};
800 if (attrs
.test(attr
)) {
801 PutAttr(os
<< before
, attr
) << after
;
807 llvm::raw_ostream
&PutAttr(llvm::raw_ostream
&os
, Attr attr
) {
808 return PutLower(os
, AttrToString(attr
));
811 llvm::raw_ostream
&PutType(llvm::raw_ostream
&os
, const DeclTypeSpec
&type
) {
812 return PutLower(os
, type
.AsFortran());
815 llvm::raw_ostream
&PutLower(llvm::raw_ostream
&os
, std::string_view str
) {
817 os
<< parser::ToLowerCaseLetter(c
);
823 Temp(int fd
, std::string path
) : fd
{fd
}, path
{path
} {}
824 Temp(Temp
&&t
) : fd
{std::exchange(t
.fd
, -1)}, path
{std::move(t
.path
)} {}
827 llvm::sys::fs::file_t native
{llvm::sys::fs::convertFDToNativeFile(fd
)};
828 llvm::sys::fs::closeFile(native
);
829 llvm::sys::fs::remove(path
.c_str());
836 // Create a temp file in the same directory and with the same suffix as path.
837 // Return an open file descriptor and its path.
838 static llvm::ErrorOr
<Temp
> MkTemp(const std::string
&path
) {
839 auto length
{path
.length()};
840 auto dot
{path
.find_last_of("./")};
842 dot
< length
&& path
[dot
] == '.' ? path
.substr(dot
+ 1) : ""};
843 CHECK(length
> suffix
.length() &&
844 path
.substr(length
- suffix
.length()) == suffix
);
845 auto prefix
{path
.substr(0, length
- suffix
.length())};
847 llvm::SmallString
<16> tempPath
;
848 if (std::error_code err
{llvm::sys::fs::createUniqueFile(
849 prefix
+ "%%%%%%" + suffix
, fd
, tempPath
)}) {
852 return Temp
{fd
, tempPath
.c_str()};
855 // Write the module file at path, prepending header. If an error occurs,
856 // return errno, otherwise 0.
857 static std::error_code
WriteFile(
858 const std::string
&path
, const std::string
&contents
, bool debug
) {
859 auto header
{std::string
{ModHeader::bom
} + ModHeader::magic
+
860 CheckSum(contents
) + ModHeader::terminator
};
862 llvm::dbgs() << "Processing module " << path
<< ": ";
864 if (FileContentsMatch(path
, header
, contents
)) {
866 llvm::dbgs() << "module unchanged, not writing\n";
870 llvm::ErrorOr
<Temp
> temp
{MkTemp(path
)};
872 return temp
.getError();
874 llvm::raw_fd_ostream
writer(temp
->fd
, /*shouldClose=*/false);
878 if (writer
.has_error()) {
879 return writer
.error();
882 llvm::dbgs() << "module written\n";
884 return llvm::sys::fs::rename(temp
->path
, path
);
887 // Return true if the stream matches what we would write for the mod file.
888 static bool FileContentsMatch(const std::string
&path
,
889 const std::string
&header
, const std::string
&contents
) {
890 std::size_t hsize
{header
.size()};
891 std::size_t csize
{contents
.size()};
892 auto buf_or
{llvm::MemoryBuffer::getFile(path
)};
896 auto buf
= std::move(buf_or
.get());
897 if (buf
->getBufferSize() != hsize
+ csize
) {
900 if (!std::equal(header
.begin(), header
.end(), buf
->getBufferStart(),
901 buf
->getBufferStart() + hsize
)) {
905 return std::equal(contents
.begin(), contents
.end(),
906 buf
->getBufferStart() + hsize
, buf
->getBufferEnd());
909 // Compute a simple hash of the contents of a module file and
910 // return it as a string of hex digits.
911 // This uses the Fowler-Noll-Vo hash function.
912 static std::string
CheckSum(const std::string_view
&contents
) {
913 std::uint64_t hash
{0xcbf29ce484222325ull
};
914 for (char c
: contents
) {
916 hash
*= 0x100000001b3;
918 static const char *digits
= "0123456789abcdef";
919 std::string
result(ModHeader::sumLen
, '0');
920 for (size_t i
{ModHeader::sumLen
}; hash
!= 0; hash
>>= 4) {
921 result
[--i
] = digits
[hash
& 0xf];
926 static bool VerifyHeader(llvm::ArrayRef
<char> content
) {
927 std::string_view sv
{content
.data(), content
.size()};
928 if (sv
.substr(0, ModHeader::magicLen
) != ModHeader::magic
) {
931 std::string_view expectSum
{sv
.substr(ModHeader::magicLen
, ModHeader::sumLen
)};
932 std::string actualSum
{CheckSum(sv
.substr(ModHeader::len
))};
933 return expectSum
== actualSum
;
936 Scope
*ModFileReader::Read(const SourceName
&name
,
937 std::optional
<bool> isIntrinsic
, Scope
*ancestor
, bool silent
) {
938 std::string ancestorName
; // empty for module
939 Symbol
*notAModule
{nullptr};
940 bool fatalError
{false};
942 if (auto *scope
{ancestor
->FindSubmodule(name
)}) {
945 ancestorName
= ancestor
->GetName().value().ToString();
947 if (!isIntrinsic
.value_or(false) && !ancestor
) {
948 // Already present in the symbol table as a usable non-intrinsic module?
949 auto it
{context_
.globalScope().find(name
)};
950 if (it
!= context_
.globalScope().end()) {
951 Scope
*scope
{it
->second
->scope()};
952 if (scope
->kind() == Scope::Kind::Module
) {
955 notAModule
= scope
->symbol();
956 // USE, NON_INTRINSIC global name isn't a module?
957 fatalError
= isIntrinsic
.has_value();
961 auto path
{ModFileName(name
, ancestorName
, context_
.moduleFileSuffix())};
962 parser::Parsing parsing
{context_
.allCookedSources()};
963 parser::Options options
;
964 options
.isModuleFile
= true;
965 options
.features
.Enable(common::LanguageFeature::BackslashEscapes
);
966 options
.features
.Enable(common::LanguageFeature::OpenMP
);
967 if (!isIntrinsic
.value_or(false) && !notAModule
) {
968 // The search for this module file will scan non-intrinsic module
969 // directories. If a directory is in both the intrinsic and non-intrinsic
970 // directory lists, the intrinsic module directory takes precedence.
971 options
.searchDirectories
= context_
.searchDirectories();
972 for (const auto &dir
: context_
.intrinsicModuleDirectories()) {
973 options
.searchDirectories
.erase(
974 std::remove(options
.searchDirectories
.begin(),
975 options
.searchDirectories
.end(), dir
),
976 options
.searchDirectories
.end());
978 options
.searchDirectories
.insert(options
.searchDirectories
.begin(), "."s
);
980 bool foundNonIntrinsicModuleFile
{false};
982 std::list
<std::string
> searchDirs
;
983 for (const auto &d
: options
.searchDirectories
) {
984 searchDirs
.push_back(d
);
986 foundNonIntrinsicModuleFile
=
987 parser::LocateSourceFile(path
, searchDirs
).has_value();
989 if (isIntrinsic
.value_or(!foundNonIntrinsicModuleFile
)) {
990 // Explicitly intrinsic, or not specified and not found in the search
991 // path; see whether it's already in the symbol table as an intrinsic
993 auto it
{context_
.intrinsicModulesScope().find(name
)};
994 if (it
!= context_
.intrinsicModulesScope().end()) {
995 return it
->second
->scope();
998 // We don't have this module in the symbol table yet.
999 // Find its module file and parse it. Define or extend the search
1000 // path with intrinsic module directories, if appropriate.
1001 if (isIntrinsic
.value_or(true)) {
1002 for (const auto &dir
: context_
.intrinsicModuleDirectories()) {
1003 options
.searchDirectories
.push_back(dir
);
1006 const auto *sourceFile
{fatalError
? nullptr : parsing
.Prescan(path
, options
)};
1007 if (fatalError
|| parsing
.messages().AnyFatalError()) {
1010 // Module is not explicitly INTRINSIC, and there's already a global
1011 // symbol of the same name that is not a module.
1012 context_
.SayWithDecl(
1013 *notAModule
, name
, "'%s' is not a module"_err_en_US
, name
);
1015 for (auto &msg
: parsing
.messages().messages()) {
1016 std::string str
{msg
.ToString()};
1017 Say(name
, ancestorName
,
1018 parser::MessageFixedText
{str
.c_str(), str
.size(), msg
.severity()},
1026 if (!VerifyHeader(sourceFile
->content())) {
1027 Say(name
, ancestorName
, "File has invalid checksum: %s"_warn_en_US
,
1028 sourceFile
->path());
1031 llvm::raw_null_ostream NullStream
;
1032 parsing
.Parse(NullStream
);
1033 std::optional
<parser::Program
> &parsedProgram
{parsing
.parseTree()};
1034 if (!parsing
.messages().empty() || !parsing
.consumedWholeFile() ||
1036 Say(name
, ancestorName
, "Module file is corrupt: %s"_err_en_US
,
1037 sourceFile
->path());
1040 parser::Program
&parseTree
{context_
.SaveParseTree(std::move(*parsedProgram
))};
1041 Scope
*parentScope
; // the scope this module/submodule goes into
1042 if (!isIntrinsic
.has_value()) {
1043 for (const auto &dir
: context_
.intrinsicModuleDirectories()) {
1044 if (sourceFile
->path().size() > dir
.size() &&
1045 sourceFile
->path().find(dir
) == 0) {
1051 Scope
&topScope
{isIntrinsic
.value_or(false) ? context_
.intrinsicModulesScope()
1052 : context_
.globalScope()};
1054 parentScope
= &topScope
;
1055 } else if (std::optional
<SourceName
> parent
{GetSubmoduleParent(parseTree
)}) {
1056 parentScope
= Read(*parent
, false /*not intrinsic*/, ancestor
, silent
);
1058 parentScope
= ancestor
;
1060 auto pair
{parentScope
->try_emplace(name
, UnknownDetails
{})};
1064 // Process declarations from the module file
1065 Symbol
&modSymbol
{*pair
.first
->second
};
1066 modSymbol
.set(Symbol::Flag::ModFile
);
1067 bool wasInModuleFile
{context_
.foldingContext().inModuleFile()};
1068 context_
.foldingContext().set_inModuleFile(true);
1069 ResolveNames(context_
, parseTree
, topScope
);
1070 context_
.foldingContext().set_inModuleFile(wasInModuleFile
);
1071 CHECK(modSymbol
.has
<ModuleDetails
>());
1072 CHECK(modSymbol
.test(Symbol::Flag::ModFile
));
1073 if (isIntrinsic
.value_or(false)) {
1074 modSymbol
.attrs().set(Attr::INTRINSIC
);
1076 return modSymbol
.scope();
1079 parser::Message
&ModFileReader::Say(const SourceName
&name
,
1080 const std::string
&ancestor
, parser::MessageFixedText
&&msg
,
1081 const std::string
&arg
) {
1082 return context_
.Say(name
, "Cannot read module file for %s: %s"_err_en_US
,
1083 parser::MessageFormattedText
{ancestor
.empty()
1084 ? "module '%s'"_en_US
1085 : "submodule '%s' of module '%s'"_en_US
,
1088 parser::MessageFormattedText
{std::move(msg
), arg
}.MoveString());
1091 // program was read from a .mod file for a submodule; return the name of the
1092 // submodule's parent submodule, nullptr if none.
1093 static std::optional
<SourceName
> GetSubmoduleParent(
1094 const parser::Program
&program
) {
1095 CHECK(program
.v
.size() == 1);
1096 auto &unit
{program
.v
.front()};
1097 auto &submod
{std::get
<common::Indirection
<parser::Submodule
>>(unit
.u
)};
1099 std::get
<parser::Statement
<parser::SubmoduleStmt
>>(submod
.value().t
)};
1100 auto &parentId
{std::get
<parser::ParentIdentifier
>(stmt
.statement
.t
)};
1101 if (auto &parent
{std::get
<std::optional
<parser::Name
>>(parentId
.t
)}) {
1102 return parent
->source
;
1104 return std::nullopt
;
1108 void SubprogramSymbolCollector::Collect() {
1109 const auto &details
{symbol_
.get
<SubprogramDetails
>()};
1110 isInterface_
= details
.isInterface();
1111 for (const Symbol
*dummyArg
: details
.dummyArgs()) {
1113 DoSymbol(*dummyArg
);
1116 if (details
.isFunction()) {
1117 DoSymbol(details
.result());
1119 for (const auto &pair
: scope_
) {
1120 const Symbol
&symbol
{*pair
.second
};
1121 if (const auto *useDetails
{symbol
.detailsIf
<UseDetails
>()}) {
1122 const Symbol
&ultimate
{useDetails
->symbol().GetUltimate()};
1123 bool needed
{useSet_
.count(ultimate
) > 0};
1124 if (const auto *generic
{ultimate
.detailsIf
<GenericDetails
>()}) {
1125 // The generic may not be needed itself, but the specific procedure
1126 // &/or derived type that it shadows may be needed.
1127 const Symbol
*spec
{generic
->specific()};
1128 const Symbol
*dt
{generic
->derivedType()};
1129 needed
= needed
|| (spec
&& useSet_
.count(*spec
) > 0) ||
1130 (dt
&& useSet_
.count(*dt
) > 0);
1131 } else if (const auto *subp
{ultimate
.detailsIf
<SubprogramDetails
>()}) {
1132 const Symbol
*interface
{ subp
->moduleInterface() };
1133 needed
= needed
|| (interface
&& useSet_
.count(*interface
) > 0);
1136 need_
.push_back(symbol
);
1138 } else if (symbol
.has
<SubprogramDetails
>()) {
1139 // An internal subprogram is needed if it is used as interface
1140 // for a dummy or return value procedure.
1142 const auto hasInterface
{[&symbol
](const Symbol
*s
) -> bool {
1143 // Is 's' a procedure with interface 'symbol'?
1145 if (const auto *sDetails
{s
->detailsIf
<ProcEntityDetails
>()}) {
1146 if (sDetails
->procInterface() == &symbol
) {
1153 for (const Symbol
*dummyArg
: details
.dummyArgs()) {
1154 needed
= needed
|| hasInterface(dummyArg
);
1157 needed
|| (details
.isFunction() && hasInterface(&details
.result()));
1158 if (needed
&& needSet_
.insert(symbol
).second
) {
1159 need_
.push_back(symbol
);
1165 void SubprogramSymbolCollector::DoSymbol(const Symbol
&symbol
) {
1166 DoSymbol(symbol
.name(), symbol
);
1169 // Do symbols this one depends on; then add to need_
1170 void SubprogramSymbolCollector::DoSymbol(
1171 const SourceName
&name
, const Symbol
&symbol
) {
1172 const auto &scope
{symbol
.owner()};
1173 if (scope
!= scope_
&& !scope
.IsDerivedType()) {
1174 if (scope
!= scope_
.parent()) {
1175 useSet_
.insert(symbol
);
1177 if (NeedImport(name
, symbol
)) {
1178 imports_
.insert(name
);
1182 if (!needSet_
.insert(symbol
).second
) {
1183 return; // already done
1185 common::visit(common::visitors
{
1186 [this](const ObjectEntityDetails
&details
) {
1187 for (const ShapeSpec
&spec
: details
.shape()) {
1188 DoBound(spec
.lbound());
1189 DoBound(spec
.ubound());
1191 for (const ShapeSpec
&spec
: details
.coshape()) {
1192 DoBound(spec
.lbound());
1193 DoBound(spec
.ubound());
1195 if (const Symbol
* commonBlock
{details
.commonBlock()}) {
1196 DoSymbol(*commonBlock
);
1199 [this](const CommonBlockDetails
&details
) {
1200 for (const auto &object
: details
.objects()) {
1204 [this](const ProcEntityDetails
&details
) {
1205 if (details
.procInterface()) {
1206 DoSymbol(*details
.procInterface());
1208 DoType(details
.type());
1211 [](const auto &) {},
1214 if (!symbol
.has
<UseDetails
>()) {
1215 DoType(symbol
.GetType());
1217 if (!scope
.IsDerivedType()) {
1218 need_
.push_back(symbol
);
1222 void SubprogramSymbolCollector::DoType(const DeclTypeSpec
*type
) {
1226 switch (type
->category()) {
1227 case DeclTypeSpec::Numeric
:
1228 case DeclTypeSpec::Logical
:
1229 break; // nothing to do
1230 case DeclTypeSpec::Character
:
1231 DoParamValue(type
->characterTypeSpec().length());
1234 if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
1235 const auto &typeSymbol
{derived
->typeSymbol()};
1236 if (const DerivedTypeSpec
* extends
{typeSymbol
.GetParentTypeSpec()}) {
1237 DoSymbol(extends
->name(), extends
->typeSymbol());
1239 for (const auto &pair
: derived
->parameters()) {
1240 DoParamValue(pair
.second
);
1242 for (const auto &pair
: *typeSymbol
.scope()) {
1243 const Symbol
&comp
{*pair
.second
};
1246 DoSymbol(derived
->name(), derived
->typeSymbol());
1251 void SubprogramSymbolCollector::DoBound(const Bound
&bound
) {
1252 if (const MaybeSubscriptIntExpr
& expr
{bound
.GetExplicit()}) {
1256 void SubprogramSymbolCollector::DoParamValue(const ParamValue
¶mValue
) {
1257 if (const auto &expr
{paramValue
.GetExplicit()}) {
1262 // Do we need a IMPORT of this symbol into an interface block?
1263 bool SubprogramSymbolCollector::NeedImport(
1264 const SourceName
&name
, const Symbol
&symbol
) {
1265 if (!isInterface_
) {
1267 } else if (IsSeparateModuleProcedureInterface(&symbol_
)) {
1268 return false; // IMPORT needed only for external and dummy procedure
1270 } else if (&symbol
== scope_
.symbol()) {
1272 } else if (symbol
.owner().Contains(scope_
)) {
1274 } else if (const Symbol
*found
{scope_
.FindSymbol(name
)}) {
1275 // detect import from ancestor of use-associated symbol
1276 return found
->has
<UseDetails
>() && found
->owner() != scope_
;
1278 // "found" can be null in the case of a use-associated derived type's parent
1280 CHECK(symbol
.has
<DerivedTypeDetails
>());
1285 } // namespace Fortran::semantics