forked from OSchip/llvm-project
[modules] If we hit a failure while loading a PCH/module, abort parsing instead of trying to continue in an invalid state.
Also don't let libclang create a PCH with such an error. Fixes rdar://13953768 llvm-svn: 182629
This commit is contained in:
parent
aa79068157
commit
dc9fdaf217
|
@ -75,6 +75,7 @@ private:
|
|||
IntrusiveRefCntPtr<TargetOptions> TargetOpts;
|
||||
IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
|
||||
ASTReader *Reader;
|
||||
bool HadModuleLoaderFatalFailure;
|
||||
|
||||
struct ASTWriterData;
|
||||
OwningPtr<ASTWriterData> WriterData;
|
||||
|
|
|
@ -664,6 +664,10 @@ public:
|
|||
SourceLocation ImportLoc,
|
||||
bool Complain);
|
||||
|
||||
bool hadModuleLoaderFatalFailure() const {
|
||||
return ModuleLoader::HadFatalFailure;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -54,6 +54,8 @@ public:
|
|||
/// then loading that module.
|
||||
class ModuleLoader {
|
||||
public:
|
||||
ModuleLoader() : HadFatalFailure(false) {}
|
||||
|
||||
virtual ~ModuleLoader();
|
||||
|
||||
/// \brief Attempt to load the given module.
|
||||
|
@ -85,6 +87,8 @@ public:
|
|||
Module::NameVisibilityKind Visibility,
|
||||
SourceLocation ImportLoc,
|
||||
bool Complain) = 0;
|
||||
|
||||
bool HadFatalFailure;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -457,6 +457,10 @@ public:
|
|||
/// \brief Retrieve the module loader associated with this preprocessor.
|
||||
ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
|
||||
|
||||
bool hadModuleLoaderFatalFailure() const {
|
||||
return TheModuleLoader.HadFatalFailure;
|
||||
}
|
||||
|
||||
/// \brief True if we are currently preprocessing a #if or #elif directive
|
||||
bool isParsingIfOrElifDirective() const {
|
||||
return ParsingIfOrElifDirective;
|
||||
|
|
|
@ -398,7 +398,8 @@ private:
|
|||
/// \brief Abruptly cut off parsing; mainly used when we have reached the
|
||||
/// code-completion point.
|
||||
void cutOffParsing() {
|
||||
PP.setCodeCompletionReached();
|
||||
if (PP.isCodeCompletionEnabled())
|
||||
PP.setCodeCompletionReached();
|
||||
// Cut off parsing by acting as if we reached the end-of-file.
|
||||
Tok.setKind(tok::eof);
|
||||
}
|
||||
|
|
|
@ -309,6 +309,10 @@ private:
|
|||
/// \brief The module manager which manages modules and their dependencies
|
||||
ModuleManager ModuleMgr;
|
||||
|
||||
/// \brief The location where the module file will be considered as
|
||||
/// imported from. For non-module AST types it should be invalid.
|
||||
SourceLocation CurrentImportLoc;
|
||||
|
||||
/// \brief The global module index, if loaded.
|
||||
llvm::OwningPtr<GlobalModuleIndex> GlobalIndex;
|
||||
|
||||
|
|
|
@ -216,7 +216,8 @@ const unsigned DefaultPreambleRebuildInterval = 5;
|
|||
static llvm::sys::cas_flag ActiveASTUnitObjects;
|
||||
|
||||
ASTUnit::ASTUnit(bool _MainFileIsAST)
|
||||
: Reader(0), OnlyLocalDecls(false), CaptureDiagnostics(false),
|
||||
: Reader(0), HadModuleLoaderFatalFailure(false),
|
||||
OnlyLocalDecls(false), CaptureDiagnostics(false),
|
||||
MainFileIsAST(_MainFileIsAST),
|
||||
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
|
||||
OwnsRemappedFileBuffers(true),
|
||||
|
@ -1705,6 +1706,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
|
|||
CI.setFileManager(0);
|
||||
Target = &CI.getTarget();
|
||||
Reader = CI.getModuleManager();
|
||||
HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
|
||||
}
|
||||
|
||||
StringRef ASTUnit::getMainFileName() const {
|
||||
|
@ -2504,6 +2506,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
|
|||
}
|
||||
|
||||
bool ASTUnit::Save(StringRef File) {
|
||||
if (HadModuleLoaderFatalFailure)
|
||||
return true;
|
||||
|
||||
// Write to a temporary file and later rename it to the actual file, to avoid
|
||||
// possible race conditions.
|
||||
SmallString<128> TempPath;
|
||||
|
|
|
@ -1247,12 +1247,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
|||
case ASTReader::VersionMismatch:
|
||||
case ASTReader::ConfigurationMismatch:
|
||||
case ASTReader::HadErrors:
|
||||
ModuleLoader::HadFatalFailure = true;
|
||||
// FIXME: The ASTReader will already have complained, but can we showhorn
|
||||
// that diagnostic information into a more useful form?
|
||||
KnownModules[Path[0].first] = 0;
|
||||
return ModuleLoadResult();
|
||||
|
||||
case ASTReader::Failure:
|
||||
ModuleLoader::HadFatalFailure = true;
|
||||
// Already complained, but note now that we failed.
|
||||
KnownModules[Path[0].first] = 0;
|
||||
ModuleBuildFailed = true;
|
||||
|
|
|
@ -3426,6 +3426,12 @@ HandleDirective:
|
|||
FormTokenWithChars(Result, CurPtr, tok::hash);
|
||||
PP->HandleDirective(Result);
|
||||
|
||||
if (PP->hadModuleLoaderFatalFailure()) {
|
||||
// With a fatal failure in the module loader, we abort parsing.
|
||||
assert(Result.is(tok::eof) && "Preprocessor did not set tok:eof");
|
||||
return;
|
||||
}
|
||||
|
||||
// As an optimization, if the preprocessor didn't switch lexers, tail
|
||||
// recurse.
|
||||
if (PP->isCurrentLexer(this)) {
|
||||
|
|
|
@ -1512,6 +1512,20 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
|
|||
/*IsIncludeDirective=*/true);
|
||||
assert((Imported == 0 || Imported == SuggestedModule) &&
|
||||
"the imported module is different than the suggested one");
|
||||
|
||||
if (!Imported && hadModuleLoaderFatalFailure()) {
|
||||
// With a fatal failure in the module loader, we abort parsing.
|
||||
Token &Result = IncludeTok;
|
||||
if (CurLexer) {
|
||||
Result.startToken();
|
||||
CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof);
|
||||
CurLexer->cutOffLexing();
|
||||
} else {
|
||||
assert(CurPTHLexer && "#include but no current lexer set!");
|
||||
CurPTHLexer->getEOF(Result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If this header isn't part of the module we're building, we're done.
|
||||
if (!BuildingImportedModule && Imported) {
|
||||
|
|
|
@ -1884,7 +1884,13 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
|
|||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
|
||||
if (PP.hadModuleLoaderFatalFailure()) {
|
||||
// With a fatal failure in the module loader, we abort parsing.
|
||||
cutOffParsing();
|
||||
return DeclGroupPtrTy();
|
||||
}
|
||||
|
||||
DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path);
|
||||
ExpectAndConsumeSemi(diag::err_module_expected_semi);
|
||||
if (Import.isInvalid())
|
||||
|
|
|
@ -2900,6 +2900,9 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
|
|||
ModuleKind Type,
|
||||
SourceLocation ImportLoc,
|
||||
unsigned ClientLoadCapabilities) {
|
||||
llvm::SaveAndRestore<SourceLocation>
|
||||
SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
|
||||
|
||||
// Bump the generation number.
|
||||
unsigned PreviousGeneration = CurrentGeneration++;
|
||||
|
||||
|
@ -7167,7 +7170,7 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
|
|||
}
|
||||
|
||||
DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
|
||||
return Diag(SourceLocation(), DiagID);
|
||||
return Diag(CurrentImportLoc, DiagID);
|
||||
}
|
||||
|
||||
DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: touch %t/Module.pcm
|
||||
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -fdisable-module-hash -F %S/Inputs -verify
|
||||
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -fdisable-module-hash -F %S/Inputs -DIMPLICIT -verify
|
||||
|
||||
// This tests that after a fatal module loader error, we do not continue parsing.
|
||||
|
||||
#ifdef IMPLICIT
|
||||
|
||||
// expected-error@+1{{does not appear to be}}
|
||||
#import <Module/Module.h>
|
||||
#pragma clang __debug crash;
|
||||
|
||||
#else
|
||||
|
||||
// expected-error@+1{{does not appear to be}}
|
||||
@import Module;
|
||||
#pragma clang __debug crash;
|
||||
|
||||
#endif
|
||||
|
||||
// Also check that libclang does not create a PCH with such an error.
|
||||
// RUN: c-index-test -write-pch %t.pch -fmodules -fmodules-cache-path=%t %s \
|
||||
// RUN: -Xclang -fdisable-module-hash -F %S/Inputs 2>&1 | Filecheck %s
|
||||
// CHECK: Unable to write PCH file
|
Loading…
Reference in New Issue