forked from OSchip/llvm-project
Make PCHReader cope with PCH files containing more than one predefines buffer.
llvm-svn: 108340
This commit is contained in:
parent
a90af1ba38
commit
75fbb3b5e5
|
@ -65,6 +65,15 @@ class SwitchCase;
|
|||
class PCHReader;
|
||||
struct HeaderFileInfo;
|
||||
|
||||
struct PCHPredefinesBlock {
|
||||
/// \brief The file ID for this predefines buffer in a PCH file.
|
||||
FileID BufferID;
|
||||
|
||||
/// \brief This predefines buffer in a PCH file.
|
||||
llvm::StringRef Data;
|
||||
};
|
||||
typedef llvm::SmallVector<PCHPredefinesBlock, 2> PCHPredefinesBlocks;
|
||||
|
||||
/// \brief Abstract interface for callback invocations by the PCHReader.
|
||||
///
|
||||
/// While reading a PCH file, the PCHReader will call the methods of the
|
||||
|
@ -103,8 +112,7 @@ public:
|
|||
/// here.
|
||||
///
|
||||
/// \returns true to indicate the predefines are invalid or false otherwise.
|
||||
virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
FileID PCHBufferID,
|
||||
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
||||
llvm::StringRef OriginalFileName,
|
||||
std::string &SuggestedPredefines) {
|
||||
return false;
|
||||
|
@ -131,8 +139,7 @@ public:
|
|||
|
||||
virtual bool ReadLanguageOptions(const LangOptions &LangOpts);
|
||||
virtual bool ReadTargetTriple(llvm::StringRef Triple);
|
||||
virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
FileID PCHBufferID,
|
||||
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
||||
llvm::StringRef OriginalFileName,
|
||||
std::string &SuggestedPredefines);
|
||||
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
|
||||
|
@ -483,15 +490,9 @@ private:
|
|||
~ReadingKindTracker() { Reader.ReadingKind = PrevKind; }
|
||||
};
|
||||
|
||||
/// \brief The file ID for the predefines buffer in the PCH file.
|
||||
FileID PCHPredefinesBufferID;
|
||||
|
||||
/// \brief Pointer to the beginning of the predefines buffer in the
|
||||
/// PCH file.
|
||||
const char *PCHPredefines;
|
||||
|
||||
/// \brief Length of the predefines buffer in the PCH file.
|
||||
unsigned PCHPredefinesLen;
|
||||
/// \brief All predefines buffers in all PCH files, to be treated as if
|
||||
/// concatenated.
|
||||
PCHPredefinesBlocks PCHPredefinesBuffers;
|
||||
|
||||
/// \brief Suggested contents of the predefines buffer, after this
|
||||
/// PCH file has been processed.
|
||||
|
@ -509,7 +510,7 @@ private:
|
|||
void MaybeAddSystemRootToFilename(std::string &Filename);
|
||||
|
||||
PCHReadResult ReadPCHBlock();
|
||||
bool CheckPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID);
|
||||
bool CheckPredefinesBuffers();
|
||||
bool ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record);
|
||||
PCHReadResult ReadSourceManagerBlock();
|
||||
PCHReadResult ReadSLocEntryRecord(unsigned ID);
|
||||
|
|
|
@ -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.
|
||||
/// \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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// \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) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t1 %S/pchpch1.h
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t2 %S/pchpch2.h -include-pch %t1
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -fsyntax-only %s -include-pch %t2
|
||||
|
||||
// The purpose of this test is to make sure that a PCH created while including
|
||||
// an existing PCH can be loaded.
|
Loading…
Reference in New Issue