/// \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.
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
/// 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> >
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);
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.
///
/// 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;
/// \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;
/// \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.
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();
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;
TypeRemap.insert(std::make_pair(TypeIndexOffset,
OM->BaseTypeIndex - TypeIndexOffset));
+
+ // Global -> local mappings.
+ F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
}
break;
}
}
}
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;
}
}
}
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) {
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() ||
!PendingPreviousDecls.empty() ||
+ !PendingDeclChains.empty() ||
!PendingChainedObjCCategories.empty()) {
// If any identifiers with corresponding top-level declarations have
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(),
}
finishPendingActions();
+ PendingDeclChainsKnown.clear();
assert(PendingForwardRefs.size() == 0 &&
"Some forward refs did not get linked to the definition!");
TypeIDForTypeDecl(0) { }
static void attachPreviousDecl(Decl *D, Decl *previous);
+ static void attachLatestDecl(Decl *D, Decl *latest);
void Visit(Decl *D);
}
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));
}
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));
- }
}
//===----------------------------------------------------------------------===//
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);
}
}
+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);
}
}
+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.
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);
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);
};
}
+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);
}
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() &&
}
void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ VisitRedeclarable(D);
VisitTypeDecl(D);
Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
Code = serialization::DECL_TYPEALIAS;
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ isFirstDeclInFile(D) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ isFirstDeclInFile(D) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
!D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ isFirstDeclInFile(D) &&
!D->hasCXXDirectInitializer() &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
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);
}
}
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
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
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
// 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
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)); // LexicalDeclContext
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
- FileSortedDecls(0),
+ FileSortedDecls(0), RedeclarationsInfo(0), LocalNumRedeclarationsInfos(0),
LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
{}
explicit module Decl { header "decl.h" }
explicit module Decl2 { header "decl2.h" }
explicit module Def { header "def.h" }
-}
\ No newline at end of file
+}
+
+module redecl_merge_top {
+ header "redecl-merge-top.h"
+}
+module redecl_merge_left {
+ header "redecl-merge-left.h"
+ export *
+}
+module redecl_merge_right {
+ header "redecl-merge-right.h"
+ export *
+}
+module redecl_merge_bottom {
+ header "redecl-merge-bottom.h"
+ export *
+}
--- /dev/null
+__import_module__ redecl_merge_left;
+__import_module__ redecl_merge_right;
+
+@class A;
--- /dev/null
+__import_module__ redecl_merge_top;
+
+@class A;
+
+@class A;
+
+@class A;
--- /dev/null
+__import_module__ redecl_merge_top;
+
+@interface Super
+@end
+
+@interface A : Super
+- (Super*)init;
+@end
+
--- /dev/null
+@class A;
+
+@class A;
+
+@class A;
--- /dev/null
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-cache-path %t -I %S/Inputs %s -verify
+__import_module__ redecl_merge_left;
+__import_module__ redecl_merge_right;
+
+@implementation A
+- (Super*)init { return self; }
+@end
+
+void f(A *a) {
+ [a init];
+}
+
+@class A;
+
+__import_module__ redecl_merge_bottom;
+
+void g(A *a) {
+ [a init];
+}
// Instantiate struct, but not value.
struct instantiate : TS3<int> {};
+// Typedef
+typedef int Integer;
//===----------------------------------------------------------------------===//
#elif not defined(HEADER2)
// Instantiate TS3's member.
static const int ts3m1 = TS3<int>::value;
+// Redefinition of typedef
+typedef int Integer;
+
//===----------------------------------------------------------------------===//
#else
//===----------------------------------------------------------------------===//
TS2int ts2;
B b;
+ Integer i = 17;
}
// Should have remembered that there is a definition.