[modules] Don't defer performing updates if we have incomplete redecl chains.

Instead, perform them carefully immediately.

llvm-svn: 215147
This commit is contained in:
Richard Smith 2014-08-07 20:58:41 +00:00
parent d45e7cec42
commit d6db68c181
2 changed files with 39 additions and 25 deletions

View File

@ -8125,10 +8125,7 @@ void ASTReader::finishPendingActions() {
}
// Perform any pending declaration updates.
//
// Don't do this if we have known-incomplete redecl chains: it relies on
// being able to walk redeclaration chains.
while (PendingDeclChains.empty() && !PendingUpdateRecords.empty()) {
while (!PendingUpdateRecords.empty()) {
auto Update = PendingUpdateRecords.pop_back_val();
ReadingKindTracker ReadingKind(Read_Decl, *this);
loadDeclUpdateRecords(Update.first, Update.second);

View File

@ -3208,9 +3208,11 @@ public:
DeclT *operator*() { return Current; }
MergedRedeclIterator &operator++() {
if (Current->isFirstDecl())
if (Current->isFirstDecl()) {
Canonical = Current;
Current = Current->getPreviousDecl();
Current = Current->getMostRecentDecl();
} else
Current = Current->getPreviousDecl();
// If we started in the merged portion, we'll reach our start position
// eventually. Otherwise, we'll never reach it, but the second declaration
@ -3234,11 +3236,34 @@ llvm::iterator_range<MergedRedeclIterator<DeclT>> merged_redecls(DeclT *D) {
MergedRedeclIterator<DeclT>());
}
template<typename DeclT, typename Fn>
static void forAllLaterRedecls(DeclT *D, Fn F) {
F(D);
// Check whether we've already merged D into its redeclaration chain.
// MostRecent may or may not be nullptr if D has not been merged. If
// not, walk the merged redecl chain and see if it's there.
auto *MostRecent = D->getMostRecentDecl();
bool Found = false;
for (auto *Redecl = MostRecent; Redecl && !Found;
Redecl = Redecl->getPreviousDecl())
Found = (Redecl == D);
// If this declaration is merged, apply the functor to all later decls.
if (Found) {
for (auto *Redecl = MostRecent; Redecl != D;
Redecl = Redecl->getPreviousDecl())
F(Redecl);
}
}
void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
const RecordData &Record) {
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
// FIXME: If we also have an update record for instantiating the
// definition of D, we need that to happen before we get here.
Decl *MD = Reader.ReadDecl(ModuleFile, Record, Idx);
assert(MD && "couldn't read decl from update record");
// FIXME: We should call addHiddenDecl instead, to add the member
@ -3285,12 +3310,9 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
// Maintain AST consistency: any later redeclarations of this function
// are inline if this one is. (We might have merged another declaration
// into this one.)
for (auto *D = FD->getMostRecentDecl(); /**/;
D = D->getPreviousDecl()) {
D->setImplicitlyInline();
if (D == FD)
break;
}
forAllLaterRedecls(FD, [](FunctionDecl *FD) {
FD->setImplicitlyInline();
});
}
FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
@ -3379,9 +3401,13 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
}
case UPD_CXX_DEDUCED_RETURN_TYPE: {
FunctionDecl *FD = cast<FunctionDecl>(D);
Reader.Context.adjustDeducedFunctionResultType(
FD, Reader.readType(ModuleFile, Record, Idx));
// FIXME: Also do this when merging redecls.
QualType DeducedResultType = Reader.readType(ModuleFile, Record, Idx);
for (auto *Redecl : merged_redecls(D)) {
// FIXME: If the return type is already deduced, check that it matches.
FunctionDecl *FD = cast<FunctionDecl>(Redecl);
Reader.Context.adjustDeducedFunctionResultType(FD, DeducedResultType);
}
break;
}
@ -3389,17 +3415,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
// FIXME: This doesn't send the right notifications if there are
// ASTMutationListeners other than an ASTWriter.
// FIXME: We can't both pull in declarations (and thus create new pending
// redeclaration chains) *and* walk redeclaration chains in this function.
// We should defer the updates that require walking redecl chains.
// Maintain AST consistency: any later redeclarations are used too.
for (auto *Redecl = D->getMostRecentDecl(); /**/;
Redecl = Redecl->getPreviousDecl()) {
Redecl->Used = true;
if (Redecl == D)
break;
}
forAllLaterRedecls(D, [](Decl *D) { D->Used = true; });
break;
}