diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-08-06 04:23:48 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-08-06 04:23:48 +0000 |
commit | 0f4e2c4d0f46b5edb4159b2d982327475b797efe (patch) | |
tree | c893a8277ae403c41609130361a3d4d2fe141a6c /clang/lib/Serialization/ASTReader.cpp | |
parent | 9b000812a44316016abe214ae98212b3cdd079fc (diff) | |
download | bcm5719-llvm-0f4e2c4d0f46b5edb4159b2d982327475b797efe.tar.gz bcm5719-llvm-0f4e2c4d0f46b5edb4159b2d982327475b797efe.zip |
[modules] Defer setting up the lookup table for a DeclContext until we can
determine the primary context, rather than sometimes registering the lookup
table on the wrong context.
This exposed a couple of bugs:
* the odr violation check didn't deal properly with mergeable declarations
if the declaration retained by name lookup wasn't in the canonical
definition of the class
* the (broken) RewriteDecl mechanism would emit two name lookup tables for
the same DeclContext into the same module file (one as part of the
rewritten declaration and one as a visible update for the old declaration)
These are both fixed too.
llvm-svn: 244192
Diffstat (limited to 'clang/lib/Serialization/ASTReader.cpp')
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 143 |
1 files changed, 69 insertions, 74 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index abc91e771ec..41294a82b26 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -955,48 +955,54 @@ ASTDeclContextNameLookupTrait::ReadData(internal_key_type, return std::make_pair(Start, Start + NumDecls); } -bool ASTReader::ReadDeclContextStorage(ModuleFile &M, - BitstreamCursor &Cursor, - const std::pair<uint64_t, uint64_t> &Offsets, - DeclContextInfo &Info) { - SavedStreamPosition SavedPosition(Cursor); - // First the lexical decls. - if (Offsets.first != 0) { - Cursor.JumpToBit(Offsets.first); +bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, + BitstreamCursor &Cursor, + uint64_t Offset, + DeclContext *DC) { + assert(Offset != 0); - RecordData Record; - StringRef Blob; - unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); - if (RecCode != DECL_CONTEXT_LEXICAL) { - Error("Expected lexical block"); - return true; - } + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); - Info.LexicalDecls = llvm::makeArrayRef( - reinterpret_cast<const KindDeclIDPair *>(Blob.data()), - Blob.size() / sizeof(KindDeclIDPair)); + RecordData Record; + StringRef Blob; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); + if (RecCode != DECL_CONTEXT_LEXICAL) { + Error("Expected lexical block"); + return true; } - // Now the lookup table. - if (Offsets.second != 0) { - Cursor.JumpToBit(Offsets.second); + M.DeclContextInfos[DC].LexicalDecls = llvm::makeArrayRef( + reinterpret_cast<const KindDeclIDPair *>(Blob.data()), + Blob.size() / sizeof(KindDeclIDPair)); + DC->setHasExternalLexicalStorage(true); + return false; +} - RecordData Record; - StringRef Blob; - unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); - if (RecCode != DECL_CONTEXT_VISIBLE) { - Error("Expected visible lookup table block"); - return true; - } - Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create( - (const unsigned char *)Blob.data() + Record[0], - (const unsigned char *)Blob.data() + sizeof(uint32_t), - (const unsigned char *)Blob.data(), - ASTDeclContextNameLookupTrait(*this, M)); +bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, + BitstreamCursor &Cursor, + uint64_t Offset, + DeclID ID) { + assert(Offset != 0); + + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + + RecordData Record; + StringRef Blob; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); + if (RecCode != DECL_CONTEXT_VISIBLE) { + Error("Expected visible lookup table block"); + return true; } + // We can't safely determine the primary context yet, so delay attaching the + // lookup table until we're done with recursive deserialization. + unsigned BucketOffset = Record[0]; + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{ + &M, (const unsigned char *)Blob.data(), BucketOffset}); return false; } @@ -2503,20 +2509,14 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { case UPDATE_VISIBLE: { unsigned Idx = 0; serialization::DeclID ID = ReadDeclID(F, Record, Idx); - ASTDeclContextNameLookupTable *Table = - ASTDeclContextNameLookupTable::Create( - (const unsigned char *)Blob.data() + Record[Idx++], - (const unsigned char *)Blob.data() + sizeof(uint32_t), - (const unsigned char *)Blob.data(), - ASTDeclContextNameLookupTrait(*this, F)); - if (Decl *D = GetExistingDecl(ID)) { - auto *DC = cast<DeclContext>(D); - DC->getPrimaryContext()->setHasExternalVisibleStorage(true); - auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData; - delete LookupTable; - LookupTable = Table; - } else - PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F)); + auto *Data = (const unsigned char*)Blob.data(); + unsigned BucketOffset = Record[Idx++]; + PendingVisibleUpdates[ID].push_back( + PendingVisibleUpdate{&F, Data, BucketOffset}); + // 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; } @@ -8331,21 +8331,26 @@ void ASTReader::diagnoseOdrViolations() { if (Found) continue; + // Quick check failed, time to do the slow thing. Note, we can't just + // look up the name of D in CanonDef here, because the member that is + // in CanonDef might not be found by name lookup (it might have been + // replaced by a more recent declaration in the lookup table), and we + // can't necessarily find it in the redeclaration chain because it might + // be merely mergeable, not redeclarable. llvm::SmallVector<const NamedDecl*, 4> Candidates; - DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName()); - 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; - } + for (auto *CanonMember : CanonDef->decls()) { + if (CanonMember->getCanonicalDecl() == DCanon) { + // This can happen if the declaration is merely mergeable and not + // actually redeclarable (we looked for redeclarations earlier). + // + // FIXME: We should be able to detect this more efficiently, without + // pulling in all of the members of CanonDef. + Found = true; + break; } + if (auto *ND = dyn_cast<NamedDecl>(CanonMember)) + if (ND->getDeclName() == D->getDeclName()) + Candidates.push_back(ND); } if (!Found) { @@ -8454,11 +8459,11 @@ void ASTReader::FinishedDeserializing() { } } - diagnoseOdrViolations(); - if (ReadTimer) ReadTimer->stopTimer(); + diagnoseOdrViolations(); + // We are not in recursive loading, so it's safe to pass the "interesting" // decls to the consumer. if (Consumer) @@ -8527,14 +8532,4 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, ASTReader::~ASTReader() { if (OwnsDeserializationListener) delete DeserializationListener; - - for (DeclContextVisibleUpdatesPending::iterator - I = PendingVisibleUpdates.begin(), - E = PendingVisibleUpdates.end(); - I != E; ++I) { - for (DeclContextVisibleUpdates::iterator J = I->second.begin(), - F = I->second.end(); - J != F; ++J) - delete J->first; - } } |