mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
[PCH] Mark a PCH file with a flag to indicate if the serialized AST had
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. llvm-svn: 152192
This commit is contained in:
parent
9b2ab81a0c
commit
4a280ff48f
@ -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">;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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())
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
28
clang/test/Index/pch-with-errors.c
Normal file
28
clang/test/Index/pch-with-errors.c
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user