class RedeclarableResult {
ASTReader &Reader;
GlobalDeclID FirstID;
+ Decl *MergeWith;
mutable bool Owning;
Decl::Kind DeclKind;
public:
RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID,
- Decl::Kind DeclKind)
- : Reader(Reader), FirstID(FirstID), Owning(true), DeclKind(DeclKind) { }
+ Decl *MergeWith, Decl::Kind DeclKind)
+ : Reader(Reader), FirstID(FirstID), MergeWith(MergeWith),
+ Owning(true), DeclKind(DeclKind) {}
RedeclarableResult(const RedeclarableResult &Other)
- : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning) ,
- DeclKind(Other.DeclKind)
- {
+ : Reader(Other.Reader), FirstID(Other.FirstID),
+ MergeWith(Other.MergeWith), Owning(Other.Owning),
+ DeclKind(Other.DeclKind) {
Other.Owning = false;
}
/// \brief Retrieve the first ID.
GlobalDeclID getFirstID() const { return FirstID; }
-
+
+ /// \brief Get a known declaration that this should be merged with, if
+ /// any.
+ Decl *getKnownMergeTarget() const { return MergeWith; }
+
/// \brief Do not introduce this declaration ID into the set of pending
/// declaration chains.
void suppress() {
}
template <typename T>
-ASTDeclReader::RedeclarableResult
+ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
DeclID FirstDeclID = ReadDeclID(Record, Idx);
-
+ Decl *MergeWith = nullptr;
+
// 0 indicates that this declaration was the only declaration of its entity,
// and is used for space optimization.
if (FirstDeclID == 0)
FirstDeclID = ThisDeclID;
-
+ else if (Record[Idx++]) {
+ // We need to merge with FirstDeclID. Read it now to ensure that it is
+ // before us in the redecl chain, then forget we saw it so that we will
+ // merge with it.
+ MergeWith = Reader.GetDecl(FirstDeclID);
+ FirstDeclID = ThisDeclID;
+ }
+
T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
if (FirstDecl != D) {
// We delay loading of the redeclaration chain to avoid deeply nested calls.
// The result structure takes care to note that we need to load the
// other declaration chains for this ID.
- return RedeclarableResult(Reader, FirstDeclID,
+ return RedeclarableResult(Reader, FirstDeclID, MergeWith,
static_cast<T *>(D)->getKind());
}
if (!Reader.getContext().getLangOpts().Modules)
return;
- if (FindExistingResult ExistingRes = findExisting(D))
+ if (auto *Existing = Redecl.getKnownMergeTarget())
+ // We already know of an existing declaration we should merge with.
+ mergeRedeclarable(D, cast<T>(Existing), Redecl, TemplatePatternID);
+ else if (FindExistingResult ExistingRes = findExisting(D))
if (T *Existing = ExistingRes)
mergeRedeclarable(D, Existing, Redecl, TemplatePatternID);
}
auto *DPattern = D->getTemplatedDecl();
auto *ExistingPattern = Existing->getTemplatedDecl();
RedeclarableResult Result(Reader, DPattern->getCanonicalDecl()->getGlobalID(),
- DPattern->getKind());
+ /*MergeWith*/ExistingPattern, DPattern->getKind());
if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) {
// Merge with any existing definition.
template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
T *First = D->getFirstDecl();
- if (First->getMostRecentDecl() != First) {
+ T *MostRecent = First->getMostRecentDecl();
+ if (MostRecent != First) {
assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) &&
"Not considered redeclarable?");
-
+
+ auto *Previous = D->getPreviousDecl();
+ auto *FirstToEmit = First;
+ if (Context.getLangOpts().Modules && Writer.Chain && !Previous) {
+ // In a modules build, we can have imported declarations after a local
+ // canonical declaration. If we do, we want to treat the first imported
+ // declaration as our canonical declaration on reload, in order to
+ // rebuild the redecl chain in the right order.
+ for (auto *Redecl = MostRecent; Redecl;
+ Redecl = Redecl->getPreviousDecl())
+ if (Redecl->isFromASTFile())
+ FirstToEmit = Redecl;
+ }
+
// There is more than one declaration of this entity, so we will need to
// write a redeclaration chain.
- Writer.AddDeclRef(First, Record);
+ Writer.AddDeclRef(FirstToEmit, Record);
+ Record.push_back(FirstToEmit != First);
Writer.Redeclarations.insert(First);
// Make sure that we serialize both the previous and the most-recent
// declarations, which (transitively) ensures that all declarations in the
// chain get serialized.
- (void)Writer.GetDeclRef(D->getPreviousDecl());
- (void)Writer.GetDeclRef(First->getMostRecentDecl());
+ //
+ // FIXME: This is not correct; when we reach an imported declaration we
+ // won't emit its previous declaration.
+ (void)Writer.GetDeclRef(Previous);
+ (void)Writer.GetDeclRef(MostRecent);
} else {
// We use the sentinel value 0 to indicate an only declaration.
Record.push_back(0);
}
-
}
void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
// Determine the ID for this declaration.
serialization::DeclID ID;
- if (D->isFromASTFile())
+ if (D->isFromASTFile()) {
+ assert(isRewritten(D) && "should not be emitting imported decl");
ID = getDeclID(D);
- else {
+ } else {
serialization::DeclID &IDR = DeclIDs[D];
if (IDR == 0)
IDR = NextDeclID++;