diff options
Diffstat (limited to 'lib/Frontend/PCHReader.cpp')
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index d366cddf17..01a79b44d9 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -15,6 +15,9 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Type.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" @@ -111,6 +114,84 @@ static bool Error(const char *Str) { return true; } +/// \brief Read the source manager block +bool PCHReader::ReadSourceManagerBlock() { + using namespace SrcMgr; + if (Stream.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) + return Error("Malformed source manager block record"); + + SourceManager &SourceMgr = Context.getSourceManager(); + RecordData Record; + while (true) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Error at end of Source Manager block"); + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block record"); + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + const char *BlobStart; + unsigned BlobLen; + Record.clear(); + switch (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case pch::SM_SLOC_FILE_ENTRY: { + // FIXME: We would really like to delay the creation of this + // FileEntry until it is actually required, e.g., when producing + // a diagnostic with a source location in this file. + const FileEntry *File + = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen); + // FIXME: Error recovery if file cannot be found. + SourceMgr.createFileID(File, + SourceLocation::getFromRawEncoding(Record[1]), + (CharacteristicKind)Record[2]); + break; + } + + case pch::SM_SLOC_BUFFER_ENTRY: { + const char *Name = BlobStart; + unsigned Code = Stream.ReadCode(); + Record.clear(); + unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen); + assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file"); + SourceMgr.createFileIDForMemBuffer( + llvm::MemoryBuffer::getMemBuffer(BlobStart, BlobStart + BlobLen - 1, + Name)); + break; + } + + case pch::SM_SLOC_INSTANTIATION_ENTRY: { + SourceLocation SpellingLoc + = SourceLocation::getFromRawEncoding(Record[1]); + SourceMgr.createInstantiationLoc( + SpellingLoc, + SourceLocation::getFromRawEncoding(Record[2]), + SourceLocation::getFromRawEncoding(Record[3]), + Lexer::MeasureTokenLength(SpellingLoc, + SourceMgr)); + break; + } + + } + } +} + /// \brief Read the type-offsets block. bool PCHReader::ReadTypeOffsets() { if (Stream.EnterSubBlock(pch::TYPE_OFFSETS_BLOCK_ID)) @@ -217,6 +298,10 @@ bool PCHReader::ReadPCHBlock() { return Error("Malformed block record"); break; + case pch::SOURCE_MANAGER_BLOCK_ID: + if (ReadSourceManagerBlock()) + return Error("Malformed source manager block"); + break; case pch::TYPE_OFFSETS_BLOCK_ID: if (ReadTypeOffsets()) |