]> granicus.if.org Git - clang/commitdiff
[libclang] Allow building a precompiled preamble with compiler errors
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 11 Jun 2013 00:36:55 +0000 (00:36 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 11 Jun 2013 00:36:55 +0000 (00:36 +0000)
A while ago we allowed libclang to build a PCH that had compiler errors; this was to retain the performance
afforded by a PCH even if the user's code is in an intermediate state.

Extend this for the precompiled preamble as well.

rdar://14109828

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183717 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Frontend/FrontendAction.h
include/clang/Serialization/ASTWriter.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/FrontendAction.cpp
lib/Serialization/GeneratePCH.cpp
test/Index/preamble-reparse-with-BOM.m

index fee8d95a05ba8bdf55d3c0b104668930df898c2a..a568ba02d2a0cc45d951e37106b1d32f240ec18e 100644 (file)
@@ -94,6 +94,14 @@ protected:
   /// BeginSourceFileAction (and BeginSourceFile).
   virtual void EndSourceFileAction() {}
 
+  /// \brief Callback at the end of processing a single input, to determine
+  /// if the output files should be erased or not.
+  ///
+  /// By default it returns true if a compiler error occurred.
+  /// This is guaranteed to only be called following a successful call to
+  /// BeginSourceFileAction (and BeginSourceFile).
+  virtual bool shouldEraseOutputFiles();
+
   /// @}
 
 public:
index ab8fa079bb4f1e619aef50371daac1d109840696..25335967bc05d7e090f0c517dfb3f8affc94b968 100644 (file)
@@ -747,6 +747,8 @@ class PCHGenerator : public SemaConsumer {
   SmallVector<char, 128> Buffer;
   llvm::BitstreamWriter Stream;
   ASTWriter Writer;
+  bool AllowASTWithErrors;
+  bool HasEmittedPCH;
 
 protected:
   ASTWriter &getWriter() { return Writer; }
@@ -755,12 +757,15 @@ protected:
 public:
   PCHGenerator(const Preprocessor &PP, StringRef OutputFile,
                clang::Module *Module,
-               StringRef isysroot, raw_ostream *Out);
+               StringRef isysroot, raw_ostream *Out,
+               bool AllowASTWithErrors = false);
   ~PCHGenerator();
   virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
   virtual void HandleTranslationUnit(ASTContext &Ctx);
   virtual ASTMutationListener *GetASTMutationListener();
   virtual ASTDeserializationListener *GetASTDeserializationListener();
+
+  bool hasEmittedPCH() const { return HasEmittedPCH; }
 };
 
 } // end namespace clang
index 2d916536d3d2f75fc5d65dc8573224b9060f7a22..b03e71ccbbd422c19aa439101dd9e105a7b3bef6 100644 (file)
@@ -974,8 +974,8 @@ class PrecompilePreambleConsumer : public PCHGenerator {
 public:
   PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP, 
                              StringRef isysroot, raw_ostream *Out)
-    : PCHGenerator(PP, "", 0, isysroot, Out), Unit(Unit),
-      Hash(Unit.getCurrentTopLevelHashValue()) {
+    : PCHGenerator(PP, "", 0, isysroot, Out, /*AllowASTWithErrors=*/true),
+      Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()) {
     Hash = 0;
   }
 
@@ -996,7 +996,7 @@ public:
 
   virtual void HandleTranslationUnit(ASTContext &Ctx) {
     PCHGenerator::HandleTranslationUnit(Ctx);
-    if (!Unit.getDiagnostics().hasErrorOccurred()) {
+    if (hasEmittedPCH()) {
       // Translate the top-level declarations we captured during
       // parsing into declaration IDs in the precompiled
       // preamble. This will allow us to deserialize those top-level
@@ -1010,9 +1010,11 @@ public:
 
 class PrecompilePreambleAction : public ASTFrontendAction {
   ASTUnit &Unit;
+  PrecompilePreambleConsumer *PreambleConsumer;
 
 public:
-  explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {}
+  explicit PrecompilePreambleAction(ASTUnit &Unit)
+    : Unit(Unit), PreambleConsumer(0) {}
 
   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
                                          StringRef InFile) {
@@ -1029,10 +1031,16 @@ public:
 
     CI.getPreprocessor().addPPCallbacks(
      new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
-    return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Sysroot, 
-                                          OS);
+    PreambleConsumer = new PrecompilePreambleConsumer(Unit,CI.getPreprocessor(),
+                                                      Sysroot, OS);
+    return PreambleConsumer;
   }
 
+  bool hasEmittedPreamblePCH() const {
+    return PreambleConsumer && PreambleConsumer->hasEmittedPCH();
+  }
+  virtual bool shouldEraseOutputFiles() { return !hasEmittedPreamblePCH(); }
+
   virtual bool hasCodeCompletionSupport() const { return false; }
   virtual bool hasASTFileSupport() const { return false; }
   virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; }
@@ -1622,7 +1630,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
   Act->Execute();
   Act->EndSourceFile();
 
-  if (Diagnostics->hasErrorOccurred()) {
+  if (!Act->hasEmittedPreamblePCH()) {
     // There were errors parsing the preamble, so no precompiled header was
     // generated. Forget that we even tried.
     // FIXME: Should we leave a note for ourselves to try again?
index ece51a35707d6db785413bd8c63b74e87c2575e8..60e615674fa0fed6d7ff3605a736971b49f828fd 100644 (file)
@@ -429,9 +429,9 @@ void FrontendAction::EndSourceFile() {
     llvm::errs() << "\n";
   }
 
-  // Cleanup the output streams, and erase the output files if we encountered
-  // an error.
-  CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().hasErrorOccurred());
+  // Cleanup the output streams, and erase the output files if instructed by the
+  // FrontendAction.
+  CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles());
 
   if (isCurrentFileAST()) {
     CI.takeSema();
@@ -445,6 +445,10 @@ void FrontendAction::EndSourceFile() {
   setCurrentInput(FrontendInputFile());
 }
 
+bool FrontendAction::shouldEraseOutputFiles() {
+  return getCompilerInstance().getDiagnostics().hasErrorOccurred();
+}
+
 //===----------------------------------------------------------------------===//
 // Utility Actions
 //===----------------------------------------------------------------------===//
index 32c2df3b88d290ae1b0439c6ce153d9a5de07979..7e8baa2c1095bf8bd7dca529e4f038798ea80cc5 100644 (file)
@@ -28,22 +28,29 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP,
                            StringRef OutputFile,
                            clang::Module *Module,
                            StringRef isysroot,
-                           raw_ostream *OS)
+                           raw_ostream *OS, bool AllowASTWithErrors)
   : PP(PP), OutputFile(OutputFile), Module(Module), 
     isysroot(isysroot.str()), Out(OS), 
-    SemaPtr(0), Stream(Buffer), Writer(Stream) {
+    SemaPtr(0), Stream(Buffer), Writer(Stream),
+    AllowASTWithErrors(AllowASTWithErrors),
+    HasEmittedPCH(false) {
 }
 
 PCHGenerator::~PCHGenerator() {
 }
 
 void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
-  if (PP.getDiagnostics().hasErrorOccurred())
+  // Don't create a PCH if there were fatal failures during module loading.
+  if (PP.getModuleLoader().HadFatalFailure)
+    return;
+
+  bool hasErrors = PP.getDiagnostics().hasErrorOccurred();
+  if (hasErrors && !AllowASTWithErrors)
     return;
   
   // Emit the PCH file
   assert(SemaPtr && "No Sema?");
-  Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot);
+  Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, hasErrors);
 
   // Write the generated bitstream to "Out".
   Out->write((char *)&Buffer.front(), Buffer.size());
@@ -53,6 +60,8 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
 
   // Free up some memory, in case the process is kept alive.
   Buffer.clear();
+
+  HasEmittedPCH = true;
 }
 
 ASTMutationListener *PCHGenerator::GetASTMutationListener() {
index a2a89c8d8e15033cc0b76aa6878a5dae18480c55..6727a7ee1cac78121cadd11d8aba1b4dadf8d779 100644 (file)
@@ -2,5 +2,7 @@
 @interface I2
 @end
 
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_FAILONERROR=1 \
-// RUN:   c-index-test -test-load-source-reparse 1 local %s
+// RUN: env CINDEXTEST_EDITING=1 \
+// RUN:   c-index-test -test-load-source-reparse 1 local %s | FileCheck %s
+
+// CHECK: preamble-reparse-with-BOM.m:2:12: ObjCInterfaceDecl=I2:2:12 Extent=[2:1 - 3:5]