summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Driver/Tools.cpp10
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp25
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp26
-rw-r--r--clang/lib/Serialization/ASTReader.cpp49
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp10
5 files changed, 97 insertions, 23 deletions
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp
index 9e71c31c623..73437f68f35 100644
--- a/clang/lib/Driver/Tools.cpp
+++ b/clang/lib/Driver/Tools.cpp
@@ -3289,6 +3289,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
+ Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
+
+ if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
+ if (!Args.getLastArg(options::OPT_fbuild_session_timestamp))
+ D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
+
+ Args.AddLastArg(CmdArgs,
+ options::OPT_fmodules_validate_once_per_build_session);
+ }
+
// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
options::OPT_faccess_control,
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index d1211801253..61fe26c9222 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1057,41 +1057,38 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
continue;
// Walk all of the files within this directory.
- bool RemovedAllFiles = true;
for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
// We only care about module and global module index files.
- if (llvm::sys::path::extension(File->path()) != ".pcm" &&
- llvm::sys::path::filename(File->path()) != "modules.idx") {
- RemovedAllFiles = false;
+ StringRef Extension = llvm::sys::path::extension(File->path());
+ if (Extension != ".pcm" && Extension != ".timestamp" &&
+ llvm::sys::path::filename(File->path()) != "modules.idx")
continue;
- }
// Look at this file. If we can't stat it, there's nothing interesting
// there.
- if (::stat(File->path().c_str(), &StatBuf)) {
- RemovedAllFiles = false;
+ if (::stat(File->path().c_str(), &StatBuf))
continue;
- }
// If the file has been used recently enough, leave it there.
time_t FileAccessTime = StatBuf.st_atime;
if (CurrentTime - FileAccessTime <=
time_t(HSOpts.ModuleCachePruneAfter)) {
- RemovedAllFiles = false;
continue;
}
// Remove the file.
- bool Existed;
- if (llvm::sys::fs::remove(File->path(), Existed) || !Existed) {
- RemovedAllFiles = false;
- }
+ llvm::sys::fs::remove(File->path());
+
+ // Remove the timestamp file.
+ std::string TimpestampFilename = File->path() + ".timestamp";
+ llvm::sys::fs::remove(TimpestampFilename);
}
// If we removed all of the files in the directory, remove the directory
// itself.
- if (RemovedAllFiles)
+ if (llvm::sys::fs::directory_iterator(Dir->path(), EC) ==
+ llvm::sys::fs::directory_iterator() && !EC)
llvm::sys::fs::remove(Dir->path());
}
}
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 5320415ecb4..5b26df037f6 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -924,6 +924,10 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
getLastArgIntValue(Args, OPT_fmodules_prune_interval, 7 * 24 * 60 * 60);
Opts.ModuleCachePruneAfter =
getLastArgIntValue(Args, OPT_fmodules_prune_after, 31 * 24 * 60 * 60);
+ Opts.ModulesValidateOncePerBuildSession =
+ Args.hasArg(OPT_fmodules_validate_once_per_build_session);
+ Opts.BuildSessionTimestamp =
+ getLastArgUInt64Value(Args, OPT_fbuild_session_timestamp, 0);
for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro),
ie = Args.filtered_end();
it != ie; ++it) {
@@ -1837,10 +1841,11 @@ std::string CompilerInvocation::getModuleHash() const {
namespace clang {
-// Declared in clang/Frontend/Utils.h.
-int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
- DiagnosticsEngine *Diags) {
- int Res = Default;
+template<typename IntTy>
+static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id,
+ IntTy Default,
+ DiagnosticsEngine *Diags) {
+ IntTy Res = Default;
if (Arg *A = Args.getLastArg(Id)) {
if (StringRef(A->getValue()).getAsInteger(10, Res)) {
if (Diags)
@@ -1851,6 +1856,19 @@ int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
return Res;
}
+
+// Declared in clang/Frontend/Utils.h.
+int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
+ DiagnosticsEngine *Diags) {
+ return getLastArgIntValueImpl<int>(Args, Id, Default, Diags);
+}
+
+uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,
+ uint64_t Default,
+ DiagnosticsEngine *Diags) {
+ return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags);
+}
+
void BuryPointer(const void *Ptr) {
// This function may be called only a small fixed amount of times per each
// invocation, otherwise we do actually have a leak which we want to report.
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 674aefeb1c5..fb1d7edcbad 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -49,6 +49,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cstdio>
@@ -1827,16 +1828,28 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
return Failure;
- case llvm::BitstreamEntry::EndBlock:
- // Validate all of the non-system input files.
- if (!DisableValidation) {
+ case llvm::BitstreamEntry::EndBlock: {
+ // Validate input files.
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ if (!DisableValidation &&
+ (!HSOpts.ModulesValidateOncePerBuildSession ||
+ F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp)) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
// All user input files reside at the index range [0, Record[1]), and
// system input files reside at [Record[1], Record[0]).
// Record is the one from INPUT_FILE_OFFSETS.
+ //
+ // If we are reading a module, we will create a verification timestamp,
+ // so we verify all input files. Otherwise, verify only user input
+ // files.
unsigned NumInputs = Record[0];
unsigned NumUserInputs = Record[1];
- unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs;
+ unsigned N = ValidateSystemInputs ||
+ (HSOpts.ModulesValidateOncePerBuildSession &&
+ F.Kind == MK_Module)
+ ? NumInputs
+ : NumUserInputs;
for (unsigned I = 0; I < N; ++I) {
InputFile IF = getInputFile(F, I+1, Complain);
if (!IF.getFile() || IF.isOutOfDate())
@@ -1844,7 +1857,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
}
return Success;
-
+ }
+
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
case INPUT_FILES_BLOCK_ID:
@@ -2922,6 +2936,16 @@ bool ASTReader::isGlobalIndexUnavailable() const {
!hasGlobalIndex() && TriedLoadingGlobalIndex;
}
+static void updateModuleTimestamp(ModuleFile &MF) {
+ // Overwrite the timestamp file contents so that file's mtime changes.
+ std::string TimestampFilename = MF.getTimestampFilename();
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream OS(TimestampFilename.c_str(), ErrorInfo);
+ if (!ErrorInfo.empty())
+ return;
+ OS << "Timestamp file\n";
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type,
SourceLocation ImportLoc,
@@ -3080,6 +3104,21 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
PreviousGeneration);
}
+ if (PP.getHeaderSearchInfo()
+ .getHeaderSearchOpts()
+ .ModulesValidateOncePerBuildSession) {
+ // Now we are certain that the module and all modules it depends on are
+ // up to date. Create or update timestamp files for modules that are
+ // located in the module cache (not for PCH files that could be anywhere
+ // in the filesystem).
+ for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
+ ImportedModule &M = Loaded[I];
+ if (M.Mod->Kind == MK_Module) {
+ updateModuleTimestamp(*M.Mod);
+ }
+ }
+ }
+
return Success;
}
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index 9c4b3d92bef..711afcd2dca 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -86,6 +86,16 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
NewModule = true;
ModuleEntry = New;
+ New->InputFilesValidationTimestamp = 0;
+ if (New->Kind == MK_Module) {
+ std::string TimestampFilename = New->getTimestampFilename();
+ llvm::sys::fs::file_status Status;
+ // A cached stat value would be fine as well.
+ if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
+ New->InputFilesValidationTimestamp =
+ Status.getLastModificationTime().toEpochTime();
+ }
+
// Load the contents of the module
if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
// The buffer was already provided for us.
OpenPOWER on IntegriCloud