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 std::map
<const Symbol
*, SourceName
> &);
49 static void PutPassName(llvm::raw_ostream
&, const std::optional
<SourceName
> &);
50 static void PutInit(llvm::raw_ostream
&, const Symbol
&, const MaybeExpr
&,
51 const parser::Expr
*, const std::map
<const Symbol
*, SourceName
> &);
52 static void PutInit(llvm::raw_ostream
&, const MaybeIntExpr
&);
53 static void PutBound(llvm::raw_ostream
&, const Bound
&);
54 static void PutShapeSpec(llvm::raw_ostream
&, const ShapeSpec
&);
56 llvm::raw_ostream
&, const ArraySpec
&, char open
, char close
);
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
&, std::string_view
);
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
&);
67 // Collect symbols needed for a subprogram interface
68 class SubprogramSymbolCollector
{
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_
; }
77 const Symbol
&symbol_
;
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
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
&);
92 template <typename T
> void DoExpr(evaluate::Expr
<T
> expr
) {
93 for (const Symbol
&symbol
: evaluate::CollectSymbols(expr
)) {
99 bool ModFileWriter::WriteAll() {
100 // this flag affects character literals: force it to be consistent
102 common::ScopedSet(parser::useHexadecimalEscapeSequences
, false)};
103 WriteAll(context_
.globalScope());
104 return !context_
.AnyFatalError();
107 void ModFileWriter::WriteAll(const Scope
&scope
) {
108 for (const auto &child
: scope
.children()) {
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
)) {
119 WriteAll(scope
); // write out submodules
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
;
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 isSubmodule_
= ancestor
!= nullptr;
134 auto ancestorName
{ancestor
? ancestor
->GetName().value().ToString() : ""s
};
135 auto path
{context_
.moduleDirectory() + '/' +
136 ModFileName(symbol
.name(), ancestorName
, context_
.moduleFileSuffix())};
137 PutSymbols(DEREF(symbol
.scope()));
138 if (std::error_code error
{
139 WriteFile(path
, GetAsString(symbol
), context_
.debugModuleWriter())}) {
141 symbol
.name(), "Error writing %s: %s"_err_en_US
, path
, error
.message());
145 // Return the entire body of the module file
146 // and clear saved uses, decls, and contains.
147 std::string
ModFileWriter::GetAsString(const Symbol
&symbol
) {
149 llvm::raw_string_ostream all
{buf
};
150 auto &details
{symbol
.get
<ModuleDetails
>()};
151 if (!details
.isSubmodule()) {
152 all
<< "module " << symbol
.name();
154 auto *parent
{details
.parent()->symbol()};
155 auto *ancestor
{details
.ancestor()->symbol()};
156 all
<< "submodule(" << ancestor
->name();
157 if (parent
!= ancestor
) {
158 all
<< ':' << parent
->name();
160 all
<< ") " << symbol
.name();
162 all
<< '\n' << uses_
.str();
164 all
<< useExtraAttrs_
.str();
165 useExtraAttrs_
.str().clear();
167 decls_
.str().clear();
168 auto str
{contains_
.str()};
169 contains_
.str().clear();
171 all
<< "contains\n" << str
;
177 // Collect symbols from initializations that are being referenced directly
178 // from other modules; they may require new USE associations.
179 static void HarvestInitializerSymbols(
180 SourceOrderedSymbolSet
&set
, const Scope
&scope
) {
181 for (const auto &[_
, symbol
] : scope
) {
182 if (symbol
->has
<DerivedTypeDetails
>()) {
183 if (symbol
->scope()) {
184 HarvestInitializerSymbols(set
, *symbol
->scope());
186 } else if (IsNamedConstant(*symbol
) || scope
.IsDerivedType()) {
187 if (const auto *object
{symbol
->detailsIf
<ObjectEntityDetails
>()}) {
188 if (object
->init()) {
189 for (SymbolRef ref
: evaluate::CollectSymbols(*object
->init())) {
193 } else if (const auto *proc
{symbol
->detailsIf
<ProcEntityDetails
>()}) {
194 if (proc
->init() && *proc
->init()) {
195 set
.emplace(**proc
->init());
202 void ModFileWriter::PrepareRenamings(const Scope
&scope
) {
203 SourceOrderedSymbolSet symbolsInInits
;
204 HarvestInitializerSymbols(symbolsInInits
, scope
);
205 for (SymbolRef s
: symbolsInInits
) {
206 const Scope
*sMod
{FindModuleContaining(s
->owner())};
210 SourceName rename
{s
->name()};
211 if (const Symbol
* found
{scope
.FindSymbol(s
->name())}) {
213 continue; // available in scope
215 if (const auto *generic
{found
->detailsIf
<GenericDetails
>()}) {
216 if (generic
->derivedType() == &*s
|| generic
->specific() == &*s
) {
219 } else if (found
->has
<UseDetails
>()) {
220 if (&found
->GetUltimate() == &*s
) {
221 continue; // already use-associated with same name
224 if (&s
->owner() != &found
->owner()) { // Symbol needs renaming
225 rename
= scope
.context().SaveTempName(
226 DEREF(sMod
->symbol()).name().ToString() + "$" +
227 s
->name().ToString());
230 // Symbol is used in this scope but not visible under its name
231 if (sMod
->parent().IsIntrinsicModules()) {
232 uses_
<< "use,intrinsic::";
236 uses_
<< DEREF(sMod
->symbol()).name() << ",only:";
237 if (rename
!= s
->name()) {
238 uses_
<< rename
<< "=>";
240 uses_
<< s
->name() << '\n';
241 useExtraAttrs_
<< "private::" << rename
<< '\n';
242 renamings_
.emplace(&*s
, rename
);
246 // Put out the visible symbols from scope.
247 void ModFileWriter::PutSymbols(const Scope
&scope
) {
250 PrepareRenamings(scope
);
251 CollectSymbols(scope
, sorted
, uses
, renamings_
);
252 std::string buf
; // stuff after CONTAINS in derived type
253 llvm::raw_string_ostream typeBindings
{buf
};
254 for (const Symbol
&symbol
: sorted
) {
255 if (!symbol
.test(Symbol::Flag::CompilerCreated
)) {
256 PutSymbol(typeBindings
, symbol
);
259 for (const Symbol
&symbol
: uses
) {
262 for (const auto &set
: scope
.equivalenceSets()) {
264 !set
.front().symbol
.test(Symbol::Flag::CompilerCreated
)) {
265 char punctuation
{'('};
266 decls_
<< "equivalence";
267 for (const auto &object
: set
) {
268 decls_
<< punctuation
<< object
.AsFortran();
274 CHECK(typeBindings
.str().empty());
277 // Emit components in order
278 bool ModFileWriter::PutComponents(const Symbol
&typeSymbol
) {
279 const auto &scope
{DEREF(typeSymbol
.scope())};
280 std::string buf
; // stuff after CONTAINS in derived type
281 llvm::raw_string_ostream typeBindings
{buf
};
282 UnorderedSymbolSet emitted
;
283 SymbolVector symbols
{scope
.GetSymbols()};
284 // Emit type parameters first
285 for (const Symbol
&symbol
: symbols
) {
286 if (symbol
.has
<TypeParamDetails
>()) {
287 PutSymbol(typeBindings
, symbol
);
288 emitted
.emplace(symbol
);
291 // Emit components in component order.
292 const auto &details
{typeSymbol
.get
<DerivedTypeDetails
>()};
293 for (SourceName name
: details
.componentNames()) {
294 auto iter
{scope
.find(name
)};
295 if (iter
!= scope
.end()) {
296 const Symbol
&component
{*iter
->second
};
297 if (!component
.test(Symbol::Flag::ParentComp
)) {
298 PutSymbol(typeBindings
, component
);
300 emitted
.emplace(component
);
303 // Emit remaining symbols from the type's scope
304 for (const Symbol
&symbol
: symbols
) {
305 if (emitted
.find(symbol
) == emitted
.end()) {
306 PutSymbol(typeBindings
, symbol
);
309 if (auto str
{typeBindings
.str()}; !str
.empty()) {
310 CHECK(scope
.IsDerivedType());
311 decls_
<< "contains\n" << str
;
318 // Return the symbol's attributes that should be written
319 // into the mod file.
320 static Attrs
getSymbolAttrsToWrite(const Symbol
&symbol
) {
321 // Is SAVE attribute is implicit, it should be omitted
322 // to not violate F202x C862 for a common block member.
323 return symbol
.attrs() & ~(symbol
.implicitAttrs() & Attrs
{Attr::SAVE
});
326 static llvm::raw_ostream
&PutGenericName(
327 llvm::raw_ostream
&os
, const Symbol
&symbol
) {
328 if (IsGenericDefinedOp(symbol
)) {
329 return os
<< "operator(" << symbol
.name() << ')';
331 return os
<< symbol
.name();
335 // Emit a symbol to decls_, except for bindings in a derived type (type-bound
336 // procedures, type-bound generics, final procedures) which go to typeBindings.
337 void ModFileWriter::PutSymbol(
338 llvm::raw_ostream
&typeBindings
, const Symbol
&symbol
) {
341 [&](const ModuleDetails
&) { /* should be current module */ },
342 [&](const DerivedTypeDetails
&) { PutDerivedType(symbol
); },
343 [&](const SubprogramDetails
&) { PutSubprogram(symbol
); },
344 [&](const GenericDetails
&x
) {
345 if (symbol
.owner().IsDerivedType()) {
347 for (const Symbol
&proc
: x
.specificProcs()) {
348 PutGenericName(typeBindings
<< "generic::", symbol
)
349 << "=>" << proc
.name() << '\n';
355 [&](const UseDetails
&) { PutUse(symbol
); },
356 [](const UseErrorDetails
&) {},
357 [&](const ProcBindingDetails
&x
) {
358 bool deferred
{symbol
.attrs().test(Attr::DEFERRED
)};
359 typeBindings
<< "procedure";
361 typeBindings
<< '(' << x
.symbol().name() << ')';
363 PutPassName(typeBindings
, x
.passName());
364 auto attrs
{symbol
.attrs()};
366 attrs
.reset(Attr::PASS
);
368 PutAttrs(typeBindings
, attrs
);
369 typeBindings
<< "::" << symbol
.name();
370 if (!deferred
&& x
.symbol().name() != symbol
.name()) {
371 typeBindings
<< "=>" << x
.symbol().name();
373 typeBindings
<< '\n';
375 [&](const NamelistDetails
&x
) {
376 decls_
<< "namelist/" << symbol
.name();
378 for (const Symbol
&object
: x
.objects()) {
379 decls_
<< sep
<< object
.name();
383 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
384 decls_
<< "private::" << symbol
.name() << '\n';
387 [&](const CommonBlockDetails
&x
) {
388 decls_
<< "common/" << symbol
.name();
390 for (const auto &object
: x
.objects()) {
391 decls_
<< sep
<< object
->name();
395 if (symbol
.attrs().test(Attr::BIND_C
)) {
396 PutAttrs(decls_
, getSymbolAttrsToWrite(symbol
), x
.bindName(),
397 x
.isExplicitBindName(), ""s
);
398 decls_
<< "::/" << symbol
.name() << "/\n";
401 [](const HostAssocDetails
&) {},
402 [](const MiscDetails
&) {},
404 PutEntity(decls_
, symbol
);
405 PutDirective(decls_
, symbol
);
411 void ModFileWriter::PutDerivedType(
412 const Symbol
&typeSymbol
, const Scope
*scope
) {
413 auto &details
{typeSymbol
.get
<DerivedTypeDetails
>()};
414 if (details
.isDECStructure()) {
415 PutDECStructure(typeSymbol
, scope
);
418 PutAttrs(decls_
<< "type", typeSymbol
.attrs());
419 if (const DerivedTypeSpec
* extends
{typeSymbol
.GetParentTypeSpec()}) {
420 decls_
<< ",extends(" << extends
->name() << ')';
422 decls_
<< "::" << typeSymbol
.name();
423 if (!details
.paramNames().empty()) {
425 for (const auto &name
: details
.paramNames()) {
426 decls_
<< sep
<< name
;
432 if (details
.sequence()) {
433 decls_
<< "sequence\n";
435 bool contains
{PutComponents(typeSymbol
)};
436 if (!details
.finals().empty()) {
437 const char *sep
{contains
? "final::" : "contains\nfinal::"};
438 for (const auto &pair
: details
.finals()) {
439 decls_
<< sep
<< pair
.second
->name();
446 decls_
<< "end type\n";
449 void ModFileWriter::PutDECStructure(
450 const Symbol
&typeSymbol
, const Scope
*scope
) {
451 if (emittedDECStructures_
.find(typeSymbol
) != emittedDECStructures_
.end()) {
454 if (!scope
&& context_
.IsTempName(typeSymbol
.name().ToString())) {
455 return; // defer until used
457 emittedDECStructures_
.insert(typeSymbol
);
458 decls_
<< "structure ";
459 if (!context_
.IsTempName(typeSymbol
.name().ToString())) {
460 decls_
<< typeSymbol
.name();
462 if (scope
&& scope
->kind() == Scope::Kind::DerivedType
) {
463 // Nested STRUCTURE: emit entity declarations right now
464 // on the STRUCTURE statement.
466 for (const auto &ref
: scope
->GetSymbols()) {
467 const auto *object
{ref
->detailsIf
<ObjectEntityDetails
>()};
468 if (object
&& object
->type() &&
469 object
->type()->category() == DeclTypeSpec::TypeDerived
&&
470 &object
->type()->derivedTypeSpec().typeSymbol() == &typeSymbol
) {
476 decls_
<< ref
->name();
477 PutShape(decls_
, object
->shape(), '(', ')');
478 PutInit(decls_
, *ref
, object
->init(), nullptr, renamings_
);
479 emittedDECFields_
.insert(*ref
);
481 break; // any later use of this structure will use RECORD/str/
486 PutComponents(typeSymbol
);
487 decls_
<< "end structure\n";
490 // Attributes that may be in a subprogram prefix
491 static const Attrs subprogramPrefixAttrs
{Attr::ELEMENTAL
, Attr::IMPURE
,
492 Attr::MODULE
, Attr::NON_RECURSIVE
, Attr::PURE
, Attr::RECURSIVE
};
494 static void PutOpenACCRoutineInfo(
495 llvm::raw_ostream
&os
, const SubprogramDetails
&details
) {
496 for (auto info
: details
.openACCRoutineInfos()) {
497 os
<< "!$acc routine";
503 if (info
.gangDim() > 0) {
504 os
<< "(dim: " << info
.gangDim() << ")";
507 if (info
.isVector()) {
510 if (info
.isWorker()) {
513 if (info
.isNohost()) {
516 if (info
.bindName()) {
517 os
<< " bind(" << *info
.bindName() << ")";
523 void ModFileWriter::PutSubprogram(const Symbol
&symbol
) {
524 auto &details
{symbol
.get
<SubprogramDetails
>()};
525 if (const Symbol
* interface
{details
.moduleInterface()}) {
526 const Scope
*module
{FindModuleContaining(interface
->owner())};
527 if (module
&& module
!= &symbol
.owner()) {
528 // Interface is in ancestor module
530 PutSubprogram(*interface
);
533 auto attrs
{symbol
.attrs()};
535 if (attrs
.test(Attr::BIND_C
)) {
536 // bind(c) is a suffix, not prefix
537 bindAttrs
.set(Attr::BIND_C
, true);
538 attrs
.set(Attr::BIND_C
, false);
540 bool isAbstract
{attrs
.test(Attr::ABSTRACT
)};
542 attrs
.set(Attr::ABSTRACT
, false);
544 Attrs prefixAttrs
{subprogramPrefixAttrs
& attrs
};
545 // emit any non-prefix attributes in an attribute statement
546 attrs
&= ~subprogramPrefixAttrs
;
548 llvm::raw_string_ostream ss
{ssBuf
};
550 if (!ss
.str().empty()) {
551 decls_
<< ss
.str().substr(1) << "::" << symbol
.name() << '\n';
553 bool isInterface
{details
.isInterface()};
554 llvm::raw_ostream
&os
{isInterface
? decls_
: contains_
};
556 os
<< (isAbstract
? "abstract " : "") << "interface\n";
558 PutAttrs(os
, prefixAttrs
, nullptr, false, ""s
, " "s
);
559 if (auto attrs
{details
.cudaSubprogramAttrs()}) {
560 if (*attrs
== common::CUDASubprogramAttrs::HostDevice
) {
561 os
<< "attributes(host,device) ";
563 PutLower(os
<< "attributes(", common::EnumToString(*attrs
)) << ") ";
565 if (!details
.cudaLaunchBounds().empty()) {
566 os
<< "launch_bounds";
568 for (auto x
: details
.cudaLaunchBounds()) {
574 if (!details
.cudaClusterDims().empty()) {
575 os
<< "cluster_dims";
577 for (auto x
: details
.cudaClusterDims()) {
584 os
<< (details
.isFunction() ? "function " : "subroutine ");
585 os
<< symbol
.name() << '(';
587 for (const auto &dummy
: details
.dummyArgs()) {
598 PutAttrs(os
, bindAttrs
, details
.bindName(), details
.isExplicitBindName(),
600 if (details
.isFunction()) {
601 const Symbol
&result
{details
.result()};
602 if (result
.name() != symbol
.name()) {
603 os
<< " result(" << result
.name() << ')';
607 // walk symbols, collect ones needed for interface
609 details
.entryScope() ? *details
.entryScope() : DEREF(symbol
.scope())};
610 SubprogramSymbolCollector collector
{symbol
, scope
};
612 std::string typeBindingsBuf
;
613 llvm::raw_string_ostream typeBindings
{typeBindingsBuf
};
614 ModFileWriter writer
{context_
};
615 for (const Symbol
&need
: collector
.symbols()) {
616 writer
.PutSymbol(typeBindings
, need
);
618 CHECK(typeBindings
.str().empty());
619 os
<< writer
.uses_
.str();
620 for (const SourceName
&import
: collector
.imports()) {
621 decls_
<< "import::" << import
<< "\n";
623 os
<< writer
.decls_
.str();
624 PutOpenACCRoutineInfo(os
, details
);
627 os
<< "end interface\n";
631 static bool IsIntrinsicOp(const Symbol
&symbol
) {
632 if (const auto *details
{symbol
.GetUltimate().detailsIf
<GenericDetails
>()}) {
633 return details
->kind().IsIntrinsicOperator();
639 void ModFileWriter::PutGeneric(const Symbol
&symbol
) {
640 const auto &genericOwner
{symbol
.owner()};
641 auto &details
{symbol
.get
<GenericDetails
>()};
642 PutGenericName(decls_
<< "interface ", symbol
) << '\n';
643 for (const Symbol
&specific
: details
.specificProcs()) {
644 if (specific
.owner() == genericOwner
) {
645 decls_
<< "procedure::" << specific
.name() << '\n';
648 decls_
<< "end interface\n";
649 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
650 PutGenericName(decls_
<< "private::", symbol
) << '\n';
654 void ModFileWriter::PutUse(const Symbol
&symbol
) {
655 auto &details
{symbol
.get
<UseDetails
>()};
656 auto &use
{details
.symbol()};
657 const Symbol
&module
{GetUsedModule(details
)};
658 if (use
.owner().parent().IsIntrinsicModules()) {
659 uses_
<< "use,intrinsic::";
663 uses_
<< module
.name() << ",only:";
664 PutGenericName(uses_
, symbol
);
665 // Can have intrinsic op with different local-name and use-name
666 // (e.g. `operator(<)` and `operator(.lt.)`) but rename is not allowed
667 if (!IsIntrinsicOp(symbol
) && use
.name() != symbol
.name()) {
668 PutGenericName(uses_
<< "=>", use
);
671 PutUseExtraAttr(Attr::VOLATILE
, symbol
, use
);
672 PutUseExtraAttr(Attr::ASYNCHRONOUS
, symbol
, use
);
673 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
674 PutGenericName(useExtraAttrs_
<< "private::", symbol
) << '\n';
678 // We have "USE local => use" in this module. If attr was added locally
679 // (i.e. on local but not on use), also write it out in the mod file.
680 void ModFileWriter::PutUseExtraAttr(
681 Attr attr
, const Symbol
&local
, const Symbol
&use
) {
682 if (local
.attrs().test(attr
) && !use
.attrs().test(attr
)) {
683 PutAttr(useExtraAttrs_
, attr
) << "::";
684 useExtraAttrs_
<< local
.name() << '\n';
688 static inline SourceName
NameInModuleFile(const Symbol
&symbol
) {
689 if (const auto *use
{symbol
.detailsIf
<UseDetails
>()}) {
690 if (use
->symbol().attrs().test(Attr::PRIVATE
)) {
691 // Avoid the use in sorting of names created to access private
692 // specific procedures as a result of generic resolution;
693 // they're not in the cooked source.
694 return use
->symbol().name();
697 return symbol
.name();
700 // Collect the symbols of this scope sorted by their original order, not name.
701 // Generics and namelists are exceptions: they are sorted after other symbols.
702 void CollectSymbols(const Scope
&scope
, SymbolVector
&sorted
,
703 SymbolVector
&uses
, std::map
<const Symbol
*, SourceName
> &renamings
) {
704 SymbolVector namelist
, generics
;
705 auto symbols
{scope
.GetSymbols()};
706 std::size_t commonSize
{scope
.commonBlocks().size()};
707 sorted
.reserve(symbols
.size() + commonSize
);
708 for (SymbolRef symbol
: symbols
) {
709 if (symbol
->test(Symbol::Flag::ParentComp
)) {
710 } else if (symbol
->has
<NamelistDetails
>()) {
711 namelist
.push_back(symbol
);
712 } else if (const auto *generic
{symbol
->detailsIf
<GenericDetails
>()}) {
713 if (generic
->specific() &&
714 &generic
->specific()->owner() == &symbol
->owner()) {
715 sorted
.push_back(*generic
->specific());
716 } else if (generic
->derivedType() &&
717 &generic
->derivedType()->owner() == &symbol
->owner()) {
718 sorted
.push_back(*generic
->derivedType());
720 generics
.push_back(symbol
);
722 sorted
.push_back(symbol
);
724 if (const auto *details
{symbol
->detailsIf
<GenericDetails
>()}) {
725 uses
.insert(uses
.end(), details
->uses().begin(), details
->uses().end());
728 // Sort most symbols by name: use of Symbol::ReplaceName ensures the source
729 // location of a symbol's name is the first "real" use.
730 auto sorter
{[](SymbolRef x
, SymbolRef y
) {
731 return NameInModuleFile(*x
).begin() < NameInModuleFile(*y
).begin();
733 std::sort(sorted
.begin(), sorted
.end(), sorter
);
734 std::sort(generics
.begin(), generics
.end(), sorter
);
735 sorted
.insert(sorted
.end(), generics
.begin(), generics
.end());
736 sorted
.insert(sorted
.end(), namelist
.begin(), namelist
.end());
737 for (const auto &pair
: scope
.commonBlocks()) {
738 sorted
.push_back(*pair
.second
);
741 sorted
.end() - commonSize
, sorted
.end(), SymbolSourcePositionCompare
{});
744 void ModFileWriter::PutEntity(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
747 [&](const ObjectEntityDetails
&) { PutObjectEntity(os
, symbol
); },
748 [&](const ProcEntityDetails
&) { PutProcEntity(os
, symbol
); },
749 [&](const TypeParamDetails
&) { PutTypeParam(os
, symbol
); },
751 common::die("PutEntity: unexpected details: %s",
752 DetailsToString(symbol
.details()).c_str());
758 void PutShapeSpec(llvm::raw_ostream
&os
, const ShapeSpec
&x
) {
759 if (x
.lbound().isStar()) {
760 CHECK(x
.ubound().isStar());
761 os
<< ".."; // assumed rank
763 if (!x
.lbound().isColon()) {
764 PutBound(os
, x
.lbound());
767 if (!x
.ubound().isColon()) {
768 PutBound(os
, x
.ubound());
773 llvm::raw_ostream
&os
, const ArraySpec
&shape
, char open
, char close
) {
774 if (!shape
.empty()) {
777 for (const auto &shapeSpec
: shape
) {
783 PutShapeSpec(os
, shapeSpec
);
789 void ModFileWriter::PutObjectEntity(
790 llvm::raw_ostream
&os
, const Symbol
&symbol
) {
791 auto &details
{symbol
.get
<ObjectEntityDetails
>()};
792 if (details
.type() &&
793 details
.type()->category() == DeclTypeSpec::TypeDerived
) {
794 const Symbol
&typeSymbol
{details
.type()->derivedTypeSpec().typeSymbol()};
795 if (typeSymbol
.get
<DerivedTypeDetails
>().isDECStructure()) {
796 PutDerivedType(typeSymbol
, &symbol
.owner());
797 if (emittedDECFields_
.find(symbol
) != emittedDECFields_
.end()) {
798 return; // symbol was emitted on STRUCTURE statement
803 os
, symbol
, [&]() { PutType(os
, DEREF(symbol
.GetType())); },
804 getSymbolAttrsToWrite(symbol
));
805 PutShape(os
, details
.shape(), '(', ')');
806 PutShape(os
, details
.coshape(), '[', ']');
807 PutInit(os
, symbol
, details
.init(), details
.unanalyzedPDTComponentInit(),
810 if (auto tkr
{GetIgnoreTKR(symbol
)}; !tkr
.empty()) {
811 os
<< "!dir$ ignore_tkr(";
812 tkr
.IterateOverMembers([&](common::IgnoreTKR tkr
) {
814 SWITCH_COVERS_ALL_CASES
815 case common::IgnoreTKR::Type
:
818 case common::IgnoreTKR::Kind
:
821 case common::IgnoreTKR::Rank
:
824 case common::IgnoreTKR::Device
:
827 case common::IgnoreTKR::Managed
:
830 case common::IgnoreTKR::Contiguous
:
835 os
<< ") " << symbol
.name() << '\n';
837 if (auto attr
{details
.cudaDataAttr()}) {
838 PutLower(os
<< "attributes(", common::EnumToString(*attr
))
839 << ") " << symbol
.name() << '\n';
841 if (symbol
.test(Fortran::semantics::Symbol::Flag::CrayPointer
)) {
842 if (!symbol
.owner().crayPointers().empty()) {
843 for (const auto &[pointee
, pointer
] : symbol
.owner().crayPointers()) {
844 if (pointer
== symbol
) {
845 os
<< "pointer(" << symbol
.name() << "," << pointee
<< ")\n";
852 void ModFileWriter::PutProcEntity(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
853 if (symbol
.attrs().test(Attr::INTRINSIC
)) {
854 os
<< "intrinsic::" << symbol
.name() << '\n';
855 if (!isSubmodule_
&& symbol
.attrs().test(Attr::PRIVATE
)) {
856 os
<< "private::" << symbol
.name() << '\n';
860 const auto &details
{symbol
.get
<ProcEntityDetails
>()};
861 Attrs attrs
{symbol
.attrs()};
862 if (details
.passName()) {
863 attrs
.reset(Attr::PASS
);
869 if (details
.procInterface()) {
870 os
<< details
.procInterface()->name();
871 } else if (details
.type()) {
872 PutType(os
, *details
.type());
875 PutPassName(os
, details
.passName());
882 llvm::raw_ostream
&os
, const std::optional
<SourceName
> &passName
) {
884 os
<< ",pass(" << *passName
<< ')';
888 void ModFileWriter::PutTypeParam(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
889 auto &details
{symbol
.get
<TypeParamDetails
>()};
893 PutType(os
, DEREF(symbol
.GetType()));
894 PutLower(os
<< ',', common::EnumToString(details
.attr()));
897 PutInit(os
, details
.init());
901 void PutInit(llvm::raw_ostream
&os
, const Symbol
&symbol
, const MaybeExpr
&init
,
902 const parser::Expr
*unanalyzed
,
903 const std::map
<const Symbol
*, SourceName
> &renamings
) {
904 if (IsNamedConstant(symbol
) || symbol
.owner().IsDerivedType()) {
905 const char *assign
{symbol
.attrs().test(Attr::POINTER
) ? "=>" : "="};
907 parser::Unparse(os
<< assign
, *unanalyzed
);
909 if (const auto *dtConst
{
910 evaluate::UnwrapExpr
<evaluate::Constant
<evaluate::SomeDerived
>>(
912 const Symbol
&dtSym
{dtConst
->result().derivedTypeSpec().typeSymbol()};
913 if (auto iter
{renamings
.find(&dtSym
)}; iter
!= renamings
.end()) {
914 // Initializer is a constant whose derived type's name has
915 // been brought into scope from a module under a new name
916 // to avoid a conflict.
917 dtConst
->AsFortran(os
<< assign
, &iter
->second
);
921 init
->AsFortran(os
<< assign
);
926 void PutInit(llvm::raw_ostream
&os
, const MaybeIntExpr
&init
) {
928 init
->AsFortran(os
<< '=');
932 void PutBound(llvm::raw_ostream
&os
, const Bound
&x
) {
935 } else if (x
.isColon()) {
938 x
.GetExplicit()->AsFortran(os
);
942 // Write an entity (object or procedure) declaration.
943 // writeType is called to write out the type.
944 void ModFileWriter::PutEntity(llvm::raw_ostream
&os
, const Symbol
&symbol
,
945 std::function
<void()> writeType
, Attrs attrs
) {
947 PutAttrs(os
, attrs
, symbol
.GetBindName(), symbol
.GetIsExplicitBindName());
948 if (symbol
.owner().kind() == Scope::Kind::DerivedType
&&
949 context_
.IsTempName(symbol
.name().ToString())) {
952 os
<< "::" << symbol
.name();
956 // Put out each attribute to os, surrounded by `before` and `after` and
957 // mapped to lower case.
958 llvm::raw_ostream
&ModFileWriter::PutAttrs(llvm::raw_ostream
&os
, Attrs attrs
,
959 const std::string
*bindName
, bool isExplicitBindName
, std::string before
,
960 std::string after
) const {
961 attrs
.set(Attr::PUBLIC
, false); // no need to write PUBLIC
962 attrs
.set(Attr::EXTERNAL
, false); // no need to write EXTERNAL
964 attrs
.set(Attr::PRIVATE
, false);
966 if (bindName
|| isExplicitBindName
) {
967 os
<< before
<< "bind(c";
968 if (isExplicitBindName
) {
969 os
<< ",name=\"" << (bindName
? *bindName
: ""s
) << '"';
972 attrs
.set(Attr::BIND_C
, false);
974 for (std::size_t i
{0}; i
< Attr_enumSize
; ++i
) {
975 Attr attr
{static_cast<Attr
>(i
)};
976 if (attrs
.test(attr
)) {
977 PutAttr(os
<< before
, attr
) << after
;
983 llvm::raw_ostream
&PutAttr(llvm::raw_ostream
&os
, Attr attr
) {
984 return PutLower(os
, AttrToString(attr
));
987 llvm::raw_ostream
&PutType(llvm::raw_ostream
&os
, const DeclTypeSpec
&type
) {
988 return PutLower(os
, type
.AsFortran());
991 llvm::raw_ostream
&PutLower(llvm::raw_ostream
&os
, std::string_view str
) {
993 os
<< parser::ToLowerCaseLetter(c
);
998 void PutOpenACCDirective(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
999 if (symbol
.test(Symbol::Flag::AccDeclare
)) {
1000 os
<< "!$acc declare ";
1001 if (symbol
.test(Symbol::Flag::AccCopy
)) {
1003 } else if (symbol
.test(Symbol::Flag::AccCopyIn
) ||
1004 symbol
.test(Symbol::Flag::AccCopyInReadOnly
)) {
1006 } else if (symbol
.test(Symbol::Flag::AccCopyOut
)) {
1008 } else if (symbol
.test(Symbol::Flag::AccCreate
)) {
1010 } else if (symbol
.test(Symbol::Flag::AccPresent
)) {
1012 } else if (symbol
.test(Symbol::Flag::AccDevicePtr
)) {
1014 } else if (symbol
.test(Symbol::Flag::AccDeviceResident
)) {
1015 os
<< "device_resident";
1016 } else if (symbol
.test(Symbol::Flag::AccLink
)) {
1020 if (symbol
.test(Symbol::Flag::AccCopyInReadOnly
)) {
1023 os
<< symbol
.name() << ")\n";
1027 void PutOpenMPDirective(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
1028 if (symbol
.test(Symbol::Flag::OmpThreadprivate
)) {
1029 os
<< "!$omp threadprivate(" << symbol
.name() << ")\n";
1033 void ModFileWriter::PutDirective(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
1034 PutOpenACCDirective(os
, symbol
);
1035 PutOpenMPDirective(os
, symbol
);
1039 Temp(int fd
, std::string path
) : fd
{fd
}, path
{path
} {}
1040 Temp(Temp
&&t
) : fd
{std::exchange(t
.fd
, -1)}, path
{std::move(t
.path
)} {}
1043 llvm::sys::fs::file_t native
{llvm::sys::fs::convertFDToNativeFile(fd
)};
1044 llvm::sys::fs::closeFile(native
);
1045 llvm::sys::fs::remove(path
.c_str());
1052 // Create a temp file in the same directory and with the same suffix as path.
1053 // Return an open file descriptor and its path.
1054 static llvm::ErrorOr
<Temp
> MkTemp(const std::string
&path
) {
1055 auto length
{path
.length()};
1056 auto dot
{path
.find_last_of("./")};
1058 dot
< length
&& path
[dot
] == '.' ? path
.substr(dot
+ 1) : ""};
1059 CHECK(length
> suffix
.length() &&
1060 path
.substr(length
- suffix
.length()) == suffix
);
1061 auto prefix
{path
.substr(0, length
- suffix
.length())};
1063 llvm::SmallString
<16> tempPath
;
1064 if (std::error_code err
{llvm::sys::fs::createUniqueFile(
1065 prefix
+ "%%%%%%" + suffix
, fd
, tempPath
)}) {
1068 return Temp
{fd
, tempPath
.c_str()};
1071 // Write the module file at path, prepending header. If an error occurs,
1072 // return errno, otherwise 0.
1073 static std::error_code
WriteFile(
1074 const std::string
&path
, const std::string
&contents
, bool debug
) {
1075 auto header
{std::string
{ModHeader::bom
} + ModHeader::magic
+
1076 CheckSum(contents
) + ModHeader::terminator
};
1078 llvm::dbgs() << "Processing module " << path
<< ": ";
1080 if (FileContentsMatch(path
, header
, contents
)) {
1082 llvm::dbgs() << "module unchanged, not writing\n";
1086 llvm::ErrorOr
<Temp
> temp
{MkTemp(path
)};
1088 return temp
.getError();
1090 llvm::raw_fd_ostream
writer(temp
->fd
, /*shouldClose=*/false);
1094 if (writer
.has_error()) {
1095 return writer
.error();
1098 llvm::dbgs() << "module written\n";
1100 return llvm::sys::fs::rename(temp
->path
, path
);
1103 // Return true if the stream matches what we would write for the mod file.
1104 static bool FileContentsMatch(const std::string
&path
,
1105 const std::string
&header
, const std::string
&contents
) {
1106 std::size_t hsize
{header
.size()};
1107 std::size_t csize
{contents
.size()};
1108 auto buf_or
{llvm::MemoryBuffer::getFile(path
)};
1112 auto buf
= std::move(buf_or
.get());
1113 if (buf
->getBufferSize() != hsize
+ csize
) {
1116 if (!std::equal(header
.begin(), header
.end(), buf
->getBufferStart(),
1117 buf
->getBufferStart() + hsize
)) {
1121 return std::equal(contents
.begin(), contents
.end(),
1122 buf
->getBufferStart() + hsize
, buf
->getBufferEnd());
1125 // Compute a simple hash of the contents of a module file and
1126 // return it as a string of hex digits.
1127 // This uses the Fowler-Noll-Vo hash function.
1128 static std::string
CheckSum(const std::string_view
&contents
) {
1129 std::uint64_t hash
{0xcbf29ce484222325ull
};
1130 for (char c
: contents
) {
1132 hash
*= 0x100000001b3;
1134 static const char *digits
= "0123456789abcdef";
1135 std::string
result(ModHeader::sumLen
, '0');
1136 for (size_t i
{ModHeader::sumLen
}; hash
!= 0; hash
>>= 4) {
1137 result
[--i
] = digits
[hash
& 0xf];
1142 static bool VerifyHeader(llvm::ArrayRef
<char> content
) {
1143 std::string_view sv
{content
.data(), content
.size()};
1144 if (sv
.substr(0, ModHeader::magicLen
) != ModHeader::magic
) {
1147 std::string_view expectSum
{sv
.substr(ModHeader::magicLen
, ModHeader::sumLen
)};
1148 std::string actualSum
{CheckSum(sv
.substr(ModHeader::len
))};
1149 return expectSum
== actualSum
;
1152 Scope
*ModFileReader::Read(const SourceName
&name
,
1153 std::optional
<bool> isIntrinsic
, Scope
*ancestor
, bool silent
) {
1154 std::string ancestorName
; // empty for module
1155 Symbol
*notAModule
{nullptr};
1156 bool fatalError
{false};
1158 if (auto *scope
{ancestor
->FindSubmodule(name
)}) {
1161 ancestorName
= ancestor
->GetName().value().ToString();
1163 if (!isIntrinsic
.value_or(false) && !ancestor
) {
1164 // Already present in the symbol table as a usable non-intrinsic module?
1165 auto it
{context_
.globalScope().find(name
)};
1166 if (it
!= context_
.globalScope().end()) {
1167 Scope
*scope
{it
->second
->scope()};
1168 if (scope
->kind() == Scope::Kind::Module
) {
1171 notAModule
= scope
->symbol();
1172 // USE, NON_INTRINSIC global name isn't a module?
1173 fatalError
= isIntrinsic
.has_value();
1177 auto path
{ModFileName(name
, ancestorName
, context_
.moduleFileSuffix())};
1178 parser::Parsing parsing
{context_
.allCookedSources()};
1179 parser::Options options
;
1180 options
.isModuleFile
= true;
1181 options
.features
.Enable(common::LanguageFeature::BackslashEscapes
);
1182 options
.features
.Enable(common::LanguageFeature::OpenMP
);
1183 options
.features
.Enable(common::LanguageFeature::CUDA
);
1184 if (!isIntrinsic
.value_or(false) && !notAModule
) {
1185 // The search for this module file will scan non-intrinsic module
1186 // directories. If a directory is in both the intrinsic and non-intrinsic
1187 // directory lists, the intrinsic module directory takes precedence.
1188 options
.searchDirectories
= context_
.searchDirectories();
1189 for (const auto &dir
: context_
.intrinsicModuleDirectories()) {
1190 options
.searchDirectories
.erase(
1191 std::remove(options
.searchDirectories
.begin(),
1192 options
.searchDirectories
.end(), dir
),
1193 options
.searchDirectories
.end());
1195 options
.searchDirectories
.insert(options
.searchDirectories
.begin(), "."s
);
1197 bool foundNonIntrinsicModuleFile
{false};
1199 std::list
<std::string
> searchDirs
;
1200 for (const auto &d
: options
.searchDirectories
) {
1201 searchDirs
.push_back(d
);
1203 foundNonIntrinsicModuleFile
=
1204 parser::LocateSourceFile(path
, searchDirs
).has_value();
1206 if (isIntrinsic
.value_or(!foundNonIntrinsicModuleFile
)) {
1207 // Explicitly intrinsic, or not specified and not found in the search
1208 // path; see whether it's already in the symbol table as an intrinsic
1210 auto it
{context_
.intrinsicModulesScope().find(name
)};
1211 if (it
!= context_
.intrinsicModulesScope().end()) {
1212 return it
->second
->scope();
1215 // We don't have this module in the symbol table yet.
1216 // Find its module file and parse it. Define or extend the search
1217 // path with intrinsic module directories, if appropriate.
1218 if (isIntrinsic
.value_or(true)) {
1219 for (const auto &dir
: context_
.intrinsicModuleDirectories()) {
1220 options
.searchDirectories
.push_back(dir
);
1223 const auto *sourceFile
{fatalError
? nullptr : parsing
.Prescan(path
, options
)};
1224 if (fatalError
|| parsing
.messages().AnyFatalError()) {
1227 // Module is not explicitly INTRINSIC, and there's already a global
1228 // symbol of the same name that is not a module.
1229 context_
.SayWithDecl(
1230 *notAModule
, name
, "'%s' is not a module"_err_en_US
, name
);
1232 for (auto &msg
: parsing
.messages().messages()) {
1233 std::string str
{msg
.ToString()};
1234 Say(name
, ancestorName
,
1235 parser::MessageFixedText
{str
.c_str(), str
.size(), msg
.severity()},
1243 if (!VerifyHeader(sourceFile
->content())) {
1244 Say(name
, ancestorName
, "File has invalid checksum: %s"_warn_en_US
,
1245 sourceFile
->path());
1248 llvm::raw_null_ostream NullStream
;
1249 parsing
.Parse(NullStream
);
1250 std::optional
<parser::Program
> &parsedProgram
{parsing
.parseTree()};
1251 if (!parsing
.messages().empty() || !parsing
.consumedWholeFile() ||
1253 Say(name
, ancestorName
, "Module file is corrupt: %s"_err_en_US
,
1254 sourceFile
->path());
1257 parser::Program
&parseTree
{context_
.SaveParseTree(std::move(*parsedProgram
))};
1258 Scope
*parentScope
; // the scope this module/submodule goes into
1259 if (!isIntrinsic
.has_value()) {
1260 for (const auto &dir
: context_
.intrinsicModuleDirectories()) {
1261 if (sourceFile
->path().size() > dir
.size() &&
1262 sourceFile
->path().find(dir
) == 0) {
1268 Scope
&topScope
{isIntrinsic
.value_or(false) ? context_
.intrinsicModulesScope()
1269 : context_
.globalScope()};
1270 Symbol
*moduleSymbol
{nullptr};
1271 if (!ancestor
) { // module, not submodule
1272 parentScope
= &topScope
;
1273 auto pair
{parentScope
->try_emplace(name
, UnknownDetails
{})};
1277 moduleSymbol
= &*pair
.first
->second
;
1278 moduleSymbol
->set(Symbol::Flag::ModFile
);
1279 } else if (std::optional
<SourceName
> parent
{GetSubmoduleParent(parseTree
)}) {
1280 // submodule with submodule parent
1281 parentScope
= Read(*parent
, false /*not intrinsic*/, ancestor
, silent
);
1283 // submodule with module parent
1284 parentScope
= ancestor
;
1286 // Process declarations from the module file
1287 bool wasInModuleFile
{context_
.foldingContext().inModuleFile()};
1288 context_
.foldingContext().set_inModuleFile(true);
1289 ResolveNames(context_
, parseTree
, topScope
);
1290 context_
.foldingContext().set_inModuleFile(wasInModuleFile
);
1291 if (!moduleSymbol
) {
1292 // Submodule symbols' storage are owned by their parents' scopes,
1293 // but their names are not in their parents' dictionaries -- we
1294 // don't want to report bogus errors about clashes between submodule
1295 // names and other objects in the parent scopes.
1296 if (Scope
* submoduleScope
{ancestor
->FindSubmodule(name
)}) {
1297 moduleSymbol
= submoduleScope
->symbol();
1299 moduleSymbol
->set(Symbol::Flag::ModFile
);
1304 CHECK(moduleSymbol
->has
<ModuleDetails
>());
1305 CHECK(moduleSymbol
->test(Symbol::Flag::ModFile
));
1306 if (isIntrinsic
.value_or(false)) {
1307 moduleSymbol
->attrs().set(Attr::INTRINSIC
);
1309 return moduleSymbol
->scope();
1315 parser::Message
&ModFileReader::Say(const SourceName
&name
,
1316 const std::string
&ancestor
, parser::MessageFixedText
&&msg
,
1317 const std::string
&arg
) {
1318 return context_
.Say(name
, "Cannot read module file for %s: %s"_err_en_US
,
1319 parser::MessageFormattedText
{ancestor
.empty()
1320 ? "module '%s'"_en_US
1321 : "submodule '%s' of module '%s'"_en_US
,
1324 parser::MessageFormattedText
{std::move(msg
), arg
}.MoveString());
1327 // program was read from a .mod file for a submodule; return the name of the
1328 // submodule's parent submodule, nullptr if none.
1329 static std::optional
<SourceName
> GetSubmoduleParent(
1330 const parser::Program
&program
) {
1331 CHECK(program
.v
.size() == 1);
1332 auto &unit
{program
.v
.front()};
1333 auto &submod
{std::get
<common::Indirection
<parser::Submodule
>>(unit
.u
)};
1335 std::get
<parser::Statement
<parser::SubmoduleStmt
>>(submod
.value().t
)};
1336 auto &parentId
{std::get
<parser::ParentIdentifier
>(stmt
.statement
.t
)};
1337 if (auto &parent
{std::get
<std::optional
<parser::Name
>>(parentId
.t
)}) {
1338 return parent
->source
;
1340 return std::nullopt
;
1344 void SubprogramSymbolCollector::Collect() {
1345 const auto &details
{symbol_
.get
<SubprogramDetails
>()};
1346 isInterface_
= details
.isInterface();
1347 for (const Symbol
*dummyArg
: details
.dummyArgs()) {
1349 DoSymbol(*dummyArg
);
1352 if (details
.isFunction()) {
1353 DoSymbol(details
.result());
1355 for (const auto &pair
: scope_
) {
1356 const Symbol
&symbol
{*pair
.second
};
1357 if (const auto *useDetails
{symbol
.detailsIf
<UseDetails
>()}) {
1358 const Symbol
&ultimate
{useDetails
->symbol().GetUltimate()};
1359 bool needed
{useSet_
.count(ultimate
) > 0};
1360 if (const auto *generic
{ultimate
.detailsIf
<GenericDetails
>()}) {
1361 // The generic may not be needed itself, but the specific procedure
1362 // &/or derived type that it shadows may be needed.
1363 const Symbol
*spec
{generic
->specific()};
1364 const Symbol
*dt
{generic
->derivedType()};
1365 needed
= needed
|| (spec
&& useSet_
.count(*spec
) > 0) ||
1366 (dt
&& useSet_
.count(*dt
) > 0);
1367 } else if (const auto *subp
{ultimate
.detailsIf
<SubprogramDetails
>()}) {
1368 const Symbol
*interface
{ subp
->moduleInterface() };
1369 needed
= needed
|| (interface
&& useSet_
.count(*interface
) > 0);
1372 need_
.push_back(symbol
);
1374 } else if (symbol
.has
<SubprogramDetails
>()) {
1375 // An internal subprogram is needed if it is used as interface
1376 // for a dummy or return value procedure.
1378 const auto hasInterface
{[&symbol
](const Symbol
*s
) -> bool {
1379 // Is 's' a procedure with interface 'symbol'?
1381 if (const auto *sDetails
{s
->detailsIf
<ProcEntityDetails
>()}) {
1382 if (sDetails
->procInterface() == &symbol
) {
1389 for (const Symbol
*dummyArg
: details
.dummyArgs()) {
1390 needed
= needed
|| hasInterface(dummyArg
);
1393 needed
|| (details
.isFunction() && hasInterface(&details
.result()));
1394 if (needed
&& needSet_
.insert(symbol
).second
) {
1395 need_
.push_back(symbol
);
1401 void SubprogramSymbolCollector::DoSymbol(const Symbol
&symbol
) {
1402 DoSymbol(symbol
.name(), symbol
);
1405 // Do symbols this one depends on; then add to need_
1406 void SubprogramSymbolCollector::DoSymbol(
1407 const SourceName
&name
, const Symbol
&symbol
) {
1408 const auto &scope
{symbol
.owner()};
1409 if (scope
!= scope_
&& !scope
.IsDerivedType()) {
1410 if (scope
!= scope_
.parent()) {
1411 useSet_
.insert(symbol
);
1413 if (NeedImport(name
, symbol
)) {
1414 imports_
.insert(name
);
1418 if (!needSet_
.insert(symbol
).second
) {
1419 return; // already done
1421 common::visit(common::visitors
{
1422 [this](const ObjectEntityDetails
&details
) {
1423 for (const ShapeSpec
&spec
: details
.shape()) {
1424 DoBound(spec
.lbound());
1425 DoBound(spec
.ubound());
1427 for (const ShapeSpec
&spec
: details
.coshape()) {
1428 DoBound(spec
.lbound());
1429 DoBound(spec
.ubound());
1431 if (const Symbol
* commonBlock
{details
.commonBlock()}) {
1432 DoSymbol(*commonBlock
);
1435 [this](const CommonBlockDetails
&details
) {
1436 for (const auto &object
: details
.objects()) {
1440 [this](const ProcEntityDetails
&details
) {
1441 if (details
.procInterface()) {
1442 DoSymbol(*details
.procInterface());
1444 DoType(details
.type());
1447 [](const auto &) {},
1450 if (!symbol
.has
<UseDetails
>()) {
1451 DoType(symbol
.GetType());
1453 if (!scope
.IsDerivedType()) {
1454 need_
.push_back(symbol
);
1458 void SubprogramSymbolCollector::DoType(const DeclTypeSpec
*type
) {
1462 switch (type
->category()) {
1463 case DeclTypeSpec::Numeric
:
1464 case DeclTypeSpec::Logical
:
1465 break; // nothing to do
1466 case DeclTypeSpec::Character
:
1467 DoParamValue(type
->characterTypeSpec().length());
1470 if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
1471 const auto &typeSymbol
{derived
->typeSymbol()};
1472 if (const DerivedTypeSpec
* extends
{typeSymbol
.GetParentTypeSpec()}) {
1473 DoSymbol(extends
->name(), extends
->typeSymbol());
1475 for (const auto &pair
: derived
->parameters()) {
1476 DoParamValue(pair
.second
);
1478 for (const auto &pair
: *typeSymbol
.scope()) {
1479 const Symbol
&comp
{*pair
.second
};
1482 DoSymbol(derived
->name(), derived
->typeSymbol());
1487 void SubprogramSymbolCollector::DoBound(const Bound
&bound
) {
1488 if (const MaybeSubscriptIntExpr
& expr
{bound
.GetExplicit()}) {
1492 void SubprogramSymbolCollector::DoParamValue(const ParamValue
¶mValue
) {
1493 if (const auto &expr
{paramValue
.GetExplicit()}) {
1498 // Do we need a IMPORT of this symbol into an interface block?
1499 bool SubprogramSymbolCollector::NeedImport(
1500 const SourceName
&name
, const Symbol
&symbol
) {
1501 if (!isInterface_
) {
1503 } else if (IsSeparateModuleProcedureInterface(&symbol_
)) {
1504 return false; // IMPORT needed only for external and dummy procedure
1506 } else if (&symbol
== scope_
.symbol()) {
1508 } else if (symbol
.owner().Contains(scope_
)) {
1510 } else if (const Symbol
*found
{scope_
.FindSymbol(name
)}) {
1511 // detect import from ancestor of use-associated symbol
1512 return found
->has
<UseDetails
>() && found
->owner() != scope_
;
1514 // "found" can be null in the case of a use-associated derived type's parent
1516 CHECK(symbol
.has
<DerivedTypeDetails
>());
1521 } // namespace Fortran::semantics