]> granicus.if.org Git - clang/commitdiff
[PCH] Mark a PCH file with a flag to indicate if the serialized AST had
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 7 Mar 2012 01:51:17 +0000 (01:51 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 7 Mar 2012 01:51:17 +0000 (01:51 +0000)
compiler errors or not.

-Control whether ASTReader should reject such a PCH by a boolean flag at ASTReader's creation time.
By default, such a PCH file will be rejected with an error when trying to load it.

[libclang] Allow clang_saveTranslationUnit to create a PCH file even if compiler errors
occurred.
-Have libclang API calls accept a PCH that had compiler errors.

The general idea is that we want libclang to stay functional even if a PCH had a compiler error.
rdar://10976363.

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

15 files changed:
include/clang/Basic/DiagnosticSerializationKinds.td
include/clang/Frontend/ASTUnit.h
include/clang/Frontend/CompilerInstance.h
include/clang/Frontend/PreprocessorOptions.h
include/clang/Serialization/ASTReader.h
include/clang/Serialization/ASTWriter.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/FrontendAction.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Index/pch-with-errors.c [new file with mode: 0644]
test/Index/werror.c
tools/libclang/CIndex.cpp
tools/libclang/Indexing.cpp

index 9a86ebfad86195c25b8f3762b6ffb79a393b8df1..7f9fe262f7f64b9f77e4ab7978263aa00a21f30e 100644 (file)
@@ -37,6 +37,8 @@ def warn_pch_version_too_new : Error<
     "PCH file uses a newer PCH format that cannot be read">;
 def warn_pch_different_branch : Error<
     "PCH file built from a different branch (%0) than the compiler (%1)">;
+def err_pch_with_compiler_errors : Error<
+    "PCH file contains compiler errors">;
 def warn_cmdline_conflicting_macro_def : Error<
     "definition of the macro '%0' conflicts with the definition used to "
     "build the precompiled header">;
index 210c7ce23eeaedea9c6812d8c52ad1e42ac0965a..3d0639561a5a88547395178959c51870841201f4 100644 (file)
@@ -642,7 +642,8 @@ public:
                                   bool OnlyLocalDecls = false,
                                   RemappedFile *RemappedFiles = 0,
                                   unsigned NumRemappedFiles = 0,
-                                  bool CaptureDiagnostics = false);
+                                  bool CaptureDiagnostics = false,
+                                  bool AllowPCHWithCompilerErrors = false);
 
 private:
   /// \brief Helper function for \c LoadFromCompilerInvocation() and
@@ -730,7 +731,8 @@ public:
                                       bool RemappedFilesKeepOriginalName = true,
                                       bool PrecompilePreamble = false,
                                       TranslationUnitKind TUKind = TU_Complete,
-                                      bool CacheCodeCompletionResults = false);
+                                      bool CacheCodeCompletionResults = false,
+                                      bool AllowPCHWithCompilerErrors = false);
   
   /// \brief Reparse the source files using the same command-line options that
   /// were originally used to produce this translation unit.
index ff0c30939a411e53d68904aa242f96f1a028aaa3..1bb76952d5a9646e2f6ba7a24800d1c997971d76 100644 (file)
@@ -535,6 +535,7 @@ public:
   void createPCHExternalASTSource(StringRef Path,
                                   bool DisablePCHValidation,
                                   bool DisableStatCache,
+                                  bool AllowPCHWithCompilerErrors,
                                   void *DeserializationListener);
 
   /// Create an external AST source to read a PCH file.
@@ -544,6 +545,7 @@ public:
   createPCHExternalASTSource(StringRef Path, const std::string &Sysroot,
                              bool DisablePCHValidation,
                              bool DisableStatCache,
+                             bool AllowPCHWithCompilerErrors,
                              Preprocessor &PP, ASTContext &Context,
                              void *DeserializationListener, bool Preamble);
 
index 4a0de963820941363fb5f3163bd9a47658bc280e..d86a923d43074d5c8b4fa3fa1630f920a103f8b7 100644 (file)
@@ -69,6 +69,9 @@ public:
   /// precompiled header or AST file.
   bool DisableStatCache;
 
+  /// \brief When true, a PCH with compiler errors will not be rejected.
+  bool AllowPCHWithCompilerErrors;
+
   /// \brief Dump declarations that are deserialized from PCH, for testing.
   bool DumpDeserializedPCHDecls;
 
@@ -165,6 +168,7 @@ public:
   PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
                           DetailedRecordConditionalDirectives(false),
                           DisablePCHValidation(false), DisableStatCache(false),
+                          AllowPCHWithCompilerErrors(false),
                           DumpDeserializedPCHDecls(false),
                           PrecompiledPreambleBytes(0, true),
                           RemappedFilesKeepOriginalName(true),
index 3ad132c19fe7e9875dca0f0a3bb55c54c8cd3ccf..d0cdbeabbb56f46a15c676b3e1a028962dc832f2 100644 (file)
@@ -579,6 +579,9 @@ private:
   /// \brief Whether to disable the use of stat caches in AST files.
   bool DisableStatCache;
 
+  /// \brief Whether to accept an AST file with compiler errors.
+  bool AllowASTWithCompilerErrors;
+
   /// \brief The current "generation" of the module file import stack, which 
   /// indicates how many separate module file load operations have occurred.
   unsigned CurrentGeneration;
@@ -875,8 +878,13 @@ public:
   /// help when an AST file is being used in cases where the
   /// underlying files in the file system may have changed, but
   /// parsing should still continue.
+  ///
+  /// \param AllowASTWithCompilerErrors If true, the AST reader will accept an
+  /// AST file the was created out of an AST with compiler errors,
+  /// otherwise it will reject it.
   ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "",
-            bool DisableValidation = false, bool DisableStatCache = false);
+            bool DisableValidation = false, bool DisableStatCache = false,
+            bool AllowASTWithCompilerErrors = false);
 
   ~ASTReader();
 
index 940c86ab333c59a69b3ba820426e4f04a569618c..4c62385cf2c2e1651efca9357f6e7be4639f6010 100644 (file)
@@ -109,6 +109,9 @@ private:
   /// serialization, rather than just queueing updates.
   bool WritingAST;
 
+  /// \brief Indicates that the AST contained compiler errors.
+  bool ASTHasCompilerErrors;
+
   /// \brief Stores a declaration or a type to be written to the AST file.
   class DeclOrType {
   public:
@@ -467,7 +470,8 @@ public:
   /// are relative to the given system root.
   void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
                 const std::string &OutputFile,
-                Module *WritingModule, StringRef isysroot);
+                Module *WritingModule, StringRef isysroot,
+                bool hasErrors = false);
 
   /// \brief Emit a source location.
   void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record);
index c1678d4ef01a37d5a86682f1f34de283a69b659f..82e3382780538881f9cf9e41b759fd5d2ee98ddc 100644 (file)
@@ -652,7 +652,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
                                   bool OnlyLocalDecls,
                                   RemappedFile *RemappedFiles,
                                   unsigned NumRemappedFiles,
-                                  bool CaptureDiagnostics) {
+                                  bool CaptureDiagnostics,
+                                  bool AllowPCHWithCompilerErrors) {
   OwningPtr<ASTUnit> AST(new ASTUnit(true));
 
   // Recover resources if we crash before exiting this method.
@@ -748,7 +749,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
                             /*DelayInitialization=*/true);
   ASTContext &Context = *AST->Ctx;
 
-  Reader.reset(new ASTReader(PP, Context));
+  Reader.reset(new ASTReader(PP, Context,
+                             /*isysroot=*/"",
+                             /*DisableValidation=*/false,
+                             /*DisableStatCache=*/false,
+                             AllowPCHWithCompilerErrors));
   
   // Recover resources if we crash before exiting this method.
   llvm::CrashRecoveryContextCleanupRegistrar<ASTReader>
@@ -1862,7 +1867,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
                                       bool RemappedFilesKeepOriginalName,
                                       bool PrecompilePreamble,
                                       TranslationUnitKind TUKind,
-                                      bool CacheCodeCompletionResults) {
+                                      bool CacheCodeCompletionResults,
+                                      bool AllowPCHWithCompilerErrors) {
   if (!Diags.getPtr()) {
     // No diagnostics engine was provided, so create our own diagnostics object
     // with the default options.
@@ -1898,8 +1904,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
       CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname);
     }
   }
-  CI->getPreprocessorOpts().RemappedFilesKeepOriginalName =
-                                                  RemappedFilesKeepOriginalName;
+  PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
+  PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
+  PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
   
   // Override the resources path.
   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
@@ -2388,9 +2395,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
 }
 
 CXSaveError ASTUnit::Save(StringRef File) {
-  if (getDiagnostics().hasUnrecoverableErrorOccurred())
-    return CXSaveError_TranslationErrors;
-
   // Write to a temporary file and later rename it to the actual file, to avoid
   // possible race conditions.
   SmallString<128> TempPath;
@@ -2420,14 +2424,13 @@ CXSaveError ASTUnit::Save(StringRef File) {
 }
 
 bool ASTUnit::serialize(raw_ostream &OS) {
-  if (getDiagnostics().hasErrorOccurred())
-    return true;
+  bool hasErrors = getDiagnostics().hasErrorOccurred();
 
   SmallString<128> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
   ASTWriter Writer(Stream);
   // FIXME: Handle modules
-  Writer.WriteAST(getSema(), 0, std::string(), 0, "");
+  Writer.WriteAST(getSema(), 0, std::string(), 0, "", hasErrors);
   
   // Write the generated bitstream to "Out".
   if (!Buffer.empty())
index c6838be7af0299751b5197c143989e2d3b5b1107..60273816d910c0c0f31d8ac37f0a3a2d5cdef7bf 100644 (file)
@@ -306,12 +306,14 @@ void CompilerInstance::createASTContext() {
 void CompilerInstance::createPCHExternalASTSource(StringRef Path,
                                                   bool DisablePCHValidation,
                                                   bool DisableStatCache,
+                                                bool AllowPCHWithCompilerErrors,
                                                  void *DeserializationListener){
   OwningPtr<ExternalASTSource> Source;
   bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
   Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
                                           DisablePCHValidation,
                                           DisableStatCache,
+                                          AllowPCHWithCompilerErrors,
                                           getPreprocessor(), getASTContext(),
                                           DeserializationListener,
                                           Preamble));
@@ -324,6 +326,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
                                              const std::string &Sysroot,
                                              bool DisablePCHValidation,
                                              bool DisableStatCache,
+                                             bool AllowPCHWithCompilerErrors,
                                              Preprocessor &PP,
                                              ASTContext &Context,
                                              void *DeserializationListener,
@@ -331,7 +334,8 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
   OwningPtr<ASTReader> Reader;
   Reader.reset(new ASTReader(PP, Context,
                              Sysroot.empty() ? "" : Sysroot.c_str(),
-                             DisablePCHValidation, DisableStatCache));
+                             DisablePCHValidation, DisableStatCache,
+                             AllowPCHWithCompilerErrors));
 
   Reader->setDeserializationListener(
             static_cast<ASTDeserializationListener *>(DeserializationListener));
index 4bc6dada70821ea7289b902e5ed170931ac28625..f687ccb22b4e2996071d76d9dd9b7bb3e913b3b2 100644 (file)
@@ -268,6 +268,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
                                 CI.getPreprocessorOpts().ImplicitPCHInclude,
                                 CI.getPreprocessorOpts().DisablePCHValidation,
                                 CI.getPreprocessorOpts().DisableStatCache,
+                            CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
                                 DeserialListener);
       if (!CI.getASTContext().getExternalSource())
         goto failure;
index 39f24da6d40f572501214a162810a811c7667e61..5684949e7eb5a213da759118b88993fbaceb2098 100644 (file)
@@ -1807,6 +1807,12 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
         return IgnorePCH;
       }
 
+      bool hasErrors = Record[5];
+      if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
+        Diag(diag::err_pch_with_compiler_errors);
+        return IgnorePCH;
+      }
+
       RelocatablePCH = Record[4];
       if (Listener) {
         std::string TargetTriple(BlobStart, BlobLen);
@@ -6282,14 +6288,15 @@ void ASTReader::FinishedDeserializing() {
 
 ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
                      StringRef isysroot, bool DisableValidation,
-                     bool DisableStatCache)
+                     bool DisableStatCache, bool AllowASTWithCompilerErrors)
   : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
     SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
     Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
     Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()),
     RelocatablePCH(false), isysroot(isysroot),
     DisableValidation(DisableValidation),
-    DisableStatCache(DisableStatCache), 
+    DisableStatCache(DisableStatCache),
+    AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), 
     CurrentGeneration(0), NumStatHits(0), NumStatMisses(0), 
     NumSLocEntriesRead(0), TotalNumSLocEntries(0), 
     NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), 
index 88c1f70021efd2e9802090e77272083c81884a0a..4edfbff28880587d285c4d10db5e1cb62f3c576d 100644 (file)
@@ -981,6 +981,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
   MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
   MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
   MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
+  MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Has errors
   MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
   unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
 
@@ -991,6 +992,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
   Record.push_back(CLANG_VERSION_MAJOR);
   Record.push_back(CLANG_VERSION_MINOR);
   Record.push_back(!isysroot.empty());
+  Record.push_back(ASTHasCompilerErrors);
   const std::string &Triple = Target.getTriple().getTriple();
   Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple);
 
@@ -3115,7 +3117,7 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
 
 ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
   : Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0),
-    WritingAST(false),
+    WritingAST(false), ASTHasCompilerErrors(false),
     FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
     FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
     FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), 
@@ -3144,9 +3146,12 @@ ASTWriter::~ASTWriter() {
 
 void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
                          const std::string &OutputFile,
-                         Module *WritingModule, StringRef isysroot) {
+                         Module *WritingModule, StringRef isysroot,
+                         bool hasErrors) {
   WritingAST = true;
   
+  ASTHasCompilerErrors = hasErrors;
+  
   // Emit the file header.
   Stream.Emit((unsigned)'C', 8);
   Stream.Emit((unsigned)'P', 8);
diff --git a/test/Index/pch-with-errors.c b/test/Index/pch-with-errors.c
new file mode 100644 (file)
index 0000000..21cf32a
--- /dev/null
@@ -0,0 +1,28 @@
+
+#ifndef HEADER
+#define HEADER
+
+void erroneous(int);
+void erroneous(float);
+
+#else
+
+void foo(void) {
+  erroneous(0);
+}
+
+#endif
+
+// RUN: c-index-test -write-pch %t.h.pch %s
+// RUN: c-index-test -test-load-source local %s -include %t.h | FileCheck -check-prefix=CHECK-PARSE %s
+// RUN: c-index-test -index-file %s -include %t.h | FileCheck -check-prefix=CHECK-INDEX %s
+
+// CHECK-PARSE: pch-with-errors.c:10:6: FunctionDecl=foo:10:6 (Definition) Extent=[10:1 - 12:2]
+// CHECK-PARSE: pch-with-errors.c:11:3: CallExpr=erroneous:5:6 Extent=[11:3 - 11:15]
+
+// CHECK-INDEX: [indexDeclaration]: kind: function | name: foo
+// CHECK-INDEX: [indexEntityReference]: kind: function | name: erroneous
+
+// RUN: %clang -fsyntax-only %s -include %t.h 2>&1 | FileCheck -check-prefix=PCH-ERR %s
+
+// PCH-ERR: error: PCH file contains compiler errors
index 150095d8599cb6297f17b3781b5523561d482ad6..98b602a170c00033e15c26aa389c22867e80c719 100644 (file)
@@ -7,9 +7,6 @@ void fatal(int);
 void fatal(float);
 #endif
 
-// CHECK-FATAL: translation errors
-
 // RUN: c-index-test -write-pch %t.pch -Werror %s
-// RUN: not c-index-test -write-pch %t.pch -DFATAL -Werror %s 2>%t.err
-// RUN: FileCheck -check-prefix=CHECK-FATAL %s < %t.err
+// RUN: c-index-test -write-pch %t.pch -DFATAL -Werror %s
 
index 3b025951884a936bd9a84925c4fbe1c2d56c12c5..7e4a1ede74f0bef7b348c8e8c96dab5b487871f6 100644 (file)
@@ -2438,7 +2438,9 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
                                   CXXIdx->getOnlyLocalDecls(),
-                                  0, 0, true);
+                                  0, 0,
+                                  /*CaptureDiagnostics=*/true,
+                                  /*AllowPCHWithCompilerErrors=*/true);
   return MakeCXTranslationUnit(TU);
 }
 
@@ -2575,7 +2577,8 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
                                  /*RemappedFilesKeepOriginalName=*/true,
                                  PrecompilePreamble,
                                  TUKind,
-                                 CacheCodeCompetionResults));
+                                 CacheCodeCompetionResults,
+                                 /*AllowPCHWithCompilerErrors=*/true));
 
   if (NumErrors != Diags->getClient()->getNumErrors()) {
     // Make sure to check that 'Unit' is non-NULL.
index 1475859e3355eb371c60757f836a22d628e3d9b3..aad6e02fe98653a81230db8d1ca0cec62b58425b 100644 (file)
@@ -369,6 +369,7 @@ static void clang_indexSourceFile_Impl(void *UserData) {
   bool CacheCodeCompletionResults = false;
   PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); 
   PPOpts.DetailedRecord = false;
+  PPOpts.AllowPCHWithCompilerErrors = true;
 
   if (requestedToGetTU) {
     OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();