diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2010-07-14 17:49:11 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2010-07-14 17:49:11 +0000 |
commit | 7e9ad8b4fd446ca7cc0e630edee56d8fcc4553de (patch) | |
tree | a209fbae481f4159f8463294fe38d17fd0c1eb8f /lib/Frontend/PCHReader.cpp | |
parent | 797efb51ce0825eb4cce2864a5cea2b30e85f06c (diff) |
Make PCHReader cope with PCH files containing more than one predefines buffer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108340 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend/PCHReader.cpp')
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 151 |
1 files changed, 116 insertions, 35 deletions
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index b452a0d301..cb0be410b5 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -140,8 +140,86 @@ bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) { return true; } -bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, - FileID PCHBufferID, +struct EmptyStringRef { + bool operator ()(const llvm::StringRef &r) const { return r.empty(); } +}; +struct EmptyBlock { + bool operator ()(const PCHPredefinesBlock &r) const { return r.Data.empty(); } +}; + +static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L, + PCHPredefinesBlocks R) { + // First, sum up the lengths. + unsigned LL = 0, RL = 0; + for (unsigned I = 0, N = L.size(); I != N; ++I) { + LL += L[I].size(); + } + for (unsigned I = 0, N = R.size(); I != N; ++I) { + RL += R[I].Data.size(); + } + if (LL != RL) + return false; + if (LL == 0 && RL == 0) + return true; + + // Kick out empty parts, they confuse the algorithm below. + L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end()); + R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end()); + + // Do it the hard way. At this point, both vectors must be non-empty. + llvm::StringRef LR = L[0], RR = R[0].Data; + unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size(); + for (;;) { + // Compare the current pieces. + if (LR.size() == RR.size()) { + // If they're the same length, it's pretty easy. + if (LR != RR) + return false; + // Both pieces are done, advance. + ++LI; + ++RI; + // If either string is done, they're both done, since they're the same + // length. + if (LI == LN) { + assert(RI == RN && "Strings not the same length after all?"); + return true; + } + LR = L[LI]; + RR = R[RI].Data; + } else if (LR.size() < RR.size()) { + // Right piece is longer. + if (!RR.startswith(LR)) + return false; + ++LI; + assert(LI != LN && "Strings not the same length after all?"); + RR = RR.substr(LR.size()); + LR = L[LI]; + } else { + // Left piece is longer. + if (!LR.startswith(RR)) + return false; + ++RI; + assert(RI != RN && "Strings not the same length after all?"); + LR = LR.substr(RR.size()); + RR = R[RI].Data; + } + } +} + +static std::pair<FileID, llvm::StringRef::size_type> +FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) { + std::pair<FileID, llvm::StringRef::size_type> Res; + for (unsigned I = 0, N = Buffers.size(); I != N; ++I) { + Res.second = Buffers[I].Data.find(MacroDef); + if (Res.second != llvm::StringRef::npos) { + Res.first = Buffers[I].BufferID; + break; + } + } + return Res; +} + +bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, llvm::StringRef OriginalFileName, std::string &SuggestedPredefines) { // We are in the context of an implicit include, so the predefines buffer will @@ -160,9 +238,15 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, return true; } - // If the predefines is equal to the joined left and right halves, we're done! - if (Left.size() + Right.size() == PCHPredef.size() && - PCHPredef.startswith(Left) && PCHPredef.endswith(Right)) + // If the concatenation of all the PCH buffers is equal to the adjusted + // command line, we're done. + // We build a SmallVector of the command line here, because we'll eventually + // need to support an arbitrary amount of pieces anyway (when we have chained + // PCH reading). + llvm::SmallVector<llvm::StringRef, 2> CommandLine; + CommandLine.push_back(Left); + CommandLine.push_back(Right); + if (EqualConcatenations(CommandLine, Buffers)) return false; SourceManager &SourceMgr = PP.getSourceManager(); @@ -170,7 +254,8 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, // The predefines buffers are different. Determine what the differences are, // and whether they require us to reject the PCH file. llvm::SmallVector<llvm::StringRef, 8> PCHLines; - PCHPredef.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + for (unsigned I = 0, N = Buffers.size(); I != N; ++I) + Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); llvm::SmallVector<llvm::StringRef, 8> CmdLineLines; Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); @@ -235,10 +320,12 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, << MacroName; // Show the definition of this macro within the PCH file. - llvm::StringRef::size_type Offset = PCHPredef.find(Missing); - assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); - SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) - .getFileLocWithOffset(Offset); + std::pair<FileID, llvm::StringRef::size_type> MacroLoc = + FindMacro(Buffers, Missing); + assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = + SourceMgr.getLocForStartOfFile(MacroLoc.first) + .getFileLocWithOffset(MacroLoc.second); Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; ConflictingDefines = true; @@ -256,10 +343,12 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, } // Show the definition of this macro within the PCH file. - llvm::StringRef::size_type Offset = PCHPredef.find(Missing); - assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); - SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) - .getFileLocWithOffset(Offset); + std::pair<FileID, llvm::StringRef::size_type> MacroLoc = + FindMacro(Buffers, Missing); + assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = + SourceMgr.getLocForStartOfFile(MacroLoc.first) + .getFileLocWithOffset(MacroLoc.second); Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); } @@ -609,27 +698,18 @@ void PCHReader::Error(const char *Msg) { Diag(diag::err_fe_pch_malformed) << Msg; } -/// \brief Check the contents of the predefines buffer against the -/// contents of the predefines buffer used to build the PCH file. -/// -/// The contents of the two predefines buffers should be the same. If -/// not, then some command-line option changed the preprocessor state -/// and we must reject the PCH file. -/// -/// \param PCHPredef The start of the predefines buffer in the PCH -/// file. -/// -/// \param PCHPredefLen The length of the predefines buffer in the PCH -/// file. +/// \brief Check the contents of the concatenation of all predefines buffers in +/// the PCH chain against the contents of the predefines buffer of the current +/// compiler invocation. /// -/// \param PCHBufferID The FileID for the PCH predefines buffer. +/// The contents should be the same. If not, then some command-line option +/// changed the preprocessor state and we must probably reject the PCH file. /// /// \returns true if there was a mismatch (in which case the PCH file /// should be ignored), or false otherwise. -bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef, - FileID PCHBufferID) { +bool PCHReader::CheckPredefinesBuffers() { if (Listener) - return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID, + return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers, ActualOriginalFileName, SuggestedPredefines); return false; @@ -958,9 +1038,11 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset); if (strcmp(Name, "<built-in>") == 0) { - PCHPredefinesBufferID = BufferID; - PCHPredefines = BlobStart; - PCHPredefinesLen = BlobLen - 1; + PCHPredefinesBlock Block = { + BufferID, + llvm::StringRef(BlobStart, BlobLen - 1) + }; + PCHPredefinesBuffers.push_back(Block); } break; @@ -1636,8 +1718,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { } // Check the predefines buffer. - if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen), - PCHPredefinesBufferID)) + if (CheckPredefinesBuffers()) return IgnorePCH; if (PP) { |