aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Serialization/ASTBitCodes.h33
-rw-r--r--include/clang/Serialization/ASTReader.h21
-rw-r--r--include/clang/Serialization/ASTWriter.h6
-rw-r--r--include/clang/Serialization/Module.h16
-rw-r--r--lib/Sema/SemaLookup.cpp2
-rw-r--r--lib/Serialization/ASTReader.cpp42
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp250
-rw-r--r--lib/Serialization/ASTWriter.cpp22
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp89
-rw-r--r--lib/Serialization/Module.cpp2
-rw-r--r--test/Modules/Inputs/module.map18
-rw-r--r--test/Modules/Inputs/redecl-merge-bottom.h4
-rw-r--r--test/Modules/Inputs/redecl-merge-left.h7
-rw-r--r--test/Modules/Inputs/redecl-merge-right.h9
-rw-r--r--test/Modules/Inputs/redecl-merge-top.h5
-rw-r--r--test/Modules/redecl-merge.m20
-rw-r--r--test/PCH/chain-cxx.cpp6
17 files changed, 462 insertions, 90 deletions
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 41ef74ee0a..cce6916b4e 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -452,7 +452,11 @@ namespace clang {
/// \brief Record code for an array of all of the (sub)modules that were
/// imported by the AST file.
- IMPORTED_MODULES
+ IMPORTED_MODULES,
+
+ /// \brief Record code for the array describing the first/last local
+ /// redeclarations of each entity.
+ LOCAL_REDECLARATIONS
};
/// \brief Record types used within a source manager block.
@@ -1190,6 +1194,33 @@ namespace clang {
CTOR_INITIALIZER_INDIRECT_MEMBER
};
+ /// \brief Describes the redeclarations of a declaration.
+ struct LocalRedeclarationsInfo {
+ DeclID FirstID; // The ID of the first declaration
+ DeclID FirstLocalID; // The ID of the first local declaration
+ DeclID LastLocalID; // The ID of the last local declaration
+
+ friend bool operator<(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID < Y.FirstID;
+ }
+
+ friend bool operator>(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID > Y.FirstID;
+ }
+
+ friend bool operator<=(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID <= Y.FirstID;
+ }
+
+ friend bool operator>=(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID >= Y.FirstID;
+ }
+ };
+
/// @}
}
} // end namespace clang
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 0947dfc4eb..10ed5dceea 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -674,6 +674,17 @@ private:
/// deeply nested calls when there are many redeclarations.
std::deque<std::pair<Decl *, serialization::DeclID> > PendingPreviousDecls;
+ /// \brief The list of redeclaration chains that still need to be
+ /// reconstructed.
+ ///
+ /// Each element is the global declaration ID of the first declaration in
+ /// the chain. Elements in this vector should be unique; use
+ /// PendingDeclChainsKnown to ensure uniqueness.
+ llvm::SmallVector<serialization::DeclID, 16> PendingDeclChains;
+
+ /// \brief Keeps track of the elements added to PendingDeclChains.
+ llvm::SmallSet<serialization::DeclID, 16> PendingDeclChainsKnown;
+
/// \brief We delay loading the chain of objc categories after recursive
/// loading of declarations is finished.
std::vector<std::pair<ObjCInterfaceDecl *, serialization::DeclID> >
@@ -759,6 +770,7 @@ private:
RecordLocation DeclCursorForID(serialization::DeclID ID,
unsigned &RawLocation);
void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
+ void loadPendingDeclChain(serialization::GlobalDeclID ID);
void loadObjCChainedCategories(serialization::GlobalDeclID ID,
ObjCInterfaceDecl *D);
@@ -1028,6 +1040,15 @@ public:
return cast_or_null<T>(GetLocalDecl(F, LocalID));
}
+ /// \brief Map a global declaration ID into the declaration ID used to
+ /// refer to this declaration within the given module fule.
+ ///
+ /// \returns the global ID of the given declaration as known in the given
+ /// module file.
+ serialization::DeclID
+ mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
+ serialization::DeclID GlobalID);
+
/// \brief Reads a declaration ID from the given position in a record in the
/// given module.
///
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index ab0d1ef3d9..fd581bc452 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -312,7 +312,11 @@ private:
/// serialized again. In this case, it is registered here, so that the reader
/// knows to read the updated version.
SmallVector<ReplacedDeclInfo, 16> ReplacedDecls;
-
+
+ /// \brief The list of local redeclarations of entities that were
+ /// first declared non-locally.
+ SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclarations;
+
/// \brief Statements that we've encountered while serializing a
/// declaration or type.
SmallVector<Stmt *, 16> StmtsToEmit;
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 16d9779e04..cbac5cd148 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -260,6 +260,15 @@ public:
/// \brief Remapping table for declaration IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> DeclRemap;
+ /// \brief Mapping from the module files that this module file depends on
+ /// to the base declaration ID for that module as it is understood within this
+ /// module.
+ ///
+ /// This is effectively a reverse global-to-local mapping for declaration
+ /// IDs, so that we can interpret a true global ID (for this translation unit)
+ /// as a local ID (for this module file).
+ llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs;
+
/// \brief The number of C++ base specifier sets in this AST file.
unsigned LocalNumCXXBaseSpecifiers;
@@ -286,6 +295,13 @@ public:
/// \brief Array of file-level DeclIDs sorted by file.
const serialization::DeclID *FileSortedDecls;
+ /// \brief Array of redeclaration information within this module file,
+ /// sorted by the first declaration ID.
+ const serialization::LocalRedeclarationsInfo *RedeclarationsInfo;
+
+ /// \brief The number of redeclaration info entries in RedeclarationsInfo.
+ unsigned LocalNumRedeclarationsInfos;
+
// === Types ===
/// \brief The number of types in this AST file.
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index a1713ee685..bc1cb3fca6 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -1063,6 +1063,8 @@ static NamedDecl *getPreviousDeclaration(NamedDecl *D) {
return FD->getPreviousDeclaration();
if (RedeclarableTemplateDecl *RTD = dyn_cast<RedeclarableTemplateDecl>(D))
return RTD->getPreviousDeclaration();
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
+ return TD->getPreviousDeclaration();
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
return ID->getPreviousDeclaration();
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 3af04c2bc8..64414c9167 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1846,6 +1846,10 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
F.DeclRemap.insert(std::make_pair(LocalBaseDeclID,
F.BaseDeclID - LocalBaseDeclID));
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
+
DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
}
break;
@@ -2125,6 +2129,9 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
TypeRemap.insert(std::make_pair(TypeIndexOffset,
OM->BaseTypeIndex - TypeIndexOffset));
+
+ // Global -> local mappings.
+ F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
}
break;
}
@@ -2396,7 +2403,17 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
}
}
break;
+ }
+
+ case LOCAL_REDECLARATIONS: {
+ if (F.LocalNumRedeclarationsInfos != 0) {
+ Error("duplicate LOCAL_REDECLARATIONS record in AST file");
+ return Failure;
+ }
+ F.LocalNumRedeclarationsInfos = Record[0];
+ F.RedeclarationsInfo = (const LocalRedeclarationsInfo *)BlobStart;
+ break;
}
}
}
@@ -4568,6 +4585,23 @@ Decl *ASTReader::GetDecl(DeclID ID) {
return DeclsLoaded[Index];
}
+DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
+ DeclID GlobalID) {
+ if (GlobalID < NUM_PREDEF_DECL_IDS)
+ return GlobalID;
+
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ ModuleFile *Owner = I->second;
+
+ llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos
+ = M.GlobalToLocalDeclIDs.find(Owner);
+ if (Pos == M.GlobalToLocalDeclIDs.end())
+ return 0;
+
+ return GlobalID - Owner->BaseDeclID + Pos->second;
+}
+
serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F,
const RecordData &Record,
unsigned &Idx) {
@@ -6027,6 +6061,7 @@ void ASTReader::ClearSwitchCaseIDs() {
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() ||
!PendingPreviousDecls.empty() ||
+ !PendingDeclChains.empty() ||
!PendingChainedObjCCategories.empty()) {
// If any identifiers with corresponding top-level declarations have
@@ -6044,6 +6079,12 @@ void ASTReader::finishPendingActions() {
PendingPreviousDecls.pop_front();
}
+ // Load pending declaration chains.
+ for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
+ loadPendingDeclChain(PendingDeclChains[I]);
+ }
+ PendingDeclChains.clear();
+
for (std::vector<std::pair<ObjCInterfaceDecl *,
serialization::DeclID> >::iterator
I = PendingChainedObjCCategories.begin(),
@@ -6082,6 +6123,7 @@ void ASTReader::FinishedDeserializing() {
}
finishPendingActions();
+ PendingDeclChainsKnown.clear();
assert(PendingForwardRefs.size() == 0 &&
"Some forward refs did not get linked to the definition!");
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 5e5f1cb6fe..69f309aef0 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -114,6 +114,7 @@ namespace clang {
TypeIDForTypeDecl(0) { }
static void attachPreviousDecl(Decl *D, Decl *previous);
+ static void attachLatestDecl(Decl *D, Decl *latest);
void Visit(Decl *D);
@@ -307,11 +308,13 @@ void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
}
void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+ VisitRedeclarable(TD);
VisitTypeDecl(TD);
TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
}
void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
+ VisitRedeclarable(TD);
VisitTypeDecl(TD);
TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
}
@@ -1398,73 +1401,39 @@ ASTDeclReader::VisitDeclContext(DeclContext *DC) {
template <typename T>
void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
- enum RedeclKind { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
+ enum RedeclKind { FirstInFile, PointsToPrevious };
RedeclKind Kind = (RedeclKind)Record[Idx++];
+
+ // Read the first declaration ID, and note that we need to reconstruct
+ // the redeclaration chain once we hit the top level.
+ DeclID FirstDeclID = ReadDeclID(Record, Idx);
+ if (Reader.PendingDeclChainsKnown.insert(FirstDeclID))
+ Reader.PendingDeclChains.push_back(FirstDeclID);
+
+ T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
+
switch (Kind) {
- default:
- llvm_unreachable("Out of sync with ASTDeclWriter::VisitRedeclarable or"
- " messed up reading");
- case NoRedeclaration:
+ case FirstInFile:
+ if (FirstDecl != D)
+ D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl);
break;
+
case PointsToPrevious: {
DeclID PreviousDeclID = ReadDeclID(Record, Idx);
- DeclID FirstDeclID = ReadDeclID(Record, Idx);
+
// We delay loading of the redeclaration chain to avoid deeply nested calls.
// We temporarily set the first (canonical) declaration as the previous one
// which is the one that matters and mark the real previous DeclID to be
// loaded & attached later on.
- T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl);
- if (PreviousDeclID != FirstDeclID)
- Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast<T*>(D),
- PreviousDeclID));
-
- // If the first declaration in the chain is in an inconsistent
- // state where it thinks that it is the only declaration, fix its
- // redeclaration link now to point at this declaration, so that we have a
- // proper redeclaration chain.
- if (FirstDecl->RedeclLink.getPointer() == FirstDecl) {
- FirstDecl->RedeclLink
- = typename Redeclarable<T>::LatestDeclLink(static_cast<T*>(D));
- }
- break;
- }
- case PointsToLatest: {
- T *LatestDecl = ReadDeclAs<T>(Record, Idx);
- D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(LatestDecl);
- // If the latest declaration in the chain is in an inconsistent
- // state where it thinks that it is the only declaration, fix its
- // redeclaration link now to point at this declaration, so that we have a
- // proper redeclaration chain.
- if (LatestDecl->RedeclLink.getPointer() == LatestDecl) {
- LatestDecl->RedeclLink
- = typename Redeclarable<T>::PreviousDeclLink(static_cast<T*>(D));
- }
+ // Make a note that we need to wire up this declaration to its
+ // previous declaration, later.
+ Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast<T*>(D),
+ PreviousDeclID));
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 AST file. However, if this actually needs to point to a
- // redeclaration in another AST file, 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 ?");
- ASTReader::FirstLatestDeclIDMap::iterator I
- = Reader.FirstLatestDeclIDs.find(ThisDeclID);
- if (I != Reader.FirstLatestDeclIDs.end()) {
- Decl *NewLatest = Reader.GetDecl(I->second);
- D->RedeclLink
- = typename Redeclarable<T>::LatestDeclLink(cast_or_null<T>(NewLatest));
- }
}
//===----------------------------------------------------------------------===//
@@ -1564,7 +1533,9 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
FD->RedeclLink.setPointer(cast<FunctionDecl>(previous));
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
VD->RedeclLink.setPointer(cast<VarDecl>(previous));
- } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(previous)) {
+ } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ TD->RedeclLink.setPointer(cast<TypedefNameDecl>(previous));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
ID->RedeclLink.setPointer(cast<ObjCInterfaceDecl>(previous));
} else {
RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
@@ -1572,6 +1543,31 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
}
}
+void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
+ assert(D && Latest);
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ TD->RedeclLink
+ = Redeclarable<TagDecl>::LatestDeclLink(cast<TagDecl>(Latest));
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ FD->RedeclLink
+ = Redeclarable<FunctionDecl>::LatestDeclLink(cast<FunctionDecl>(Latest));
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ VD->RedeclLink
+ = Redeclarable<VarDecl>::LatestDeclLink(cast<VarDecl>(Latest));
+ } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ TD->RedeclLink
+ = Redeclarable<TypedefNameDecl>::LatestDeclLink(
+ cast<TypedefNameDecl>(Latest));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ ID->RedeclLink
+ = Redeclarable<ObjCInterfaceDecl>::LatestDeclLink(
+ cast<ObjCInterfaceDecl>(Latest));
+ } else {
+ RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
+ TD->getCommonPtr()->Latest = cast<RedeclarableTemplateDecl>(Latest);
+ }
+}
+
void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
Decl *previous = GetDecl(ID);
ASTDeclReader::attachPreviousDecl(D, previous);
@@ -1904,6 +1900,152 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
}
namespace {
+ struct CompareLocalRedeclarationsInfoToID {
+ bool operator()(const LocalRedeclarationsInfo &X, DeclID Y) {
+ return X.FirstID < Y;
+ }
+
+ bool operator()(DeclID X, const LocalRedeclarationsInfo &Y) {
+ return X < Y.FirstID;
+ }
+
+ bool operator()(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID < Y.FirstID;
+ }
+ bool operator()(DeclID X, DeclID Y) {
+ return X < Y;
+ }
+ };
+
+ class RedeclChainVisitor {
+ ASTReader &Reader;
+ DeclID GlobalFirstID;
+ llvm::SmallVector<std::pair<Decl *, Decl *>, 4> Chains;
+
+ public:
+ RedeclChainVisitor(ASTReader &Reader, DeclID GlobalFirstID)
+ : Reader(Reader), GlobalFirstID(GlobalFirstID) { }
+
+ static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
+ if (Preorder)
+ return false;
+
+ return static_cast<RedeclChainVisitor *>(UserData)->visit(M);
+ }
+
+ bool visit(ModuleFile &M) {
+ // Map global ID of the first declaration down to the local ID
+ // used in this module file.
+ DeclID FirstID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalFirstID);
+ if (!FirstID)
+ return false;
+
+ // Perform a binary search to find the local redeclarations for this
+ // declaration (if any).
+ const LocalRedeclarationsInfo *Result
+ = std::lower_bound(M.RedeclarationsInfo,
+ M.RedeclarationsInfo + M.LocalNumRedeclarationsInfos,
+ FirstID, CompareLocalRedeclarationsInfoToID());
+ if (Result == M.RedeclarationsInfo + M.LocalNumRedeclarationsInfos ||
+ Result->FirstID != FirstID)
+ return false;
+
+ // Dig out the starting/ending declarations.
+ Decl *FirstLocalDecl = Reader.GetLocalDecl(M, Result->FirstLocalID);
+ Decl *LastLocalDecl = Reader.GetLocalDecl(M, Result->LastLocalID);
+ if (!FirstLocalDecl || !LastLocalDecl)
+ return false;
+
+ // Append this redeclaration chain to the list.
+ Chains.push_back(std::make_pair(FirstLocalDecl, LastLocalDecl));
+ return false;
+ }
+
+ ArrayRef<std::pair<Decl *, Decl *> > getChains() const {
+ return Chains;
+ }
+
+ void addParsed(Decl *FirstParsedDecl, Decl *LastParsedDecl) {
+ Chains.push_back(std::make_pair(FirstParsedDecl, LastParsedDecl));
+ }
+ };
+}
+
+/// \brief Retrieve the previous declaration to D.
+static Decl *getPreviousDecl(Decl *D) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->getPreviousDeclaration();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getPreviousDeclaration();
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->getPreviousDeclaration();
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
+ return TD->getPreviousDeclaration();
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return ID->getPreviousDeclaration();
+
+ return cast<RedeclarableTemplateDecl>(D)->getPreviousDeclaration();
+}
+
+/// \brief Retrieve the most recent declaration of D.
+static Decl *getMostRecentDecl(Decl *D) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->getMostRecentDeclaration();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getMostRecentDeclaration();
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->getMostRecentDeclaration();
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
+ return TD->getMostRecentDeclaration();
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return ID->getMostRecentDeclaration();
+
+ return cast<RedeclarableTemplateDecl>(D)->getMostRecentDeclaration();
+}
+
+void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
+ // Build up the list of redeclaration chains.
+ RedeclChainVisitor Visitor(*this, ID);
+ ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visit, &Visitor);
+
+ // Retrieve the chains.
+ ArrayRef<std::pair<Decl *, Decl *> > Chains = Visitor.getChains();
+ if (Chains.empty())
+ return;
+
+ // FIXME: Splice local (not from AST file) declarations into the list,
+ // rather than always re-ordering them.
+ Decl *CanonDecl = GetDecl(ID);
+
+ // Capture all of the parsed declarations and put them at the end.
+ Decl *MostRecent = getMostRecentDecl(CanonDecl);
+ Decl *FirstParsed = MostRecent;
+ if (CanonDecl != MostRecent && !MostRecent->isFromASTFile()) {
+ Decl *Current = MostRecent;
+ while (Decl *Prev = getPreviousDecl(Current)) {
+ if (Prev->isFromASTFile()) {
+ Current = Prev;
+ continue;
+ }
+
+ // Chain all of the parsed declarations together.
+ ASTDeclReader::attachPreviousDecl(FirstParsed, Prev);
+ FirstParsed = Prev;
+ Current = Prev;
+ }
+
+ Visitor.addParsed(FirstParsed, MostRecent);
+ }
+
+ // Hook up the separate chains.
+ Chains = Visitor.getChains();
+ for (unsigned I = 1, N = Chains.size(); I != N; ++I)
+ ASTDeclReader::attachPreviousDecl(Chains[I].first, Chains[I-1].second);
+ ASTDeclReader::attachLatestDecl(CanonDecl, Chains.back().second);
+}
+
+namespace {
/// \brief Given an ObjC interface, goes through the modules and links to the
/// interface all the categories for it.
class ObjCChainedCategoriesVisitor {
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b3f76f7494..bb2b1cb5b0 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -798,7 +798,8 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(KNOWN_NAMESPACES);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
-
+ RECORD(LOCAL_REDECLARATIONS);
+
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
@@ -3411,6 +3412,25 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
WriteDeclReplacementsBlock();
WriteChainedObjCCategories();
+ if (!LocalRedeclarations.empty()) {
+ // Sort the local redeclarations info by the first declaration ID,
+ // since the reader will be perforing binary searches on this information.
+ llvm::array_pod_sort(LocalRedeclarations.begin(),LocalRedeclarations.end());
+
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
+
+ Record.clear();
+ Record.push_back(LOCAL_REDECLARATIONS);
+ Record.push_back(LocalRedeclarations.size());
+ Stream.EmitRecordWithBlob(AbbrevID, Record,
+ reinterpret_cast<char*>(LocalRedeclarations.data()),
+ LocalRedeclarations.size() * sizeof(LocalRedeclarationsInfo));
+ }
+
// Some simple statistics
Record.clear();
Record.push_back(NumStatements);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 9b74aaeae4..6c6428d55a 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -125,6 +125,30 @@ namespace clang {
};
}
+static bool isFirstDeclInFile(Decl *D) {
+ // FIXME: There must be a better way to abstract Redeclarable<T> into a
+ // more-general "redeclarable type".
+ if (TagDecl *Tag = dyn_cast<TagDecl>(D))
+ return !Tag->getPreviousDeclaration() ||
+ Tag->getPreviousDeclaration()->isFromASTFile();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return !FD->getPreviousDeclaration() ||
+ FD->getPreviousDeclaration()->isFromASTFile();
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ return !VD->getPreviousDeclaration() ||
+ VD->getPreviousDeclaration()->isFromASTFile();
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
+ return !TD->getPreviousDeclaration() ||
+ TD->getPreviousDeclaration()->isFromASTFile();
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return !ID->getPreviousDeclaration() ||
+ ID->getPreviousDeclaration()->isFromASTFile();
+
+ RedeclarableTemplateDecl *RTD = cast<RedeclarableTemplateDecl>(D);
+ return !RTD->getPreviousDeclaration() ||
+ RTD->getPreviousDeclaration()->isFromASTFile();
+}
+
void ASTDeclWriter::Visit(Decl *D) {
DeclVisitor<ASTDeclWriter>::Visit(D);
@@ -177,13 +201,14 @@ void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
}
void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+ VisitRedeclarable(D);
VisitTypeDecl(D);
Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- D->RedeclLink.getNext() == D &&
+ isFirstDeclInFile(D) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -196,6 +221,7 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
}
void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ VisitRedeclarable(D);
VisitTypeDecl(D);
Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
Code = serialization::DECL_TYPEALIAS;
@@ -234,7 +260,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ isFirstDeclInFile(D) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -258,7 +284,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ isFirstDeclInFile(D) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -701,7 +727,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ isFirstDeclInFile(D) &&
!D->hasCXXDirectInitializer() &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
@@ -1267,30 +1293,24 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
- enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
- if (D->RedeclLink.getNext() == D) {
- Record.push_back(NoRedeclaration);
- } else {
- if (D->RedeclLink.NextIsPrevious()) {
- Record.push_back(PointsToPrevious);
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
- Writer.AddDeclRef(D->getFirstDeclaration(), Record);
- } else {
- Record.push_back(PointsToLatest);
- Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
- }
- }
-
+ enum { FirstInFile, PointsToPrevious };
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 AST reading.
- if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl &&
- First->isFromASTFile() && !ThisDecl->isFromASTFile()) {
- assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end()
- && "The latest is already set");
- Writer.FirstLatestDecls[First] = ThisDecl;
+ if (!D->getPreviousDeclaration() ||
+ D->getPreviousDeclaration()->isFromASTFile()) {
+ Record.push_back(FirstInFile);
+ Writer.AddDeclRef(First, Record);
+
+ // Capture the set of redeclarations in this file.
+ LocalRedeclarationsInfo LocalInfo = {
+ Writer.GetDeclRef(First),
+ Writer.GetDeclRef(static_cast<T*>(D)),
+ Writer.GetDeclRef(D->getMostRecentDeclaration())
+ };
+ Writer.LocalRedeclarations.push_back(LocalInfo);
+ } else {
+ Record.push_back(PointsToPrevious);
+ Writer.AddDeclRef(First, Record);
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
}
}
@@ -1374,7 +1394,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
// Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(0)); // First in file
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1421,7 +1442,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
// Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(0)); // First in file
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1462,7 +1484,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
// Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(0)); // First in file
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1511,6 +1534,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Abbreviation for DECL_TYPEDEF
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // First in file
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1538,7 +1564,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR));
// Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(0)); // First in file
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclCon