diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInstance.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 49 | ||||
-rw-r--r-- | clang/lib/Serialization/ModuleManager.cpp | 10 |
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. |