From d9a30af25b22ddb336644cac36a653a706ccc5dc Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 2 Aug 2010 20:51:39 +0000 Subject: [PATCH] When using a precompiled preamble, save the diagnostics produced when creating the preamble and "replay" them when reusing the preamble. Also, fix a thinko in the copying of the preamble when building the precompiled preamble. llvm-svn: 110061 --- clang/include/clang/Basic/Diagnostic.h | 8 +++- clang/include/clang/Frontend/ASTUnit.h | 18 ++++++++- clang/lib/Frontend/ASTUnit.cpp | 56 +++++++++++++++++++------- clang/test/Index/Inputs/preamble.h | 7 +++- clang/test/Index/preamble.c | 4 +- 5 files changed, 74 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index c67de985a023..4371bdda0a86 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -398,6 +398,10 @@ public: unsigned getNumErrorsSuppressed() const { return NumErrorsSuppressed; } unsigned getNumWarnings() const { return NumWarnings; } + void setNumWarnings(unsigned NumWarnings) { + this->NumWarnings = NumWarnings; + } + /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is /// registered and created, otherwise the existing ID is returned. @@ -943,7 +947,9 @@ public: Diagnostic::Level getLevel() const { return Level; } const FullSourceLoc &getLocation() const { return Loc; } llvm::StringRef getMessage() const { return Message; } - + + void setLocation(FullSourceLoc Loc) { this->Loc = Loc; } + typedef std::vector::const_iterator range_iterator; range_iterator range_begin() const { return Ranges.begin(); } range_iterator range_end() const { return Ranges.end(); } diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index b9db4beafd46..ad622c55e65c 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -149,7 +149,23 @@ private: /// the main file when it has been padded for use with the precompiled /// preamble. llvm::MemoryBuffer *SavedMainFileBuffer; - + + /// \brief The number of warnings that occurred while parsing the preamble. + /// + /// This value will be used to restore the state of the \c Diagnostic object + /// when re-using the precompiled preamble. Note that only the + /// number of warnings matters, since we will not save the preamble + /// when any errors are present. + unsigned NumWarningsInPreamble; + + /// \brief The number of diagnostics that were stored when parsing + /// the precompiled preamble. + /// + /// This value is used to determine how many of the stored + /// diagnostics should be retained when reparsing in the presence of + /// a precompiled preamble. + unsigned NumStoredDiagnosticsInPreamble; + /// \brief The group of timers associated with this translation unit. llvm::OwningPtr TimerGroup; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index d7597bcf5b18..b36a338c196d 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -381,9 +381,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Clear out old caches and data. TopLevelDecls.clear(); - StoredDiagnostics.clear(); CleanTemporaryFiles(); PreprocessedEntitiesByFile.clear(); + + if (!OverrideMainBuffer) + StoredDiagnostics.clear(); // Capture any diagnostics that would otherwise be dropped. CaptureDroppedDiagnostics Capture(CaptureDiagnostics, @@ -409,6 +411,17 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Keep track of the override buffer; SavedMainFileBuffer = OverrideMainBuffer; + + // The stored diagnostic has the old source manager in it; update + // the locations to refer into the new source manager. Since we've + // been careful to make sure that the source manager's state + // before and after are identical, so that we can reuse the source + // location itself. + for (unsigned I = 0, N = StoredDiagnostics.size(); I != N; ++I) { + FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), + getSourceManager()); + StoredDiagnostics[I].setLocation(Loc); + } } llvm::OwningPtr Act; @@ -430,11 +443,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { Act->EndSourceFile(); // Remove the overridden buffer we used for the preamble. - if (OverrideMainBuffer) { + if (OverrideMainBuffer) PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); - PreprocessorOpts.DisablePCHValidation = true; - } Clang.takeDiagnosticClient(); @@ -627,7 +638,7 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { NewPreamble.second.first) == 0) { // The preamble has not changed. We may be able to re-use the precompiled // preamble. - + // Check that none of the files used by the preamble have changed. bool AnyFileChanged = false; @@ -687,7 +698,19 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { } if (!AnyFileChanged) { - // Okay! Re-use the precompiled preamble. + // Okay! We can re-use the precompiled preamble. + + // Set the state of the diagnostic object to mimic its state + // after parsing the preamble. + getDiagnostics().Reset(); + getDiagnostics().setNumWarnings(NumWarningsInPreamble); + if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble) + StoredDiagnostics.erase( + StoredDiagnostics.begin() + NumStoredDiagnosticsInPreamble, + StoredDiagnostics.end()); + + // Create a version of the main file buffer that is padded to + // buffer size we reserved when creating the preamble. return CreatePaddedMainFileBuffer(NewPreamble.first, CreatedPreambleBuffer, PreambleReservedSize, @@ -718,6 +741,13 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { else PreambleReservedSize *= 2; + // Save the preamble text for later; we'll need to compare against it for + // subsequent reparses. + Preamble.assign(NewPreamble.first->getBufferStart(), + NewPreamble.first->getBufferStart() + + NewPreamble.second.first); + PreambleEndsAtStartOfLine = NewPreamble.second.second; + llvm::MemoryBuffer *PreambleBuffer = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize, FrontendOpts.Inputs[0].second); @@ -726,13 +756,6 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { memset(const_cast(PreambleBuffer->getBufferStart()) + Preamble.size(), ' ', PreambleReservedSize - Preamble.size() - 1); const_cast(PreambleBuffer->getBufferEnd())[-1] = '\n'; - - // Save the preamble text for later; we'll need to compare against it for - // subsequent reparses. - Preamble.assign(NewPreamble.first->getBufferStart(), - NewPreamble.first->getBufferStart() - + NewPreamble.second.first); - PreambleEndsAtStartOfLine = NewPreamble.second.second; // Remap the main source file to the preamble buffer. llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second); @@ -786,7 +809,7 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { // Capture any diagnostics that would otherwise be dropped. CaptureDroppedDiagnostics Capture(CaptureDiagnostics, - Clang.getDiagnostics(), + getDiagnostics(), StoredDiagnostics); // Create a file manager object to provide access to and cache the filesystem. @@ -833,6 +856,8 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { // Keep track of the preamble we precompiled. PreambleFile = FrontendOpts.OutputFile; + NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); + NumWarningsInPreamble = getDiagnostics().getNumWarnings(); // Keep track of all of the files that the source manager knows about, // so we can verify whether they have changed or not. @@ -1003,7 +1028,8 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { OverrideMainBuffer = BuildPrecompiledPreamble(); // Clear out the diagnostics state. - getDiagnostics().Reset(); + if (!OverrideMainBuffer) + getDiagnostics().Reset(); // Parse the sources bool Result = Parse(OverrideMainBuffer); diff --git a/clang/test/Index/Inputs/preamble.h b/clang/test/Index/Inputs/preamble.h index e588c12ddcb5..b59c234e1732 100644 --- a/clang/test/Index/Inputs/preamble.h +++ b/clang/test/Index/Inputs/preamble.h @@ -1 +1,6 @@ -int bar(int); +inline int bar(int i) { + int *ptr = 0; + float *ptr1; + ptr = ptr1; + return 0; +} diff --git a/clang/test/Index/preamble.c b/clang/test/Index/preamble.c index f6d878b9eb98..e1a64c2fbe18 100644 --- a/clang/test/Index/preamble.c +++ b/clang/test/Index/preamble.c @@ -3,6 +3,8 @@ int wibble(int); // RUN: %clang -x c-header -o %t.pch %S/Inputs/prefix.h -// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s | FileCheck %s +// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck %s +// RUN: FileCheck -check-prefix CHECK-DIAG %s < %t.stderr.txt // CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:5 - 3:16] // CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16] +// CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *'