aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Redeclarable.h3
-rw-r--r--include/clang/Frontend/PCHBitCodes.h6
-rw-r--r--include/clang/Frontend/PCHReader.h7
-rw-r--r--include/clang/Frontend/PCHWriter.h6
-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
-rw-r--r--test/PCH/cxx-templates.cpp11
-rw-r--r--test/PCH/cxx-templates.h8
10 files changed, 181 insertions, 22 deletions
diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h
index 55e1f84779..85c75b771b 100644
--- a/include/clang/AST/Redeclarable.h
+++ b/include/clang/AST/Redeclarable.h
@@ -177,6 +177,9 @@ public:
static_cast<const decl_type*>(this)));
}
redecl_iterator redecls_end() const { return redecl_iterator(); }
+
+ friend class PCHDeclReader;
+ friend class PCHDeclWriter;
};
}
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index 109a78bd88..a07060f800 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -245,8 +245,12 @@ namespace clang {
/// declarations.
TU_UPDATE_LEXICAL = 28,
+ /// \brief Record code for an update to first decls pointing to the
+ /// latest redeclarations.
+ REDECLS_UPDATE_LATEST = 29,
+
/// \brief Record code for declarations that Sema keeps references of.
- SEMA_DECL_REFS = 29
+ SEMA_DECL_REFS = 30
};
/// \brief Record types used within a source manager block.
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index dda15670b5..e19669ec7f 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -319,6 +319,11 @@ private:
/// DeclContext.
DeclContextOffsetsMap DeclContextOffsets;
+ typedef llvm::DenseMap<pch::DeclID, pch::DeclID> FirstLatestDeclIDMap;
+ /// \brief Map of first declarations from a chained PCH that point to the
+ /// most recent declarations in another PCH.
+ FirstLatestDeclIDMap FirstLatestDeclIDs;
+
/// \brief Read the records that describe the contents of declcontexts.
bool ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
@@ -561,7 +566,7 @@ private:
QualType ReadTypeRecord(unsigned Index);
RecordLocation TypeCursorForIndex(unsigned Index);
void LoadedDecl(unsigned Index, Decl *D);
- Decl *ReadDeclRecord(unsigned Index);
+ Decl *ReadDeclRecord(unsigned Index, pch::DeclID ID);
RecordLocation DeclCursorForIndex(unsigned Index);
void PassInterestingDeclsToConsumer();
diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h
index 92c7085bc6..3403c6e2d1 100644
--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -79,6 +79,7 @@ class PCHWriter : public PCHDeserializationListener {
public:
typedef llvm::SmallVector<uint64_t, 64> RecordData;
+ friend class PCHDeclWriter;
private:
/// \brief The bitstream writer used to emit this precompiled header.
llvm::BitstreamWriter &Stream;
@@ -195,6 +196,11 @@ private:
/// \brief Mapping from the macro definition indices in \c MacroDefinitions
/// to the corresponding offsets within the preprocessor block.
std::vector<uint32_t> MacroDefinitionOffsets;
+
+ typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap;
+ /// \brief Map of first declarations from a chained PCH that point to the
+ /// most recent declarations in another PCH.
+ FirstLatestDeclMap FirstLatestDecls;
/// \brief Declarations encountered that might be external
/// definitions.
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
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index f12742755a..8e89b1da46 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -1,9 +1,13 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/cxx-templates.h -verify %s -ast-dump
+// RUN: %clang_cc1 -include %S/cxx-templates.h -verify %s -ast-dump 1>/dev/null
+// RUN: %clang_cc1 -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s
// Test with pch.
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -include-pch %t -verify %s -ast-dump
+// RUN: %clang_cc1 -include-pch %t -verify %s -ast-dump 1>/dev/null
+// RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: define linkonce_odr void @_ZN2S3IiE1mEv
struct A {
typedef int type;
@@ -22,4 +26,7 @@ void test() {
Dep<A>::Ty ty;
Dep<A> a;
a.f();
+
+ S3<int> s3;
+ s3.m();
}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index 92932199fa..91d53d3060 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -116,3 +116,11 @@ struct S2 {
};
extern template class S2<true>;
+
+template <typename T>
+struct S3 {
+ void m();
+};
+
+template <typename T>
+inline void S3<T>::m() { }