forked from OSchip/llvm-project
Serialize the AST reader's mapping from canonical declarations to the
set of (previously-canonical) declaration IDs to the module file, so that future AST reader instances that load the module know which declarations are merged. This is important in the fairly tricky case where a declaration of an entity, e.g., @class X; occurs before the import of a module that also declares that entity. We merge the declarations, and record the fact that the declaration of X loaded from the module was merged into the (now canonical) declaration of X that we parsed. llvm-svn: 147181
This commit is contained in:
parent
6ca42c5be3
commit
464b0ca61a
|
@ -452,7 +452,10 @@ namespace clang {
|
|||
|
||||
/// \brief Record code for an array of all of the (sub)modules that were
|
||||
/// imported by the AST file.
|
||||
IMPORTED_MODULES = 51
|
||||
IMPORTED_MODULES = 51,
|
||||
|
||||
/// \brief Record code for the set of merged declarations in an AST file.
|
||||
MERGED_DECLARATIONS = 52
|
||||
};
|
||||
|
||||
/// \brief Record types used within a source manager block.
|
||||
|
|
|
@ -690,6 +690,26 @@ private:
|
|||
/// that canonical declaration.
|
||||
MergedDeclsMap MergedDecls;
|
||||
|
||||
typedef llvm::DenseMap<serialization::GlobalDeclID,
|
||||
llvm::SmallVector<serialization::DeclID, 2> >
|
||||
StoredMergedDeclsMap;
|
||||
|
||||
/// \brief A mapping from canonical declaration IDs to the set of additional
|
||||
/// declaration IDs that have been merged with that canonical declaration.
|
||||
///
|
||||
/// This is the deserialized representation of the entries in MergedDecls.
|
||||
/// When we query entries in MergedDecls, they will be augmented with entries
|
||||
/// from StoredMergedDecls.
|
||||
StoredMergedDeclsMap StoredMergedDecls;
|
||||
|
||||
/// \brief Combine the stored merged declarations for the given canonical
|
||||
/// declaration into the set of merged declarations.
|
||||
///
|
||||
/// \returns An iterator into MergedDecls that corresponds to the position of
|
||||
/// the given canonical declaration.
|
||||
MergedDeclsMap::iterator
|
||||
combineStoredMergedDecls(Decl *Canon, serialization::GlobalDeclID CanonID);
|
||||
|
||||
/// \brief We delay loading the chain of objc categories after recursive
|
||||
/// loading of declarations is finished.
|
||||
std::vector<std::pair<ObjCInterfaceDecl *, serialization::DeclID> >
|
||||
|
|
|
@ -415,7 +415,8 @@ private:
|
|||
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
|
||||
void WriteFPPragmaOptions(const FPOptions &Opts);
|
||||
void WriteOpenCLExtensions(Sema &SemaRef);
|
||||
|
||||
void WriteMergedDecls();
|
||||
|
||||
unsigned DeclParmVarAbbrev;
|
||||
unsigned DeclContextLexicalAbbrev;
|
||||
unsigned DeclContextVisibleLookupAbbrev;
|
||||
|
|
|
@ -2407,6 +2407,16 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
|
|||
F.RedeclarationsInfo = (const LocalRedeclarationsInfo *)BlobStart;
|
||||
break;
|
||||
}
|
||||
|
||||
case MERGED_DECLARATIONS: {
|
||||
for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) {
|
||||
GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]);
|
||||
SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID];
|
||||
for (unsigned N = Record[Idx++]; N > 0; --N)
|
||||
Decls.push_back(getGlobalDeclID(F, Record[Idx++]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Error("premature end of bitstream in AST file");
|
||||
|
|
|
@ -676,9 +676,14 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
|
|||
}
|
||||
|
||||
// If this declaration was the canonical declaration, make a note of
|
||||
// that.
|
||||
if (IDCanon == ID)
|
||||
Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID());
|
||||
// that. We accept the linear algorithm here because the number of
|
||||
// unique canonical declarations of an entity should always be tiny.
|
||||
if (IDCanon == ID) {
|
||||
SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
|
||||
if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
|
||||
== Merged.end())
|
||||
Merged.push_back(Redecl.getFirstID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1725,6 +1730,29 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
|
|||
}
|
||||
}
|
||||
|
||||
ASTReader::MergedDeclsMap::iterator
|
||||
ASTReader::combineStoredMergedDecls(Decl *Canon, GlobalDeclID CanonID) {
|
||||
// If we don't have any stored merged declarations, just look in the
|
||||
// merged declarations set.
|
||||
StoredMergedDeclsMap::iterator StoredPos = StoredMergedDecls.find(CanonID);
|
||||
if (StoredPos == StoredMergedDecls.end())
|
||||
return MergedDecls.find(Canon);
|
||||
|
||||
// Append the stored merged declarations to the merged declarations set.
|
||||
MergedDeclsMap::iterator Pos = MergedDecls.find(Canon);
|
||||
if (Pos == MergedDecls.end())
|
||||
Pos = MergedDecls.insert(std::make_pair(Canon,
|
||||
SmallVector<DeclID, 2>())).first;
|
||||
Pos->second.append(StoredPos->second.begin(), StoredPos->second.end());
|
||||
StoredMergedDecls.erase(StoredPos);
|
||||
|
||||
// Sort and uniquify the set of merged declarations.
|
||||
llvm::array_pod_sort(Pos->second.begin(), Pos->second.end());
|
||||
Pos->second.erase(std::unique(Pos->second.begin(), Pos->second.end()),
|
||||
Pos->second.end());
|
||||
return Pos;
|
||||
}
|
||||
|
||||
void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
|
||||
Decl *previous = GetDecl(ID);
|
||||
ASTDeclReader::attachPreviousDecl(D, previous);
|
||||
|
@ -2186,7 +2214,7 @@ static Decl *getMostRecentDecl(Decl *D) {
|
|||
void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
|
||||
Decl *D = GetDecl(ID);
|
||||
Decl *CanonDecl = D->getCanonicalDecl();
|
||||
|
||||
|
||||
// Determine the set of declaration IDs we'll be searching for.
|
||||
llvm::SmallVector<DeclID, 1> SearchDecls;
|
||||
GlobalDeclID CanonID = 0;
|
||||
|
@ -2194,7 +2222,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
|
|||
SearchDecls.push_back(ID); // Always first.
|
||||
CanonID = ID;
|
||||
}
|
||||
MergedDeclsMap::iterator MergedPos = MergedDecls.find(CanonDecl);
|
||||
MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID);
|
||||
if (MergedPos != MergedDecls.end())
|
||||
SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
|
||||
|
||||
|
|
|
@ -2903,6 +2903,25 @@ void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {
|
|||
Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
|
||||
}
|
||||
|
||||
void ASTWriter::WriteMergedDecls() {
|
||||
if (!Chain || Chain->MergedDecls.empty())
|
||||
return;
|
||||
|
||||
RecordData Record;
|
||||
for (ASTReader::MergedDeclsMap::iterator I = Chain->MergedDecls.begin(),
|
||||
IEnd = Chain->MergedDecls.end();
|
||||
I != IEnd; ++I) {
|
||||
DeclID CanonID = I->first->isFromASTFile()? Chain->DeclToID[I->first]
|
||||
: getDeclID(I->first);
|
||||
assert(CanonID && "Merged declaration not known?");
|
||||
|
||||
Record.push_back(CanonID);
|
||||
Record.push_back(I->second.size());
|
||||
Record.append(I->second.begin(), I->second.end());
|
||||
}
|
||||
Stream.EmitRecord(MERGED_DECLARATIONS, Record);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// General Serialization Routines
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -3401,7 +3420,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
|||
WriteDeclUpdatesBlocks();
|
||||
WriteDeclReplacementsBlock();
|
||||
WriteChainedObjCCategories();
|
||||
|
||||
WriteMergedDecls();
|
||||
|
||||
if (!LocalRedeclarations.empty()) {
|
||||
// Sort the local redeclarations info by the first declaration ID,
|
||||
// since the reader will be perforing binary searches on this information.
|
||||
|
|
|
@ -8,6 +8,8 @@ __import_module__ redecl_merge_right;
|
|||
|
||||
@class A;
|
||||
|
||||
void refers_to_C4(C4*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
template<typename T> class Vector;
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ void accept_a_C2(C2*);
|
|||
void accept_a_C3(C3*);
|
||||
@class C3;
|
||||
|
||||
@class C4;
|
||||
|
||||
@class Explicit;
|
||||
|
||||
int *explicit_func(void);
|
||||
|
|
|
@ -58,13 +58,18 @@ void test_C3(C3 *c3) {
|
|||
C4 *global_C4;
|
||||
__import_module__ redecl_merge_left_left;
|
||||
|
||||
void test_C4(C4 *c4) {
|
||||
void test_C4a(C4 *c4) {
|
||||
global_C4 = c4 = get_a_C4();
|
||||
accept_a_C4(c4);
|
||||
}
|
||||
|
||||
__import_module__ redecl_merge_bottom;
|
||||
|
||||
void test_C4b() {
|
||||
if (&refers_to_C4) {
|
||||
}
|
||||
}
|
||||
|
||||
@implementation B
|
||||
+ (B*)create_a_B { return 0; }
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue