diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-04-19 03:48:30 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-04-19 03:48:30 +0000 |
commit | cd45dbc5f24c2f764c9c3435b7b31e74d6faac15 (patch) | |
tree | 79b2fcb05255ccfc49630aae44b8700c3ce59f27 /clang/lib/Serialization/ASTReader.cpp | |
parent | af90cf528c32265ecc6888714a28ef3e97342802 (diff) | |
download | bcm5719-llvm-cd45dbc5f24c2f764c9c3435b7b31e74d6faac15.tar.gz bcm5719-llvm-cd45dbc5f24c2f764c9c3435b7b31e74d6faac15.zip |
When a module completes the definition of a class template specialization imported from another module, emit an update record, rather than using the broken decl rewriting mechanism. If multiple modules do this, merge the definitions together, much as we would if they were separate declarations.
llvm-svn: 206680
Diffstat (limited to 'clang/lib/Serialization/ASTReader.cpp')
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 181 |
1 files changed, 144 insertions, 37 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 78bf151c63f..14075462bec 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2562,14 +2562,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { (const unsigned char *)Blob.data() + sizeof(uint32_t), (const unsigned char *)Blob.data(), ASTDeclContextNameLookupTrait(*this, F)); - if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU? - DeclContext *TU = Context.getTranslationUnitDecl(); - F.DeclContextInfos[TU].NameLookupTableData = Table; - TU->setHasExternalVisibleStorage(true); - } else if (Decl *D = DeclsLoaded[ID - NUM_PREDEF_DECL_IDS]) { + if (Decl *D = GetExistingDecl(ID)) { auto *DC = cast<DeclContext>(D); DC->getPrimaryContext()->setHasExternalVisibleStorage(true); auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData; + // FIXME: There should never be an existing lookup table. delete LookupTable; LookupTable = Table; } else @@ -2965,10 +2962,15 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { Error("invalid DECL_UPDATE_OFFSETS block in AST file"); return Failure; } - // FIXME: If we've already loaded the decl, perform the updates now. - for (unsigned I = 0, N = Record.size(); I != N; I += 2) - DeclUpdateOffsets[getGlobalDeclID(F, Record[I])] - .push_back(std::make_pair(&F, Record[I+1])); + for (unsigned I = 0, N = Record.size(); I != N; I += 2) { + GlobalDeclID ID = getGlobalDeclID(F, Record[I]); + DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I + 1])); + + // If we've already loaded the decl, perform the updates when we finish + // loading this block. + if (Decl *D = GetExistingDecl(ID)) + PendingUpdateRecords.push_back(std::make_pair(ID, D)); + } break; } @@ -3626,11 +3628,24 @@ void ASTReader::InitializeContext() { DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, Context.getTranslationUnitDecl()); - // Make sure we load the declaration update records for the translation unit, - // if there are any. - loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID, - Context.getTranslationUnitDecl()); - + // For any declarations we have already loaded, load any update records. + { + // We're not back to a consistent state until all our pending update + // records have been loaded. There can be interdependencies between them. + Deserializing SomeUpdateRecords(this); + ReadingKindTracker ReadingKind(Read_Decl, *this); + + // Make sure we load the declaration update records for the translation + // unit, if there are any. + // FIXME: Is this necessary any more? + loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID, + Context.getTranslationUnitDecl()); + + for (auto &Update : PendingUpdateRecords) + loadDeclUpdateRecords(Update.first, Update.second); + PendingUpdateRecords.clear(); + } + // FIXME: Find a better way to deal with collisions between these // built-in types. Right now, we just ignore the problem. @@ -5844,11 +5859,14 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) { return GetDecl(ID); } -uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record, - unsigned &Idx){ - if (Idx >= Record.size()) +uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, + const RecordData &Record, + unsigned &Idx) { + if (Idx >= Record.size() || Record[Idx] > M.LocalNumCXXBaseSpecifiers) { + Error("malformed AST file: missing C++ base specifier"); return 0; - + } + unsigned LocalID = Record[Idx++]; return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]); } @@ -5863,7 +5881,7 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { unsigned Code = Cursor.ReadCode(); unsigned RecCode = Cursor.readRecord(Code, Record); if (RecCode != DECL_CXX_BASE_SPECIFIERS) { - Error("Malformed AST file: missing C++ base specifiers"); + Error("malformed AST file: missing C++ base specifiers"); return 0; } @@ -5906,14 +5924,14 @@ ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) { SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) { if (ID < NUM_PREDEF_DECL_IDS) return SourceLocation(); - + unsigned Index = ID - NUM_PREDEF_DECL_IDS; if (Index > DeclsLoaded.size()) { Error("declaration ID out-of-range for AST file"); return SourceLocation(); } - + if (Decl *D = DeclsLoaded[Index]) return D->getLocation(); @@ -5922,15 +5940,15 @@ SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) { return ReadSourceLocation(*Rec.F, RawLocation); } -Decl *ASTReader::GetDecl(DeclID ID) { - if (ID < NUM_PREDEF_DECL_IDS) { +Decl *ASTReader::GetExistingDecl(DeclID ID) { + if (ID < NUM_PREDEF_DECL_IDS) { switch ((PredefinedDeclIDs)ID) { case PREDEF_DECL_NULL_ID: return 0; - + case PREDEF_DECL_TRANSLATION_UNIT_ID: return Context.getTranslationUnitDecl(); - + case PREDEF_DECL_OBJC_ID_ID: return Context.getObjCIdDecl(); @@ -5939,16 +5957,16 @@ Decl *ASTReader::GetDecl(DeclID ID) { case PREDEF_DECL_OBJC_CLASS_ID: return Context.getObjCClassDecl(); - + case PREDEF_DECL_OBJC_PROTOCOL_ID: return Context.getObjCProtocolDecl(); - + case PREDEF_DECL_INT_128_ID: return Context.getInt128Decl(); case PREDEF_DECL_UNSIGNED_INT_128_ID: return Context.getUInt128Decl(); - + case PREDEF_DECL_OBJC_INSTANCETYPE_ID: return Context.getObjCInstanceTypeDecl(); @@ -5956,7 +5974,7 @@ Decl *ASTReader::GetDecl(DeclID ID) { return Context.getBuiltinVaListDecl(); } } - + unsigned Index = ID - NUM_PREDEF_DECL_IDS; if (Index >= DeclsLoaded.size()) { @@ -5964,7 +5982,22 @@ Decl *ASTReader::GetDecl(DeclID ID) { Error("declaration ID out-of-range for AST file"); return 0; } - + + return DeclsLoaded[Index]; +} + +Decl *ASTReader::GetDecl(DeclID ID) { + if (ID < NUM_PREDEF_DECL_IDS) + return GetExistingDecl(ID); + + unsigned Index = ID - NUM_PREDEF_DECL_IDS; + + if (Index >= DeclsLoaded.size()) { + assert(0 && "declaration ID out-of-range for AST file"); + Error("declaration ID out-of-range for AST file"); + return 0; + } + if (!DeclsLoaded[Index]) { ReadDeclRecord(ID); if (DeserializationListener) @@ -6270,14 +6303,19 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, Contexts.push_back(DC); if (DC->isNamespace()) { - MergedDeclsMap::iterator Merged - = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); + auto Merged = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); if (Merged != MergedDecls.end()) { for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); } } - + if (isa<CXXRecordDecl>(DC)) { + auto Merged = MergedLookups.find(DC); + if (Merged != MergedLookups.end()) + Contexts.insert(Contexts.end(), Merged->second.begin(), + Merged->second.end()); + } + DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls); // If we can definitively determine which module file to look into, @@ -7820,6 +7858,19 @@ void ASTReader::ReadComments() { } } +std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { + // If we know the owning module, use it. + if (Module *M = D->getOwningModule()) + return M->getFullModuleName(); + + // Otherwise, use the name of the top-level module the decl is within. + if (ModuleFile *M = getOwningModuleFile(D)) + return M->ModuleName; + + // Not from a module. + return ""; +} + void ASTReader::finishPendingActions() { while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() || !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() || @@ -7887,6 +7938,20 @@ void ASTReader::finishPendingActions() { Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext()); } + // 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. @@ -7925,11 +7990,11 @@ void ASTReader::finishPendingActions() { if (!Found) { D->setInvalidDecl(); - Module *CanonDefModule = cast<Decl>(CanonDef)->getOwningModule(); + std::string CanonDefModule = + getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef)); Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl) - << D << D->getOwningModule()->getFullModuleName() - << CanonDef << !CanonDefModule - << (CanonDefModule ? CanonDefModule->getFullModuleName() : ""); + << D << getOwningModuleNameForDiagnostic(D) + << CanonDef << CanonDefModule.empty() << CanonDefModule; if (Candidates.empty()) Diag(cast<Decl>(CanonDef)->getLocation(), @@ -7940,6 +8005,8 @@ void ASTReader::finishPendingActions() { diag::note_module_odr_violation_possible_decl) << Candidates[I]; } + + DiagnosedOdrMergeFailures.insert(CanonDef); } } } @@ -8009,6 +8076,46 @@ void ASTReader::finishPendingActions() { MD->setLazyBody(PB->second); } PendingBodies.clear(); + + // Issue any pending ODR-failure diagnostics. + for (auto &Merge : PendingOdrMergeFailures) { + if (!DiagnosedOdrMergeFailures.insert(Merge.first)) + continue; + + bool Diagnosed = false; + for (auto *RD : Merge.second) { + // Multiple different declarations got merged together; tell the user + // where they came from. + if (Merge.first != RD) { + // FIXME: Walk the definition, figure out what's different, + // and diagnose that. + if (!Diagnosed) { + std::string Module = getOwningModuleNameForDiagnostic(Merge.first); + Diag(Merge.first->getLocation(), + diag::err_module_odr_violation_different_definitions) + << Merge.first << Module.empty() << Module; + Diagnosed = true; + } + + Diag(RD->getLocation(), + diag::note_module_odr_violation_different_definitions) + << getOwningModuleNameForDiagnostic(RD); + } + } + + if (!Diagnosed) { + // All definitions are updates to the same declaration. This happens if a + // module instantiates the declaration of a class template specialization + // and two or more other modules instantiate its definition. + // + // FIXME: Indicate which modules had instantiations of this definition. + // FIXME: How can this even happen? + Diag(Merge.first->getLocation(), + diag::err_module_odr_violation_different_instantiations) + << Merge.first; + } + } + PendingOdrMergeFailures.clear(); } void ASTReader::FinishedDeserializing() { |