[modules] Factor out ODR checking, to avoid unnecessary repeated work in

finishPendingActions loop.

llvm-svn: 214246
This commit is contained in:
Richard Smith 2014-07-29 23:23:27 +00:00
parent 20c5c7b723
commit a0ce9c4651
2 changed files with 86 additions and 75 deletions

View File

@ -1245,6 +1245,7 @@ private:
void PassInterestingDeclToConsumer(Decl *D);
void finishPendingActions();
void diagnoseOdrViolations();
void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name);

View File

@ -8054,7 +8054,7 @@ void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() ||
!PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
!PendingUpdateRecords.empty() || !PendingOdrMergeChecks.empty()) {
!PendingUpdateRecords.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >
@ -8134,78 +8134,6 @@ void ASTReader::finishPendingActions() {
ReadingKindTracker ReadingKind(Read_Decl, *this);
loadDeclUpdateRecords(Update.first, Update.second);
}
// Trigger the import of the full definition of each class that had any
// odr-merging problems, so we can produce better diagnostics for them.
for (auto &Merge : PendingOdrMergeFailures) {
Merge.first->buildLookup();
Merge.first->decls_begin();
Merge.first->bases_begin();
Merge.first->vbases_begin();
for (auto *RD : Merge.second) {
RD->decls_begin();
RD->bases_begin();
RD->vbases_begin();
}
}
// For each declaration from a merged context, check that the canonical
// definition of that context also contains a declaration of the same
// entity.
while (!PendingOdrMergeChecks.empty()) {
NamedDecl *D = PendingOdrMergeChecks.pop_back_val();
// FIXME: Skip over implicit declarations for now. This matters for things
// like implicitly-declared special member functions. This isn't entirely
// correct; we can end up with multiple unmerged declarations of the same
// implicit entity.
if (D->isImplicit())
continue;
DeclContext *CanonDef = D->getDeclContext();
DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
bool Found = false;
const Decl *DCanon = D->getCanonicalDecl();
llvm::SmallVector<const NamedDecl*, 4> Candidates;
for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
!Found && I != E; ++I) {
for (auto RI : (*I)->redecls()) {
if (RI->getLexicalDeclContext() == CanonDef) {
// This declaration is present in the canonical definition. If it's
// in the same redecl chain, it's the one we're looking for.
if (RI->getCanonicalDecl() == DCanon)
Found = true;
else
Candidates.push_back(cast<NamedDecl>(RI));
break;
}
}
}
if (!Found) {
D->setInvalidDecl();
std::string CanonDefModule =
getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
<< D << getOwningModuleNameForDiagnostic(D)
<< CanonDef << CanonDefModule.empty() << CanonDefModule;
if (Candidates.empty())
Diag(cast<Decl>(CanonDef)->getLocation(),
diag::note_module_odr_violation_no_possible_decls) << D;
else {
for (unsigned I = 0, N = Candidates.size(); I != N; ++I)
Diag(Candidates[I]->getLocation(),
diag::note_module_odr_violation_possible_decl)
<< Candidates[I];
}
DiagnosedOdrMergeFailures.insert(CanonDef);
}
}
}
// If we deserialized any C++ or Objective-C class definitions, any
@ -8272,9 +8200,88 @@ void ASTReader::finishPendingActions() {
MD->setLazyBody(PB->second);
}
PendingBodies.clear();
}
void ASTReader::diagnoseOdrViolations() {
// Trigger the import of the full definition of each class that had any
// odr-merging problems, so we can produce better diagnostics for them.
for (auto &Merge : PendingOdrMergeFailures) {
Merge.first->buildLookup();
Merge.first->decls_begin();
Merge.first->bases_begin();
Merge.first->vbases_begin();
for (auto *RD : Merge.second) {
RD->decls_begin();
RD->bases_begin();
RD->vbases_begin();
}
}
// For each declaration from a merged context, check that the canonical
// definition of that context also contains a declaration of the same
// entity.
//
// Caution: this loop does things that might invalidate iterators into
// PendingOdrMergeChecks. Don't turn this into a range-based for loop!
while (!PendingOdrMergeChecks.empty()) {
NamedDecl *D = PendingOdrMergeChecks.pop_back_val();
// FIXME: Skip over implicit declarations for now. This matters for things
// like implicitly-declared special member functions. This isn't entirely
// correct; we can end up with multiple unmerged declarations of the same
// implicit entity.
if (D->isImplicit())
continue;
DeclContext *CanonDef = D->getDeclContext();
DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
bool Found = false;
const Decl *DCanon = D->getCanonicalDecl();
llvm::SmallVector<const NamedDecl*, 4> Candidates;
for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
!Found && I != E; ++I) {
for (auto RI : (*I)->redecls()) {
if (RI->getLexicalDeclContext() == CanonDef) {
// This declaration is present in the canonical definition. If it's
// in the same redecl chain, it's the one we're looking for.
if (RI->getCanonicalDecl() == DCanon)
Found = true;
else
Candidates.push_back(cast<NamedDecl>(RI));
break;
}
}
}
if (!Found) {
D->setInvalidDecl();
std::string CanonDefModule =
getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
<< D << getOwningModuleNameForDiagnostic(D)
<< CanonDef << CanonDefModule.empty() << CanonDefModule;
if (Candidates.empty())
Diag(cast<Decl>(CanonDef)->getLocation(),
diag::note_module_odr_violation_no_possible_decls) << D;
else {
for (unsigned I = 0, N = Candidates.size(); I != N; ++I)
Diag(Candidates[I]->getLocation(),
diag::note_module_odr_violation_possible_decl)
<< Candidates[I];
}
DiagnosedOdrMergeFailures.insert(CanonDef);
}
}
// Issue any pending ODR-failure diagnostics.
for (auto &Merge : PendingOdrMergeFailures) {
// If we've already pointed out a specific problem with this class, don't
// bother issuing a general "something's different" diagnostic.
if (!DiagnosedOdrMergeFailures.insert(Merge.first))
continue;
@ -8324,10 +8331,13 @@ void ASTReader::FinishedDeserializing() {
}
--NumCurrentElementsDeserializing;
if (NumCurrentElementsDeserializing == 0 && Consumer) {
if (NumCurrentElementsDeserializing == 0) {
diagnoseOdrViolations();
// We are not in recursive loading, so it's safe to pass the "interesting"
// decls to the consumer.
PassInterestingDeclsToConsumer();
if (Consumer)
PassInterestingDeclsToConsumer();
}
}