aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-07-31 00:40:00 +0000
committerDouglas Gregor <dgregor@apple.com>2010-07-31 00:40:00 +0000
commitcc5888d833caf90ebda37f24da40d2cd06b4d820 (patch)
tree6dc571d547e7b6116db03fa68d26420f3fdb2aa2
parent036cdf05ef011f564fdec3cf949fbcec41a71a77 (diff)
Implement dependency analysis for the precompiled preamble. If any of
the files in the precompiled preamble have changed since it was build, force the preamble to be rebuilt. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109937 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/SourceManager.h6
-rw-r--r--include/clang/Frontend/ASTUnit.h13
-rw-r--r--lib/Basic/Diagnostic.cpp33
-rw-r--r--lib/Frontend/ASTUnit.cpp105
4 files changed, 125 insertions, 32 deletions
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index b6a1ac4492..dc314f1f07 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -110,6 +110,12 @@ namespace SrcMgr {
Buffer.setPointer(B);
Buffer.setInt(false);
}
+
+ /// \brief Get the underlying buffer, returning NULL if the buffer is not
+ /// yet available.
+ const llvm::MemoryBuffer *getRawBuffer() const {
+ return Buffer.getPointer();
+ }
/// \brief Replace the existing buffer (which will be deleted)
/// with the given buffer.
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 56e73d9be4..b9db4beafd 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -21,6 +21,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Index/ASTLocation.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/System/Path.h"
#include "llvm/Support/Timer.h"
#include <map>
@@ -28,6 +29,7 @@
#include <vector>
#include <cassert>
#include <utility>
+#include <sys/types.h>
namespace llvm {
class MemoryBuffer;
@@ -135,14 +137,21 @@ private:
/// \brief The size of the source buffer that we've reserved for the main
/// file within the precompiled preamble.
unsigned PreambleReservedSize;
-
+
+ /// \brief Keeps track of the files that were used when computing the
+ /// preamble, with both their buffer size and their modification time.
+ ///
+ /// If any of the files have changed from one compile to the next,
+ /// the preamble must be thrown away.
+ llvm::StringMap<std::pair<off_t, time_t> > FilesInPreamble;
+
/// \brief When non-NULL, this is the buffer used to store the contents of
/// the main file when it has been padded for use with the precompiled
/// preamble.
llvm::MemoryBuffer *SavedMainFileBuffer;
/// \brief The group of timers associated with this translation unit.
- llvm::OwningPtr<llvm::TimerGroup> TimerGroup;
+ llvm::OwningPtr<llvm::TimerGroup> TimerGroup;
/// \brief The timers we've created from the various parses, reparses, etc.
/// involved in this translation unit.
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 74937910d9..0dc57e4ecb 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -251,6 +251,23 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = 0;
+ AllExtensionsSilenced = 0;
+ IgnoreAllWarnings = false;
+ WarningsAsErrors = false;
+ ErrorsAsFatal = false;
+ SuppressSystemWarnings = false;
+ SuppressAllDiagnostics = false;
+ ShowOverloads = Ovl_All;
+ ExtBehavior = Ext_Ignore;
+
+ ErrorLimit = 0;
+ TemplateBacktraceLimit = 0;
+ CustomDiagInfo = 0;
+
+ // Set all mappings to 'unset'.
+ DiagMappingsStack.clear();
+ DiagMappingsStack.push_back(DiagMappings());
+
Reset();
}
@@ -315,31 +332,15 @@ bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID,
}
void Diagnostic::Reset() {
- AllExtensionsSilenced = 0;
- IgnoreAllWarnings = false;
- WarningsAsErrors = false;
- ErrorsAsFatal = false;
- SuppressSystemWarnings = false;
- SuppressAllDiagnostics = false;
- ShowOverloads = Ovl_All;
- ExtBehavior = Ext_Ignore;
-
ErrorOccurred = false;
FatalErrorOccurred = false;
- ErrorLimit = 0;
- TemplateBacktraceLimit = 0;
NumWarnings = 0;
NumErrors = 0;
NumErrorsSuppressed = 0;
- CustomDiagInfo = 0;
CurDiagID = ~0U;
LastDiagLevel = Ignored;
DelayedDiagID = 0;
-
- // Set all mappings to 'unset'.
- DiagMappingsStack.clear();
- DiagMappingsStack.push_back(DiagMappings());
}
/// getDescription - Given a diagnostic ID, return a description of the
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 7f42fa949e..d7597bcf5b 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -36,6 +36,7 @@
#include "llvm/Support/Timer.h"
#include <cstdlib>
#include <cstdio>
+#include <sys/stat.h>
using namespace clang;
ASTUnit::ASTUnit(bool _MainFileIsAST)
@@ -626,14 +627,72 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
NewPreamble.second.first) == 0) {
// The preamble has not changed. We may be able to re-use the precompiled
// preamble.
- // FIXME: Check that none of the files used by the preamble have changed.
+ // Check that none of the files used by the preamble have changed.
+ bool AnyFileChanged = false;
+
+ // First, make a record of those files that have been overridden via
+ // remapping or unsaved_files.
+ llvm::StringMap<std::pair<off_t, time_t> > OverriddenFiles;
+ for (PreprocessorOptions::remapped_file_iterator
+ R = PreprocessorOpts.remapped_file_begin(),
+ REnd = PreprocessorOpts.remapped_file_end();
+ !AnyFileChanged && R != REnd;
+ ++R) {
+ struct stat StatBuf;
+ if (stat(R->second.c_str(), &StatBuf)) {
+ // If we can't stat the file we're remapping to, assume that something
+ // horrible happened.
+ AnyFileChanged = true;
+ break;
+ }
- // Okay! Re-use the precompiled preamble.
- return CreatePaddedMainFileBuffer(NewPreamble.first,
- CreatedPreambleBuffer,
- PreambleReservedSize,
- FrontendOpts.Inputs[0].second);
+ OverriddenFiles[R->first] = std::make_pair(StatBuf.st_size,
+ StatBuf.st_mtime);
+ }
+ for (PreprocessorOptions::remapped_file_buffer_iterator
+ R = PreprocessorOpts.remapped_file_buffer_begin(),
+ REnd = PreprocessorOpts.remapped_file_buffer_end();
+ !AnyFileChanged && R != REnd;
+ ++R) {
+ // FIXME: Should we actually compare the contents of file->buffer
+ // remappings?
+ OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(),
+ 0);
+ }
+
+ // Check whether anything has changed.
+ for (llvm::StringMap<std::pair<off_t, time_t> >::iterator
+ F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
+ !AnyFileChanged && F != FEnd;
+ ++F) {
+ llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden
+ = OverriddenFiles.find(F->first());
+ if (Overridden != OverriddenFiles.end()) {
+ // This file was remapped; check whether the newly-mapped file
+ // matches up with the previous mapping.
+ if (Overridden->second != F->second)
+ AnyFileChanged = true;
+ continue;
+ }
+
+ // The file was not remapped; check whether it has changed on disk.
+ struct stat StatBuf;
+ if (stat(F->first(), &StatBuf)) {
+ // If we can't stat the file, assume that something horrible happened.
+ AnyFileChanged = true;
+ } else if (StatBuf.st_size != F->second.first ||
+ StatBuf.st_mtime != F->second.second)
+ AnyFileChanged = true;
+ }
+
+ if (!AnyFileChanged) {
+ // Okay! Re-use the precompiled preamble.
+ return CreatePaddedMainFileBuffer(NewPreamble.first,
+ CreatedPreambleBuffer,
+ PreambleReservedSize,
+ FrontendOpts.Inputs[0].second);
+ }
}
// We can't reuse the previously-computed preamble. Build a new one.
@@ -768,14 +827,31 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
delete NewPreamble.first;
if (PreambleTimer)
PreambleTimer->stopTimer();
- if (PreambleTimer)
- PreambleTimer->stopTimer();
return 0;
}
// Keep track of the preamble we precompiled.
PreambleFile = FrontendOpts.OutputFile;
+
+ // Keep track of all of the files that the source manager knows about,
+ // so we can verify whether they have changed or not.
+ FilesInPreamble.clear();
+ SourceManager &SourceMgr = Clang.getSourceManager();
+ const llvm::MemoryBuffer *MainFileBuffer
+ = SourceMgr.getBuffer(SourceMgr.getMainFileID());
+ for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
+ FEnd = SourceMgr.fileinfo_end();
+ F != FEnd;
+ ++F) {
+ const FileEntry *File = F->second->Entry;
+ if (!File || F->second->getRawBuffer() == MainFileBuffer)
+ continue;
+
+ FilesInPreamble[File->getName()]
+ = std::make_pair(F->second->getSize(), File->getModificationTime());
+ }
+
if (PreambleTimer)
PreambleTimer->stopTimer();
@@ -913,6 +989,13 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
Timers.push_back(ReparsingTimer);
}
+ // Remap files.
+ // FIXME: Do we want to remove old mappings for these files?
+ Invocation->getPreprocessorOpts().clearRemappedFiles();
+ for (unsigned I = 0; I != NumRemappedFiles; ++I)
+ Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
+
// If we have a preamble file lying around, build or reuse the precompiled
// preamble.
llvm::MemoryBuffer *OverrideMainBuffer = 0;
@@ -922,12 +1005,6 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
// Clear out the diagnostics state.
getDiagnostics().Reset();
- // Remap files.
- Invocation->getPreprocessorOpts().clearRemappedFiles();
- for (unsigned I = 0; I != NumRemappedFiles; ++I)
- Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
- RemappedFiles[I].second);
-
// Parse the sources
bool Result = Parse(OverrideMainBuffer);
if (ReparsingTimer)