diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-10-18 06:05:18 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-10-18 06:05:18 +0000 |
commit | 2b9e3e396a6f0b1ebd247cb204f20a319f6ae7f4 (patch) | |
tree | c93d61965532f68d891027c703eae93cb71366ed /clang/lib/Serialization/ASTReader.cpp | |
parent | 3dc4f44e71bc9d5650b2cd134ca4733438acfbfb (diff) | |
download | bcm5719-llvm-2b9e3e396a6f0b1ebd247cb204f20a319f6ae7f4.tar.gz bcm5719-llvm-2b9e3e396a6f0b1ebd247cb204f20a319f6ae7f4.zip |
Basic ODR checking for C++ modules:
If we have multiple definitions of the same entity from different modules, we
nominate the first definition which we see as being the canonical definition.
If we load a declaration from a different definition and we can't find a
corresponding declaration in the canonical definition, issue a diagnostic.
This is insufficient to prevent things from going horribly wrong in all cases
-- we might be in the middle of emitting IR for a function when we trigger some
deserialization and discover that it refers to an incoherent piece of the AST,
by which point it's probably too late to bail out -- but we'll at least produce
a diagnostic.
llvm-svn: 192950
Diffstat (limited to 'clang/lib/Serialization/ASTReader.cpp')
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 9bb9a7a8632..bafe74b174a 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7337,7 +7337,8 @@ void ASTReader::ReadComments() { void ASTReader::finishPendingActions() { while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() || - !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty()) { + !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() || + !PendingOdrMergeChecks.empty()) { // If any identifiers with corresponding top-level declarations have // been loaded, load those declarations now. typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> > @@ -7400,6 +7401,64 @@ void ASTReader::finishPendingActions() { DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC)); Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext()); } + + // 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 (Decl::redecl_iterator RI = (*I)->redecls_begin(), + RE = (*I)->redecls_end(); + RI != RE; ++RI) { + 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(); + + Module *CanonDefModule = cast<Decl>(CanonDef)->getOwningModule(); + Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl) + << D << D->getOwningModule()->getFullModuleName() + << CanonDef << !CanonDefModule + << (CanonDefModule ? CanonDefModule->getFullModuleName() : ""); + + 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]; + } + } + } } // If we deserialized any C++ or Objective-C class definitions, any |