aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Frontend/PCHReader.cpp16
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp91
-rw-r--r--lib/Frontend/PCHWriter.cpp13
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp42
4 files changed, 144 insertions, 18 deletions
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index b415f8dea5..35909a0555 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1557,6 +1557,18 @@ PCHReader::ReadPCHBlock(PerFileData &F) {
break;
}
+ case pch::REDECLS_UPDATE_LATEST: {
+ assert(Record.size() % 2 == 0 && "Expected pairs of DeclIDs");
+ for (unsigned i = 0, e = Record.size(); i < e; i += 2) {
+ pch::DeclID First = Record[i], Latest = Record[i+1];
+ assert((FirstLatestDeclIDs.find(First) == FirstLatestDeclIDs.end() ||
+ Latest > FirstLatestDeclIDs[First]) &&
+ "The new latest is supposed to come after the previous latest");
+ FirstLatestDeclIDs[First] = Latest;
+ }
+ break;
+ }
+
case pch::LANGUAGE_OPTIONS:
if (ParseLanguageOptions(Record) && !DisableValidation)
return IgnorePCH;
@@ -2868,7 +2880,7 @@ Decl *PCHReader::GetExternalDecl(uint32_t ID) {
TranslationUnitDecl *PCHReader::GetTranslationUnitDecl() {
if (!DeclsLoaded[0]) {
- ReadDeclRecord(0);
+ ReadDeclRecord(0, 0);
if (DeserializationListener)
DeserializationListener->DeclRead(1, DeclsLoaded[0]);
}
@@ -2887,7 +2899,7 @@ Decl *PCHReader::GetDecl(pch::DeclID ID) {
unsigned Index = ID - 1;
if (!DeclsLoaded[Index]) {
- ReadDeclRecord(Index);
+ ReadDeclRecord(Index, ID);
if (DeserializationListener)
DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index e9428cc0b4..21beb42e93 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -31,6 +31,7 @@ namespace clang {
class PCHDeclReader : public DeclVisitor<PCHDeclReader, void> {
PCHReader &Reader;
llvm::BitstreamCursor &Cursor;
+ const pch::DeclID ThisDeclID;
const PCHReader::RecordData &Record;
unsigned &Idx;
pch::TypeID TypeIDForTypeDecl;
@@ -39,9 +40,10 @@ namespace clang {
public:
PCHDeclReader(PCHReader &Reader, llvm::BitstreamCursor &Cursor,
- const PCHReader::RecordData &Record, unsigned &Idx)
- : Reader(Reader), Cursor(Cursor), Record(Record), Idx(Idx),
- TypeIDForTypeDecl(0) { }
+ pch::DeclID thisDeclID, const PCHReader::RecordData &Record,
+ unsigned &Idx)
+ : Reader(Reader), Cursor(Cursor), ThisDeclID(thisDeclID), Record(Record),
+ Idx(Idx), TypeIDForTypeDecl(0) { }
void Visit(Decl *D);
@@ -93,6 +95,7 @@ namespace clang {
void VisitBlockDecl(BlockDecl *BD);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+ template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
@@ -178,8 +181,7 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
VisitTypeDecl(TD);
TD->IdentifierNamespace = Record[Idx++];
- TD->setPreviousDeclaration(
- cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++])));
+ VisitRedeclarable(TD);
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
TD->setDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
@@ -305,10 +307,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// FunctionDecl's body is handled last at PCHReaderDecl::Visit,
// after everything else is read.
- // Avoid side effects and invariant checking of FunctionDecl's
- // setPreviousDeclaration.
- FD->redeclarable_base::setPreviousDeclaration(
- cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ VisitRedeclarable(FD);
FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]);
FD->setInlineSpecified(Record[Idx++]);
@@ -550,8 +549,7 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
VD->setDeclaredInCondition(Record[Idx++]);
VD->setExceptionVariable(Record[Idx++]);
VD->setNRVOVariable(Record[Idx++]);
- VD->setPreviousDeclaration(
- cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ VisitRedeclarable(VD);
if (Record[Idx++])
VD->setInit(Reader.ReadExpr(Cursor));
@@ -918,6 +916,25 @@ void PCHDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
RedeclarableTemplateDecl *LatestDecl =
cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+
+ // This decl is a first one and the latest declaration that it points to is
+ // in the same PCH. However, if this actually needs to point to a
+ // redeclaration in another chained PCH, we need to update it by checking
+ // the FirstLatestDeclIDs map which tracks this kind of decls.
+ assert(Reader.GetDecl(ThisDeclID) == D && "Invalid ThisDeclID ?");
+ PCHReader::FirstLatestDeclIDMap::iterator I
+ = Reader.FirstLatestDeclIDs.find(ThisDeclID);
+ if (I != Reader.FirstLatestDeclIDs.end()) {
+ Decl *NewLatest = Reader.GetDecl(I->second);
+ assert((LatestDecl->getLocation().isInvalid() ||
+ NewLatest->getLocation().isInvalid() ||
+ Reader.SourceMgr.isBeforeInTranslationUnit(
+ LatestDecl->getLocation(),
+ NewLatest->getLocation())) &&
+ "The new latest is supposed to come after the previous latest");
+ LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest);
+ }
+
assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch");
D->getCommonPtr()->Latest = LatestDecl;
}
@@ -1072,6 +1089,54 @@ PCHDeclReader::VisitDeclContext(DeclContext *DC) {
return std::make_pair(LexicalOffset, VisibleOffset);
}
+template <typename T>
+void PCHDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
+ enum RedeclKind { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
+ RedeclKind Kind = (RedeclKind)Record[Idx++];
+ switch (Kind) {
+ default:
+ assert(0 && "Out of sync with PCHDeclWriter::VisitRedeclarable or messed up"
+ " reading");
+ case NoRedeclaration:
+ break;
+ case PointsToPrevious:
+ D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(
+ cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
+ break;
+ case PointsToLatest:
+ D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(
+ cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
+ break;
+ }
+
+ assert(!(Kind == PointsToPrevious &&
+ Reader.FirstLatestDeclIDs.find(ThisDeclID) !=
+ Reader.FirstLatestDeclIDs.end()) &&
+ "This decl is not first, it should not be in the map");
+ if (Kind == PointsToPrevious)
+ return;
+
+ // This decl is a first one and the latest declaration that it points to is in
+ // the same PCH. However, if this actually needs to point to a redeclaration
+ // in another chained PCH, we need to update it by checking the
+ // FirstLatestDeclIDs map which tracks this kind of decls.
+ assert(Reader.GetDecl(ThisDeclID) == static_cast<T*>(D) &&
+ "Invalid ThisDeclID ?");
+ PCHReader::FirstLatestDeclIDMap::iterator I
+ = Reader.FirstLatestDeclIDs.find(ThisDeclID);
+ if (I != Reader.FirstLatestDeclIDs.end()) {
+ Decl *NewLatest = Reader.GetDecl(I->second);
+ assert((D->getMostRecentDeclaration()->getLocation().isInvalid() ||
+ NewLatest->getLocation().isInvalid() ||
+ Reader.SourceMgr.isBeforeInTranslationUnit(
+ D->getMostRecentDeclaration()->getLocation(),
+ NewLatest->getLocation())) &&
+ "The new latest is supposed to come after the previous latest");
+ D->RedeclLink
+ = typename Redeclarable<T>::LatestDeclLink(cast_or_null<T>(NewLatest));
+ }
+}
+
//===----------------------------------------------------------------------===//
// Attribute Reading
//===----------------------------------------------------------------------===//
@@ -1304,7 +1369,7 @@ PCHReader::RecordLocation PCHReader::DeclCursorForIndex(unsigned Index) {
}
/// \brief Read the declaration at the given offset from the PCH file.
-Decl *PCHReader::ReadDeclRecord(unsigned Index) {
+Decl *PCHReader::ReadDeclRecord(unsigned Index, pch::DeclID ID) {
RecordLocation Loc = DeclCursorForIndex(Index);
llvm::BitstreamCursor &DeclsCursor = *Loc.first;
// Keep track of where we are in the stream, then jump back there
@@ -1320,7 +1385,7 @@ Decl *PCHReader::ReadDeclRecord(unsigned Index) {
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned Idx = 0;
- PCHDeclReader Reader(*this, DeclsCursor, Record, Idx);
+ PCHDeclReader Reader(*this, DeclsCursor, ID, Record, Idx);
Decl *D = 0;
switch ((pch::DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 75592a41c8..776a40940d 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -2410,6 +2410,19 @@ void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
WriteIdentifierTable(PP);
WriteTypeDeclOffsets();
+ /// Build a record containing first declarations from a chained PCH and the
+ /// most recent declarations in this PCH that they point to.
+ RecordData FirstLatestDeclIDs;
+ for (FirstLatestDeclMap::iterator
+ I = FirstLatestDecls.begin(), E = FirstLatestDecls.end(); I != E; ++I) {
+ assert(I->first->getPCHLevel() > I->second->getPCHLevel() &&
+ "Expected first & second to be in different PCHs");
+ AddDeclRef(I->first, FirstLatestDeclIDs);
+ AddDeclRef(I->second, FirstLatestDeclIDs);
+ }
+ if (!FirstLatestDeclIDs.empty())
+ Stream.EmitRecord(pch::REDECLS_UPDATE_LATEST, FirstLatestDeclIDs);
+
// Write the record containing external, unnamed definitions.
if (!ExternalDefinitions.empty())
Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions);
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 28a82cd23f..9e9835adb4 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -92,6 +92,7 @@ namespace clang {
void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
uint64_t VisibleOffset);
+ template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
// FIXME: Put in the same order is DeclNodes.td?
@@ -163,7 +164,7 @@ void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
VisitTypeDecl(D);
Record.push_back(D->getIdentifierNamespace());
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ VisitRedeclarable(D);
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
Record.push_back(D->isDefinition());
Record.push_back(D->isEmbeddedInDeclarator());
@@ -279,7 +280,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// FunctionDecl's body is handled last at PCHWriterDecl::Visit,
// after everything else is written.
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ VisitRedeclarable(D);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->isInlineSpecified());
@@ -500,7 +501,7 @@ void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isDeclaredInCondition());
Record.push_back(D->isExceptionVariable());
Record.push_back(D->isNRVOVariable());
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ VisitRedeclarable(D);
Record.push_back(D->getInit() ? 1 : 0);
if (D->getInit())
Writer.AddStmt(D->getInit());
@@ -854,6 +855,18 @@ void PCHDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
Record.push_back(D->isMemberSpecialization());
Writer.AddDeclRef(D->getCommonPtr()->Latest, Record);
+ } else {
+ RedeclarableTemplateDecl *First = D->getFirstDeclaration();
+ assert(First != D);
+ // If this is a most recent redeclaration that is pointed to by a first decl
+ // in a chained PCH, keep track of the association with the map so we can
+ // update the first decl during PCH reading.
+ if (First->getMostRecentDeclaration() == D &&
+ First->getPCHLevel() > D->getPCHLevel()) {
+ assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end()
+ && "The latest is already set");
+ Writer.FirstLatestDecls[First] = D;
+ }
}
}
@@ -1016,6 +1029,29 @@ void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
Record.push_back(VisibleOffset);
}
+template <typename T>
+void PCHDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
+ enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
+ if (D->RedeclLink.getNext() == D) {
+ Record.push_back(NoRedeclaration);
+ } else {
+ Record.push_back(D->RedeclLink.NextIsPrevious() ? PointsToPrevious
+ : PointsToLatest);
+ Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
+ }
+
+ T *First = D->getFirstDeclaration();
+ T *ThisDecl = static_cast<T*>(D);
+ // If this is a most recent redeclaration that is pointed to by a first decl
+ // in a chained PCH, keep track of the association with the map so we can
+ // update the first decl during PCH reading.
+ if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl &&
+ First->getPCHLevel() > ThisDecl->getPCHLevel()) {
+ assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end()
+ && "The latest is already set");
+ Writer.FirstLatestDecls[First] = ThisDecl;
+ }
+}
//===----------------------------------------------------------------------===//
// PCHWriter Implementation