forked from OSchip/llvm-project
Teach SourceManager::getSLocEntry() that it can fail due to problems
during deserialization from a precompiled header, and update all of its callers to note when this problem occurs and recover (more) gracefully. Fixes <rdar://problem/9119249>. llvm-svn: 129839
This commit is contained in:
parent
cd01ed5bd6
commit
49f754f423
|
@ -314,7 +314,10 @@ public:
|
|||
virtual ~ExternalSLocEntrySource();
|
||||
|
||||
/// \brief Read the source location entry with index ID.
|
||||
virtual void ReadSLocEntry(unsigned ID) = 0;
|
||||
///
|
||||
/// \returns true if an error occurred that prevented the source-location
|
||||
/// entry from being loaded.
|
||||
virtual bool ReadSLocEntry(unsigned ID) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -377,7 +380,7 @@ public:
|
|||
/// Spelling locations represent where the bytes corresponding to a token came
|
||||
/// from and instantiation locations represent where the location is in the
|
||||
/// user's view. In the case of a macro expansion, for example, the spelling
|
||||
/// location indicates where the expanded token came from and the instantiation
|
||||
/// location indicates where the expanded token came from and the instantiation
|
||||
/// location specifies where it was expanded.
|
||||
class SourceManager : public llvm::RefCountedBase<SourceManager> {
|
||||
/// \brief Diagnostic object.
|
||||
|
@ -445,6 +448,9 @@ class SourceManager : public llvm::RefCountedBase<SourceManager> {
|
|||
// Cache results for the isBeforeInTranslationUnit method.
|
||||
mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache;
|
||||
|
||||
// Cache for the "fake" buffer used for error-recovery purposes.
|
||||
mutable llvm::MemoryBuffer *FakeBufferForRecovery;
|
||||
|
||||
// SourceManager doesn't support copy construction.
|
||||
explicit SourceManager(const SourceManager&);
|
||||
void operator=(const SourceManager&);
|
||||
|
@ -571,18 +577,42 @@ public:
|
|||
/// buffer and returns a non-empty error string.
|
||||
const llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc,
|
||||
bool *Invalid = 0) const {
|
||||
return getSLocEntry(FID).getFile().getContentCache()
|
||||
->getBuffer(Diag, *this, Loc, Invalid);
|
||||
bool MyInvalid = false;
|
||||
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
|
||||
if (MyInvalid || !Entry.isFile()) {
|
||||
if (Invalid)
|
||||
*Invalid = true;
|
||||
|
||||
return getFakeBufferForRecovery();
|
||||
}
|
||||
|
||||
return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc,
|
||||
Invalid);
|
||||
}
|
||||
|
||||
const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const {
|
||||
return getSLocEntry(FID).getFile().getContentCache()
|
||||
->getBuffer(Diag, *this, SourceLocation(), Invalid);
|
||||
bool MyInvalid = false;
|
||||
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
|
||||
if (MyInvalid || !Entry.isFile()) {
|
||||
if (Invalid)
|
||||
*Invalid = true;
|
||||
|
||||
return getFakeBufferForRecovery();
|
||||
}
|
||||
|
||||
return Entry.getFile().getContentCache()->getBuffer(Diag, *this,
|
||||
SourceLocation(),
|
||||
Invalid);
|
||||
}
|
||||
|
||||
/// getFileEntryForID - Returns the FileEntry record for the provided FileID.
|
||||
const FileEntry *getFileEntryForID(FileID FID) const {
|
||||
return getSLocEntry(FID).getFile().getContentCache()->OrigEntry;
|
||||
bool MyInvalid = false;
|
||||
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
|
||||
if (MyInvalid || !Entry.isFile())
|
||||
return 0;
|
||||
|
||||
return Entry.getFile().getContentCache()->OrigEntry;
|
||||
}
|
||||
|
||||
/// Returns the FileEntry record for the provided SLocEntry.
|
||||
|
@ -622,8 +652,12 @@ public:
|
|||
/// first byte of the specified file.
|
||||
SourceLocation getLocForStartOfFile(FileID FID) const {
|
||||
assert(FID.ID < SLocEntryTable.size() && "FileID out of range");
|
||||
assert(getSLocEntry(FID).isFile() && "FileID is not a file");
|
||||
unsigned FileOffset = getSLocEntry(FID).getOffset();
|
||||
bool Invalid = false;
|
||||
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
|
||||
if (Invalid || !Entry.isFile())
|
||||
return SourceLocation();
|
||||
|
||||
unsigned FileOffset = Entry.getOffset();
|
||||
return SourceLocation::getFileLoc(FileOffset);
|
||||
}
|
||||
|
||||
|
@ -851,17 +885,22 @@ public:
|
|||
// any other external source).
|
||||
unsigned sloc_loaded_entry_size() const { return SLocEntryLoaded.size(); }
|
||||
|
||||
const SrcMgr::SLocEntry &getSLocEntry(unsigned ID) const {
|
||||
const SrcMgr::SLocEntry &getSLocEntry(unsigned ID, bool *Invalid = 0) const {
|
||||
assert(ID < SLocEntryTable.size() && "Invalid id");
|
||||
// If we haven't loaded this source-location entry from the external source
|
||||
// yet, do so now.
|
||||
if (ExternalSLocEntries &&
|
||||
ID < SLocEntryLoaded.size() &&
|
||||
!SLocEntryLoaded[ID])
|
||||
ExternalSLocEntries->ReadSLocEntry(ID);
|
||||
!SLocEntryLoaded[ID] &&
|
||||
ExternalSLocEntries->ReadSLocEntry(ID) &&
|
||||
Invalid)
|
||||
*Invalid = true;
|
||||
|
||||
return SLocEntryTable[ID];
|
||||
}
|
||||
|
||||
const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
|
||||
return getSLocEntry(FID.ID);
|
||||
const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
|
||||
return getSLocEntry(FID.ID, Invalid);
|
||||
}
|
||||
|
||||
unsigned getNextOffset() const { return NextOffset; }
|
||||
|
@ -877,6 +916,8 @@ public:
|
|||
void ClearPreallocatedSLocEntries();
|
||||
|
||||
private:
|
||||
const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
|
||||
|
||||
/// isOffsetInFileID - Return true if the specified FileID contains the
|
||||
/// specified SourceLocation offset. This is a very hot method.
|
||||
inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const {
|
||||
|
|
|
@ -1120,7 +1120,7 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Read the source location entry with index ID.
|
||||
virtual void ReadSLocEntry(unsigned ID);
|
||||
virtual bool ReadSLocEntry(unsigned ID);
|
||||
|
||||
Selector DecodeSelector(unsigned Idx);
|
||||
|
||||
|
|
|
@ -278,7 +278,12 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
|||
int FilenameID) {
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
|
||||
|
||||
const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
|
||||
bool Invalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (!Entry.isFile() || Invalid)
|
||||
return;
|
||||
|
||||
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
|
||||
|
||||
// Remember that this file has #line directives now if it doesn't already.
|
||||
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
|
||||
|
@ -302,7 +307,13 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
|||
}
|
||||
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
|
||||
const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
|
||||
|
||||
bool Invalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (!Entry.isFile() || Invalid)
|
||||
return;
|
||||
|
||||
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
|
||||
|
||||
// Remember that this file has #line directives now if it doesn't already.
|
||||
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
|
||||
|
@ -341,7 +352,7 @@ LineTableInfo &SourceManager::getLineTable() {
|
|||
SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr)
|
||||
: Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
|
||||
ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
|
||||
NumBinaryProbes(0) {
|
||||
NumBinaryProbes(0), FakeBufferForRecovery(0) {
|
||||
clearIDTables();
|
||||
Diag.setSourceManager(this);
|
||||
}
|
||||
|
@ -361,6 +372,8 @@ SourceManager::~SourceManager() {
|
|||
I->second->~ContentCache();
|
||||
ContentCacheAlloc.Deallocate(I->second);
|
||||
}
|
||||
|
||||
delete FakeBufferForRecovery;
|
||||
}
|
||||
|
||||
void SourceManager::clearIDTables() {
|
||||
|
@ -455,6 +468,15 @@ void SourceManager::ClearPreallocatedSLocEntries() {
|
|||
ExternalSLocEntries = 0;
|
||||
}
|
||||
|
||||
/// \brief As part of recovering from missing or changed content, produce a
|
||||
/// fake, non-empty buffer.
|
||||
const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
|
||||
if (!FakeBufferForRecovery)
|
||||
FakeBufferForRecovery
|
||||
= llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
|
||||
|
||||
return FakeBufferForRecovery;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Methods to create new FileID's and instantiations.
|
||||
|
@ -554,8 +576,8 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile,
|
|||
|
||||
llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
|
||||
bool MyInvalid = false;
|
||||
const SLocEntry &SLoc = getSLocEntry(FID.ID);
|
||||
if (!SLoc.isFile()) {
|
||||
const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid);
|
||||
if (!SLoc.isFile() || MyInvalid) {
|
||||
if (Invalid)
|
||||
*Invalid = true;
|
||||
return "<<<<<INVALID SOURCE LOCATION>>>>>";
|
||||
|
@ -583,7 +605,8 @@ llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
|
|||
/// SLocEntryTable which contains the specified location.
|
||||
///
|
||||
FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
|
||||
assert(SLocOffset && "Invalid FileID");
|
||||
if (!SLocOffset)
|
||||
return FileID::get(0);
|
||||
|
||||
// After the first and second level caches, I see two common sorts of
|
||||
// behavior: 1) a lot of searched FileID's are "near" the cached file location
|
||||
|
@ -611,8 +634,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
|
|||
unsigned NumProbes = 0;
|
||||
while (1) {
|
||||
--I;
|
||||
if (ExternalSLocEntries)
|
||||
getSLocEntry(FileID::get(I - SLocEntryTable.begin()));
|
||||
if (ExternalSLocEntries) {
|
||||
bool Invalid = false;
|
||||
getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid);
|
||||
if (Invalid)
|
||||
return FileID::get(0);
|
||||
}
|
||||
|
||||
if (I->getOffset() <= SLocOffset) {
|
||||
#if 0
|
||||
printf("lin %d -> %d [%s] %d %d\n", SLocOffset,
|
||||
|
@ -642,9 +670,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
|
|||
unsigned LessIndex = 0;
|
||||
NumProbes = 0;
|
||||
while (1) {
|
||||
bool Invalid = false;
|
||||
unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
|
||||
unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset();
|
||||
|
||||
unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid)
|
||||
.getOffset();
|
||||
if (Invalid)
|
||||
return FileID::get(0);
|
||||
|
||||
++NumProbes;
|
||||
|
||||
// If the offset of the midpoint is too large, chop the high side of the
|
||||
|
@ -794,9 +826,16 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
|
|||
|
||||
// Note that calling 'getBuffer()' may lazily page in a source file.
|
||||
bool CharDataInvalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid);
|
||||
if (CharDataInvalid || !Entry.isFile()) {
|
||||
if (Invalid)
|
||||
*Invalid = true;
|
||||
|
||||
return "<<<<INVALID BUFFER>>>>";
|
||||
}
|
||||
const llvm::MemoryBuffer *Buffer
|
||||
= getSLocEntry(LocInfo.first).getFile().getContentCache()
|
||||
->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
|
||||
= Entry.getFile().getContentCache()
|
||||
->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
|
||||
if (Invalid)
|
||||
*Invalid = CharDataInvalid;
|
||||
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
|
||||
|
@ -912,10 +951,18 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
|
|||
ContentCache *Content;
|
||||
if (LastLineNoFileIDQuery == FID)
|
||||
Content = LastLineNoContentCache;
|
||||
else
|
||||
Content = const_cast<ContentCache*>(getSLocEntry(FID)
|
||||
.getFile().getContentCache());
|
||||
|
||||
else {
|
||||
bool MyInvalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
|
||||
if (MyInvalid || !Entry.isFile()) {
|
||||
if (Invalid)
|
||||
*Invalid = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Content = const_cast<ContentCache*>(Entry.getFile().getContentCache());
|
||||
}
|
||||
|
||||
// If this is the first use of line information for this buffer, compute the
|
||||
/// SourceLineCache for it on demand.
|
||||
if (Content->SourceLineCache == 0) {
|
||||
|
@ -1042,7 +1089,12 @@ SrcMgr::CharacteristicKind
|
|||
SourceManager::getFileCharacteristic(SourceLocation Loc) const {
|
||||
assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!");
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
|
||||
const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
|
||||
bool Invalid = false;
|
||||
const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (Invalid || !SEntry.isFile())
|
||||
return C_User;
|
||||
|
||||
const SrcMgr::FileInfo &FI = SEntry.getFile();
|
||||
|
||||
// If there are no #line directives in this file, just return the whole-file
|
||||
// state.
|
||||
|
@ -1085,7 +1137,12 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
|
|||
// Presumed locations are always for instantiation points.
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
|
||||
|
||||
const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
|
||||
bool Invalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (Invalid || !Entry.isFile())
|
||||
return PresumedLoc();
|
||||
|
||||
const SrcMgr::FileInfo &FI = Entry.getFile();
|
||||
const SrcMgr::ContentCache *C = FI.getContentCache();
|
||||
|
||||
// To get the source name, first consult the FileEntry (if one exists)
|
||||
|
@ -1096,7 +1153,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
|
|||
Filename = C->OrigEntry->getName();
|
||||
else
|
||||
Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
|
||||
bool Invalid = false;
|
||||
|
||||
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
|
||||
if (Invalid)
|
||||
return PresumedLoc();
|
||||
|
@ -1173,7 +1230,11 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
|
|||
llvm::Optional<ino_t> SourceFileInode;
|
||||
llvm::Optional<llvm::StringRef> SourceFileName;
|
||||
if (!MainFileID.isInvalid()) {
|
||||
const SLocEntry &MainSLoc = getSLocEntry(MainFileID);
|
||||
bool Invalid = false;
|
||||
const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
|
||||
if (Invalid)
|
||||
return SourceLocation();
|
||||
|
||||
if (MainSLoc.isFile()) {
|
||||
const ContentCache *MainContentCache
|
||||
= MainSLoc.getFile().getContentCache();
|
||||
|
@ -1206,7 +1267,11 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
|
|||
// The location we're looking for isn't in the main file; look
|
||||
// through all of the source locations.
|
||||
for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
|
||||
const SLocEntry &SLoc = getSLocEntry(I);
|
||||
bool Invalid = false;
|
||||
const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
|
||||
if (Invalid)
|
||||
return SourceLocation();
|
||||
|
||||
if (SLoc.isFile() &&
|
||||
SLoc.getFile().getContentCache() &&
|
||||
SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
|
||||
|
@ -1224,8 +1289,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
|
|||
(SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
|
||||
(SourceFileInode ||
|
||||
(SourceFileInode = getActualFileInode(SourceFile)))) {
|
||||
bool Invalid = false;
|
||||
for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
|
||||
const SLocEntry &SLoc = getSLocEntry(I);
|
||||
const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
|
||||
if (Invalid)
|
||||
return SourceLocation();
|
||||
|
||||
if (SLoc.isFile()) {
|
||||
const ContentCache *FileContentCache
|
||||
= SLoc.getFile().getContentCache();
|
||||
|
|
|
@ -4383,8 +4383,8 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) {
|
|||
return IdentifiersLoaded[ID];
|
||||
}
|
||||
|
||||
void ASTReader::ReadSLocEntry(unsigned ID) {
|
||||
ReadSLocEntryRecord(ID);
|
||||
bool ASTReader::ReadSLocEntry(unsigned ID) {
|
||||
return ReadSLocEntryRecord(ID) != Success;
|
||||
}
|
||||
|
||||
Selector ASTReader::DecodeSelector(unsigned ID) {
|
||||
|
|
|
@ -2773,8 +2773,9 @@ void clang_getInstantiationLocation(CXSourceLocation location,
|
|||
// Check that the FileID is invalid on the instantiation location.
|
||||
// This can manifest in invalid code.
|
||||
FileID fileID = SM.getFileID(InstLoc);
|
||||
const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID);
|
||||
if (!sloc.isFile()) {
|
||||
bool Invalid = false;
|
||||
const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
|
||||
if (!sloc.isFile() || Invalid) {
|
||||
createNullLocation(file, line, column, offset);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -40,10 +40,10 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
|
|||
i = 0;
|
||||
|
||||
for ( ; i < n ; ++i) {
|
||||
|
||||
const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i);
|
||||
bool Invalid = false;
|
||||
const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i, &Invalid);
|
||||
|
||||
if (!SL.isFile())
|
||||
if (!SL.isFile() || Invalid)
|
||||
continue;
|
||||
|
||||
const SrcMgr::FileInfo &FI = SL.getFile();
|
||||
|
|
Loading…
Reference in New Issue