From 1f01f7c160c06f8290b4f1c203e36b242074c6b1 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Tue, 11 Jun 2013 00:36:55 +0000 Subject: [PATCH] [libclang] Allow building a precompiled preamble with compiler errors 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 | 8 ++++++++ include/clang/Serialization/ASTWriter.h | 7 ++++++- lib/Frontend/ASTUnit.cpp | 22 +++++++++++++++------- lib/Frontend/FrontendAction.cpp | 10 +++++++--- lib/Serialization/GeneratePCH.cpp | 17 +++++++++++++---- test/Index/preamble-reparse-with-BOM.m | 6 ++++-- 6 files changed, 53 insertions(+), 17 deletions(-) diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index fee8d95a05..a568ba02d2 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -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: diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index ab8fa079bb..25335967bc 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -747,6 +747,8 @@ class PCHGenerator : public SemaConsumer { SmallVector 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 diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 2d916536d3..b03e71ccbb 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -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? diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index ece51a3570..60e615674f 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -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 //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp index 32c2df3b88..7e8baa2c10 100644 --- a/lib/Serialization/GeneratePCH.cpp +++ b/lib/Serialization/GeneratePCH.cpp @@ -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() { diff --git a/test/Index/preamble-reparse-with-BOM.m b/test/Index/preamble-reparse-with-BOM.m index a2a89c8d8e..6727a7ee1c 100644 --- a/test/Index/preamble-reparse-with-BOM.m +++ b/test/Index/preamble-reparse-with-BOM.m @@ -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] -- 2.40.0