f18's module files are Fortran with a leading header comment containing the module file format version and a hash of the following contents. This hash is currently used only to protect module files against corruption and truncation. Extend the use of these hashes to catch or avoid some error cases. When one module file depends upon another, note its hash in additional module file header comments. This allows the compiler to detect when the module dependency is on a module file that has been updated. Further, it allows the compiler to find the right module file dependency when the same module file name appears in multiple directories on the module search path. The order in which module files are written, when multiple modules appear in a source file, is such that every dependency is written before the module(s) that depend upon it, so that their hashes are known. A warning is emitted when a module file is not the first hit on the module file search path. Further work is needed to add a compiler option that emits (larger) stand-alone module files that incorporate copies of their dependencies rather than relying on search paths. This will be desirable for application libraries that want to ship only "top-level" module files without needing to include their dependencies. Another future work item would be to admit multiple modules in the same compilation with the same name if they have distinct hashes.
104 lines
3.4 KiB
C++
104 lines
3.4 KiB
C++
//===-- lib/Semantics/mod-file.h --------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef FORTRAN_SEMANTICS_MOD_FILE_H_
|
|
#define FORTRAN_SEMANTICS_MOD_FILE_H_
|
|
|
|
#include "flang/Semantics/attr.h"
|
|
#include "flang/Semantics/symbol.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <string>
|
|
|
|
namespace Fortran::parser {
|
|
class CharBlock;
|
|
class Message;
|
|
class MessageFixedText;
|
|
} // namespace Fortran::parser
|
|
|
|
namespace llvm {
|
|
class raw_ostream;
|
|
}
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
using SourceName = parser::CharBlock;
|
|
class Symbol;
|
|
class Scope;
|
|
class SemanticsContext;
|
|
|
|
class ModFileWriter {
|
|
public:
|
|
explicit ModFileWriter(SemanticsContext &context) : context_{context} {}
|
|
bool WriteAll();
|
|
|
|
private:
|
|
SemanticsContext &context_;
|
|
// Buffers to use with raw_string_ostream
|
|
std::string needsBuf_;
|
|
std::string usesBuf_;
|
|
std::string useExtraAttrsBuf_;
|
|
std::string declsBuf_;
|
|
std::string containsBuf_;
|
|
// Tracks nested DEC structures and fields of that type
|
|
UnorderedSymbolSet emittedDECStructures_, emittedDECFields_;
|
|
|
|
llvm::raw_string_ostream needs_{needsBuf_};
|
|
llvm::raw_string_ostream uses_{usesBuf_};
|
|
llvm::raw_string_ostream useExtraAttrs_{
|
|
useExtraAttrsBuf_}; // attrs added to used entity
|
|
llvm::raw_string_ostream decls_{declsBuf_};
|
|
llvm::raw_string_ostream contains_{containsBuf_};
|
|
bool isSubmodule_{false};
|
|
std::map<const Symbol *, SourceName> renamings_;
|
|
|
|
void WriteAll(const Scope &);
|
|
void WriteOne(const Scope &);
|
|
void Write(const Symbol &);
|
|
std::string GetAsString(const Symbol &);
|
|
void PrepareRenamings(const Scope &);
|
|
void PutSymbols(const Scope &);
|
|
// Returns true if a derived type with bindings and "contains" was emitted
|
|
bool PutComponents(const Symbol &);
|
|
void PutSymbol(llvm::raw_ostream &, const Symbol &);
|
|
void PutEntity(llvm::raw_ostream &, const Symbol &);
|
|
void PutEntity(
|
|
llvm::raw_ostream &, const Symbol &, std::function<void()>, Attrs);
|
|
void PutObjectEntity(llvm::raw_ostream &, const Symbol &);
|
|
void PutProcEntity(llvm::raw_ostream &, const Symbol &);
|
|
void PutDerivedType(const Symbol &, const Scope * = nullptr);
|
|
void PutDECStructure(const Symbol &, const Scope * = nullptr);
|
|
void PutTypeParam(llvm::raw_ostream &, const Symbol &);
|
|
void PutSubprogram(const Symbol &);
|
|
void PutGeneric(const Symbol &);
|
|
void PutUse(const Symbol &);
|
|
void PutUseExtraAttr(Attr, const Symbol &, const Symbol &);
|
|
llvm::raw_ostream &PutAttrs(llvm::raw_ostream &, Attrs,
|
|
const std::string * = nullptr, bool = false, std::string before = ","s,
|
|
std::string after = ""s) const;
|
|
void PutDirective(llvm::raw_ostream &, const Symbol &);
|
|
};
|
|
|
|
class ModFileReader {
|
|
public:
|
|
ModFileReader(SemanticsContext &context) : context_{context} {}
|
|
// Find and read the module file for a module or submodule.
|
|
// If ancestor is specified, look for a submodule of that module.
|
|
// Return the Scope for that module/submodule or nullptr on error.
|
|
Scope *Read(SourceName, std::optional<bool> isIntrinsic, Scope *ancestor,
|
|
bool silent);
|
|
|
|
private:
|
|
SemanticsContext &context_;
|
|
|
|
parser::Message &Say(SourceName, const std::string &,
|
|
parser::MessageFixedText &&, const std::string &);
|
|
};
|
|
|
|
} // namespace Fortran::semantics
|
|
#endif
|