diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 498d5fffeb2d..0c14df070e08 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -107,6 +107,7 @@ class PCHReader : public ExternalASTSource { PCHReadResult ReadPCHBlock(); bool ReadSourceManagerBlock(); + bool ReadPreprocessorBlock(); bool ParseLanguageOptions(const llvm::SmallVectorImpl &Record); QualType ReadTypeRecord(uint64_t Offset); diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 9eb881ce0f44..d5923086c7a0 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Type.h" +#include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" @@ -193,6 +194,115 @@ bool PCHReader::ReadSourceManagerBlock() { } } +bool PCHReader::ReadPreprocessorBlock() { + if (Stream.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) + return Error("Malformed preprocessor block record"); + + std::string CurName; // FIXME: HACK. + RecordData Record; + llvm::SmallVector MacroArgs; + MacroInfo *LastMacro = 0; + + while (true) { + unsigned Code = Stream.ReadCode(); + switch (Code) { + case llvm::bitc::END_BLOCK: + if (Stream.ReadBlockEnd()) + return Error("Error at end of preprocessor block"); + return false; + + case llvm::bitc::ENTER_SUBBLOCK: + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block record"); + continue; + + case llvm::bitc::DEFINE_ABBREV: + Stream.ReadAbbrevRecord(); + continue; + default: break; + } + + // Read a record. + Record.clear(); + pch::PreprocessorRecordTypes RecType = + (pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record); + switch (RecType) { + default: // Default behavior: ignore unknown records. + break; + + case pch::PP_MACRO_NAME: + // Set CurName. FIXME: This is a hack and should be removed when we have + // identifier id's. + CurName.clear(); + for (unsigned i = 0, e = Record.size(); i != e; ++i) + CurName += (char)Record[i]; + break; + + case pch::PP_MACRO_OBJECT_LIKE: + case pch::PP_MACRO_FUNCTION_LIKE: { + unsigned IdentInfo = Record[0]; + IdentInfo = IdentInfo; // FIXME: Decode into identifier info*. + assert(!CurName.empty()); + IdentifierInfo *II = PP.getIdentifierInfo(CurName.c_str()); + + SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]); + bool isUsed = Record[2]; + + MacroInfo *MI = PP.AllocateMacroInfo(Loc); + MI->setIsUsed(isUsed); + + if (RecType == pch::PP_MACRO_FUNCTION_LIKE) { + // Decode function-like macro info. + bool isC99VarArgs = Record[3]; + bool isGNUVarArgs = Record[4]; + MacroArgs.clear(); + unsigned NumArgs = Record[5]; + for (unsigned i = 0; i != NumArgs; ++i) + ; // FIXME: Decode macro arg names: MacroArgs.push_back(Record[6+i]); + + // Install function-like macro info. + MI->setIsFunctionLike(); + if (isC99VarArgs) MI->setIsC99Varargs(); + if (isGNUVarArgs) MI->setIsGNUVarargs(); + MI->setArgumentList(&MacroArgs[0], MacroArgs.size(), + PP.getPreprocessorAllocator()); + } + + // Finally, install the macro. + II = II; +#if 0 + // FIXME: Do this when predefines buffer is worked out. + PP.setMacroInfo(II, MI); +#endif + + // Remember that we saw this macro last so that we add the tokens that + // form its body to it. + LastMacro = MI; + break; + } + + case pch::PP_TOKEN: { + // If we see a TOKEN before a PP_MACRO_*, then the file is eroneous, just + // pretend we didn't see this. + if (LastMacro == 0) break; + + Token Tok; + Tok.startToken(); + Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0])); + Tok.setLength(Record[1]); + unsigned IdentInfo = Record[2]; + IdentInfo = IdentInfo; // FIXME: Handle this right. + Tok.setKind((tok::TokenKind)Record[3]); + Tok.setFlag((Token::TokenFlags)Record[4]); + LastMacro->AddTokenToBody(Tok); + break; + } + } + } +} + PCHReader::PCHReadResult PCHReader::ReadPCHBlock() { if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { Error("Malformed block record"); @@ -228,6 +338,13 @@ PCHReader::PCHReadResult PCHReader::ReadPCHBlock() { return Failure; } break; + + case pch::PREPROCESSOR_BLOCK_ID: + if (ReadPreprocessorBlock()) { + Error("Malformed preprocessor block"); + return Failure; + } + break; } continue; } diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index a31c0c79855a..09080d640b5e 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -573,6 +573,8 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { // macros. for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { + // FIXME: This emits macros in hash table order, we should do it in a stable + // order so that output is reproducible. MacroInfo *MI = I->second; // Don't emit builtin macros like __LINE__ to the PCH file unless they have