template<typename T>
void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
-
+
+ template<typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
+ RedeclarableResult &Redecl);
+
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
} else {
DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
DeclContext *LexicalDC = ReadDeclAs<DeclContext>(Record, Idx);
+ DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
// Avoid calling setLexicalDeclContext() directly because it uses
// Decl::getASTContext() internally which is unsafe during derialization.
- D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
+ D->setDeclContextsImpl(MergedSemaDC ? MergedSemaDC : SemaDC, LexicalDC,
+ Reader.getContext());
}
D->setLocation(Reader.ReadSourceLocation(F, RawLocation));
D->setInvalidDecl(Record[Idx++]);
RedeclarableResult Redecl = VisitRecordDeclImpl(D);
ASTContext &C = Reader.getContext();
- if (Record[Idx++]) {
+ bool WasDefinition = Record[Idx++];
+ if (WasDefinition) {
// Determine whether this is a lambda closure type, so that we can
// allocate the appropriate DefinitionData structure.
bool IsLambda = Record[Idx++];
false);
else
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
-
+
+ ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
+
// Propagate the DefinitionData pointer to the canonical declaration, so
// that all other deserialized declarations will see it.
- // FIXME: Complain if there already is a DefinitionData!
- D->getCanonicalDecl()->DefinitionData = D->DefinitionData;
-
- ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
-
- // Note that we have deserialized a definition. Any declarations
- // deserialized before this one will be be given the DefinitionData pointer
- // at the end.
- Reader.PendingDefinitions.insert(D);
+ CXXRecordDecl *Canon = D->getCanonicalDecl();
+ if (Canon == D) {
+ // Nothing to do.
+ } else if (!Canon->DefinitionData) {
+ Canon->DefinitionData = D->DefinitionData;
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData
+ // pointer at the end.
+ Reader.PendingDefinitions.insert(D);
+ } else {
+ // We have already deserialized a definition of this record. This
+ // definition is no longer really a definition. Note that the pre-existing
+ // definition is the *real* definition.
+ // FIXME: Check DefinitionData for consistency with prior definition.
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, D->getCanonicalDecl()->DefinitionData->Definition));
+ D->IsCompleteDefinition = false;
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ }
} else {
// Propagate DefinitionData pointer from the canonical declaration.
- D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
}
enum CXXRecKind {
// Lazily load the key function to avoid deserializing every method so we can
// compute it.
- if (D->IsCompleteDefinition) {
- if (DeclID KeyFn = ReadDeclID(Record, Idx))
+ if (WasDefinition) {
+ DeclID KeyFn = ReadDeclID(Record, Idx);
+ if (KeyFn && D->IsCompleteDefinition)
C.KeyFunctions[D] = KeyFn;
}
}
}
- // Explicit info.
- if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
- ClassTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo
- = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
- ExplicitInfo->TypeAsWritten = TyInfo;
- ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
- ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
- D->ExplicitInfo = ExplicitInfo;
- }
-
SmallVector<TemplateArgument, 8> TemplArgs;
Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(),
if (writtenAsCanonicalDecl) {
ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ // Set this as, or find, the canonical declaration for this specialization
+ ClassTemplateSpecializationDecl *CanonSpec;
if (ClassTemplatePartialSpecializationDecl *Partial =
dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
- CanonPattern->getCommonPtr()->PartialSpecializations
+ CanonSpec = CanonPattern->getCommonPtr()->PartialSpecializations
.GetOrInsertNode(Partial);
} else {
- CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ CanonSpec =
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
+ // If there was already a canonical specialization, merge into it.
+ if (CanonSpec != D) {
+ mergeRedeclarable<TagDecl>(D, CanonSpec, Redecl);
+
+ // This declaration might be a definition. Merge with any existing
+ // definition.
+ if (D->DefinitionData) {
+ if (!CanonSpec->DefinitionData) {
+ CanonSpec->DefinitionData = D->DefinitionData;
+ } else {
+ // FIXME: Check DefinitionData for consistency with prior definition
+ Reader.PendingDefinitions.erase(D);
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, CanonSpec->DefinitionData->Definition));
+ D->IsCompleteDefinition = false;
+ D->DefinitionData = CanonSpec->DefinitionData;
+ }
+ }
}
}
}
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
+ ClassTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo
+ = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = TyInfo;
+ ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
+ ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
return Redecl;
}
/// \brief Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
template<typename T>
-void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
RedeclarableResult &Redecl) {
// If modules are not available, there is no reason to perform this merge.
if (!Reader.getContext().getLangOpts().Modules)
return;
-
- if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D))) {
- if (T *Existing = ExistingRes) {
- T *ExistingCanon = Existing->getCanonicalDecl();
- T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
- if (ExistingCanon != DCanon) {
- // Have our redeclaration link point back at the canonical declaration
- // of the existing declaration, so that this declaration has the
- // appropriate canonical declaration.
- D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
-
- // When we merge a namespace, update its pointer to the first namespace.
- if (NamespaceDecl *Namespace
- = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
- Namespace->AnonOrFirstNamespaceAndInline.setPointer(
- static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
- }
-
- // Don't introduce DCanon into the set of pending declaration chains.
- Redecl.suppress();
-
- // Introduce ExistingCanon into the set of pending declaration chains,
- // if in fact it came from a module file.
- if (ExistingCanon->isFromASTFile()) {
- GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
- assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
- if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
- Reader.PendingDeclChains.push_back(ExistingCanonID);
- }
-
- // If this declaration was the canonical declaration, make a note of
- // that. We accept the linear algorithm here because the number of
- // unique canonical declarations of an entity should always be tiny.
- if (DCanon == static_cast<T*>(D)) {
- SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
- if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
- == Merged.end())
- Merged.push_back(Redecl.getFirstID());
-
- // If ExistingCanon did not come from a module file, introduce the
- // first declaration that *does* come from a module file to the
- // set of pending declaration chains, so that we merge this
- // declaration.
- if (!ExistingCanon->isFromASTFile() &&
- Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
- Reader.PendingDeclChains.push_back(Merged[0]);
- }
- }
+
+ if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
+ if (T *Existing = ExistingRes)
+ mergeRedeclarable(D, Existing, Redecl);
+}
+
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity.
+template<typename T>
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
+ RedeclarableResult &Redecl) {
+ T *ExistingCanon = Existing->getCanonicalDecl();
+ T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
+ if (ExistingCanon != DCanon) {
+ // Have our redeclaration link point back at the canonical declaration
+ // of the existing declaration, so that this declaration has the
+ // appropriate canonical declaration.
+ D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
+
+ // When we merge a namespace, update its pointer to the first namespace.
+ if (NamespaceDecl *Namespace
+ = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+ Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+ static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
+ }
+
+ // Don't introduce DCanon into the set of pending declaration chains.
+ Redecl.suppress();
+
+ // Introduce ExistingCanon into the set of pending declaration chains,
+ // if in fact it came from a module file.
+ if (ExistingCanon->isFromASTFile()) {
+ GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
+ assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
+ if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
+ Reader.PendingDeclChains.push_back(ExistingCanonID);
+ }
+
+ // If this declaration was the canonical declaration, make a note of
+ // that. We accept the linear algorithm here because the number of
+ // unique canonical declarations of an entity should always be tiny.
+ if (DCanon == static_cast<T*>(D)) {
+ SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
+ if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
+ == Merged.end())
+ Merged.push_back(Redecl.getFirstID());
+
+ // If ExistingCanon did not come from a module file, introduce the
+ // first declaration that *does* come from a module file to the
+ // set of pending declaration chains, so that we merge this
+ // declaration.
+ if (!ExistingCanon->isFromASTFile() &&
+ Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
+ Reader.PendingDeclChains.push_back(Merged[0]);
}
}
}
return true;
if (isa<ClassTemplateSpecializationDecl>(X)) {
- // FIXME: Deal with merging of template specializations.
- // For now, don't merge these; we need to check more than just the name to
- // determine if they refer to the same entity.
+ // No need to handle these here: we merge them when adding them to the
+ // template.
return false;
}
-
+
// Compatible tags match.
if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
TagDecl *TagY = cast<TagDecl>(Y);
return false;
}
+/// Find the context in which we should search for previous declarations when
+/// looking for declarations to merge.
+static DeclContext *getPrimaryContextForMerging(DeclContext *DC) {
+ if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
+ return ND->getOriginalNamespace();
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
+ return RD->getDefinition();
+
+ return 0;
+}
+
ASTDeclReader::FindExistingResult::~FindExistingResult() {
if (!AddResult || Existing)
return;
DeclContext *DC = New->getDeclContext()->getRedeclContext();
if (DC->isTranslationUnit() && Reader.SemaObj) {
Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
- } else if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
// Add the declaration to its redeclaration context so later merging
// lookups will find it.
- NS->getFirstDeclaration()->makeDeclVisibleInContextImpl(New,
- /*Internal*/true);
+ MergeDC->makeDeclVisibleInContextImpl(New, /*Internal*/true);
}
}
}
DeclContext *DC = D->getDeclContext()->getRedeclContext();
- if (!DC->isFileContext())
- return FindExistingResult(Reader);
-
if (DC->isTranslationUnit() && Reader.SemaObj) {
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
if (isSameEntity(*I, D))
return FindExistingResult(Reader, D, *I);
}
- } else if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
- DeclContext::lookup_result R = NS->getFirstDeclaration()->noload_lookup(Name);
+ return FindExistingResult(Reader, D, /*Existing=*/0);
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
+ DeclContext::lookup_result R = MergeDC->noload_lookup(Name);
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (isSameEntity(*I, D))
return FindExistingResult(Reader, D, *I);
}
+ return FindExistingResult(Reader, D, /*Existing=*/0);
}
-
- return FindExistingResult(Reader, D, /*Existing=*/0);
+
+ return FindExistingResult(Reader);
}
void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {