diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-04-20 00:21:03 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-04-20 00:21:03 +0000 |
commit | e23ac65af568ffe611b0990818ac3a57c856a4d8 (patch) | |
tree | 62a21e253b6509fc1f31edeef9b77c799f04afc8 /include/clang/Basic/SourceManager.h | |
parent | a4ff648d4a75c752cbdf884c81f4926670f8e6c7 (diff) |
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>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129839 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang/Basic/SourceManager.h')
-rw-r--r-- | include/clang/Basic/SourceManager.h | 69 |
1 files changed, 55 insertions, 14 deletions
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 8fc0747586..653142dbee 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -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 { |