From: Douglas Gregor Date: Tue, 3 Jan 2012 22:46:00 +0000 (+0000) Subject: Implement cross-module declaration merging for tag declarations, so X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1ca4a5c41b8707b5fafcd1af1c9824b1bb19a399;p=clang Implement cross-module declaration merging for tag declarations, so that if two modules A and B both contain a declaration of a tag such as struct X; and those two modules are unrelated, the two declarations of X will be merged into a single redeclaration chain. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147488 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 82f6fae4a0..4871a3049a 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -182,6 +182,10 @@ namespace clang { ~FindExistingResult(); + /// \brief Suppress the addition of this result into the known set of + /// names. + void suppress() { AddResult = false; } + operator NamedDecl*() const { return Existing; } template @@ -412,20 +416,27 @@ void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) { } void ASTDeclReader::VisitTagDecl(TagDecl *TD) { - VisitRedeclarable(TD); + // Record the declaration -> global ID mapping. + Reader.DeclToID[TD] = ThisDeclID; + + RedeclarableResult Redecl = VisitRedeclarable(TD); VisitTypeDecl(TD); + TD->IdentifierNamespace = Record[Idx++]; TD->setTagKind((TagDecl::TagKind)Record[Idx++]); TD->setCompleteDefinition(Record[Idx++]); TD->setEmbeddedInDeclarator(Record[Idx++]); TD->setFreeStanding(Record[Idx++]); TD->setRBraceLoc(ReadSourceLocation(Record, Idx)); + if (Record[Idx++]) { // hasExtInfo TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo(); ReadQualifierInfo(*Info, Record, Idx); TD->TypedefNameDeclOrQualifier = Info; } else TD->setTypedefNameForAnonDecl(ReadDeclAs(Record, Idx)); + + mergeRedeclarable(TD, Redecl); } void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { @@ -1547,6 +1558,14 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable *D, if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID()) == Merged.end()) Merged.push_back(Redecl.getFirstID()); + + // If ExistingCanon did not come from a module file, introduce the + // first declaration that *does* come from a module file is in the + // set of pending declaration chains, so that we merge this + // declaration. + if (!ExistingCanon->isFromASTFile() && + Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID())) + Reader.PendingDeclChains.push_back(Merged[0]); } } } @@ -1662,6 +1681,15 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { if (isa(X) || isa(X)) return true; + // Compatible tags match. + if (TagDecl *TagX = dyn_cast(X)) { + TagDecl *TagY = cast(Y); + if ((TagX->getTagKind() == TagY->getTagKind()) || + ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class)&& + (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class))) + return true; + } + // FIXME: Many other cases to implement. return false; } @@ -1679,13 +1707,21 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() { } ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { + DeclarationName Name = D->getDeclName(); + if (!Name) { + // Don't bother trying to find unnamed declarations. + FindExistingResult Result(Reader, D, /*Existing=*/0); + Result.suppress(); + return Result; + } + DeclContext *DC = D->getDeclContext()->getRedeclContext(); if (!DC->isFileContext()) return FindExistingResult(Reader); if (DC->isTranslationUnit() && Reader.SemaObj) { IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver; - for (IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), + for (IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); I != IEnd; ++I) { if (isSameEntity(*I, D)) diff --git a/test/Modules/Inputs/redecl-merge-bottom.h b/test/Modules/Inputs/redecl-merge-bottom.h index a054cd2059..4e52a67247 100644 --- a/test/Modules/Inputs/redecl-merge-bottom.h +++ b/test/Modules/Inputs/redecl-merge-bottom.h @@ -13,6 +13,9 @@ @protocol P1; +struct S1; +struct S3; + void refers_to_C4(C4*); #ifdef __cplusplus diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h index 82146f7ed5..b21271b146 100644 --- a/test/Modules/Inputs/redecl-merge-left.h +++ b/test/Modules/Inputs/redecl-merge-left.h @@ -15,6 +15,14 @@ - (void)protoMethod2; @end +struct S1; +struct S2 { + int field; +}; + +struct S1 *produce_S1(void); +void consume_S2(struct S2*); + // Test declarations in different modules with no common initial // declaration. @class C; @@ -39,6 +47,15 @@ struct explicit_struct; @protocol P3; +struct S3; +struct S3; +struct S4 { + int field; +}; + +struct S3 *produce_S3(void); +void consume_S4(struct S4*); + #ifdef __cplusplus template class Vector; diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h index b6dfe2f53c..686a96228a 100644 --- a/test/Modules/Inputs/redecl-merge-right.h +++ b/test/Modules/Inputs/redecl-merge-right.h @@ -21,6 +21,12 @@ @protocol P2; +struct S1; +struct S2; + +void consume_S1(struct S1*); +struct S2 *produce_S2(void); + // Test declarations in different modules with no common initial // declaration. @class C; @@ -47,6 +53,12 @@ struct explicit_struct; @protocol P3; @protocol P3; +struct S3; +struct S4; + +void consume_S3(struct S3*); +struct S4 *produce_S4(void); + #ifdef __cplusplus template class Vector { public: diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h index 64c0c92546..519254ca22 100644 --- a/test/Modules/Inputs/redecl-merge-top.h +++ b/test/Modules/Inputs/redecl-merge-top.h @@ -11,6 +11,10 @@ @protocol P2; @protocol P2; +struct S1; +struct S2; +struct S2; + #ifdef __cplusplus template class Vector; #endif diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m index dfbc25fe9e..c0e83e8a86 100644 --- a/test/Modules/redecl-merge.m +++ b/test/Modules/redecl-merge.m @@ -32,6 +32,29 @@ void testProtoMerge(id p1, id p2) { [p2 protoMethod2]; } +struct S1 { + int s1_field; +}; + +struct S3 { + int s3_field; +}; + +void testTagMerge() { + consume_S1(produce_S1()); + struct S2 s2; + s2.field = 0; + consume_S2(produce_S2()); + struct S1 s1; + s1.s1_field = 0; + consume_S3(produce_S3()); + struct S4 s4; + s4.field = 0; + consume_S4(produce_S4()); + struct S3 s3; + s3.s3_field = 0; +} + // Test redeclarations of entities in explicit submodules, to make // sure we're maintaining the declaration chains even when normal name // lookup can't see what we're looking for.