"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">;
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
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.
void createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
bool DisableStatCache,
+ bool AllowPCHWithCompilerErrors,
void *DeserializationListener);
/// Create an external AST source to read a PCH file.
createPCHExternalASTSource(StringRef Path, const std::string &Sysroot,
bool DisablePCHValidation,
bool DisableStatCache,
+ bool AllowPCHWithCompilerErrors,
Preprocessor &PP, ASTContext &Context,
void *DeserializationListener, bool Preamble);
/// 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;
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
DetailedRecordConditionalDirectives(false),
DisablePCHValidation(false), DisableStatCache(false),
+ AllowPCHWithCompilerErrors(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
RemappedFilesKeepOriginalName(true),
/// \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;
/// 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();
/// 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:
/// 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);
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.
/*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>
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.
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;
}
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;
}
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())
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));
const std::string &Sysroot,
bool DisablePCHValidation,
bool DisableStatCache,
+ bool AllowPCHWithCompilerErrors,
Preprocessor &PP,
ASTContext &Context,
void *DeserializationListener,
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));
CI.getPreprocessorOpts().ImplicitPCHInclude,
CI.getPreprocessorOpts().DisablePCHValidation,
CI.getPreprocessorOpts().DisableStatCache,
+ CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
DeserialListener);
if (!CI.getASTContext().getExternalSource())
goto failure;
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);
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),
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);
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);
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),
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);
--- /dev/null
+
+#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
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
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);
}
/*RemappedFilesKeepOriginalName=*/true,
PrecompilePreamble,
TUKind,
- CacheCodeCompetionResults));
+ CacheCodeCompetionResults,
+ /*AllowPCHWithCompilerErrors=*/true));
if (NumErrors != Diags->getClient()->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
bool CacheCodeCompletionResults = false;
PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
PPOpts.DetailedRecord = false;
+ PPOpts.AllowPCHWithCompilerErrors = true;
if (requestedToGetTU) {
OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();