From: Richard Smith Date: Sat, 23 Aug 2014 01:45:27 +0000 (+0000) Subject: [modules] When merging a tag declaration that has a typedef name for linkage X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=63f1f83277156100b2eabf44ac0de16f037854d9;p=clang [modules] When merging a tag declaration that has a typedef name for linkage purposes, look for other typedefs with that same name and merge into their named tag declaration if there is one. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216312 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 49faafbe49..3738c37ae9 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -438,6 +438,11 @@ private: /// \brief Declarations that have been replaced in a later file in the chain. DeclReplacementMap ReplacedDecls; + /// \brief Declarations that have been imported and have typedef names for + /// linkage purposes. + llvm::DenseMap, NamedDecl*> + ImportedTypedefNamesForLinkage; + struct FileDeclsInfo { ModuleFile *Mod; ArrayRef Decls; diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 3e24145075..3ac67071f0 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -2412,13 +2412,38 @@ static DeclContext *getPrimaryContextForMerging(DeclContext *DC) { return nullptr; } +static DeclarationName +getNameForMerging(NamedDecl *D, bool &IsTypedefNameForLinkage) { + DeclarationName Name = D->getDeclName(); + + if (!Name) { + // If this declaration has a typedef name for linkage purposes, + // look that name up when merging. We may be able to find another + // typedef that names a matching TagDecl. + if (auto *TD = dyn_cast(D)) { + if (auto *Typedef = TD->getTypedefNameForAnonDecl()) { + Name = Typedef->getDeclName(); + IsTypedefNameForLinkage = true; + } + } + } + + return Name; +} + ASTDeclReader::FindExistingResult::~FindExistingResult() { if (!AddResult || Existing) return; + bool IsTypedefNameForLinkage = false; + DeclarationName Name = getNameForMerging(New, IsTypedefNameForLinkage); + DeclContext *DC = New->getDeclContext()->getRedeclContext(); - if (DC->isTranslationUnit() && Reader.SemaObj) { - Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName()); + if (IsTypedefNameForLinkage) { + Reader.ImportedTypedefNamesForLinkage.insert( + std::make_pair(std::make_pair(DC, Name.getAsIdentifierInfo()), New)); + } else if (DC->isTranslationUnit() && Reader.SemaObj) { + Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name); } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) { // Add the declaration to its redeclaration context so later merging // lookups will find it. @@ -2426,8 +2451,31 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() { } } +/// Find the declaration that should be merged into, given the declaration found +/// by name lookup. If we're merging an anonymous declaration within a typedef, +/// we need a matching typedef, and we merge with the type inside it. +static NamedDecl *getDeclForMerging(NamedDecl *Found, + bool IsTypedefNameForLinkage) { + if (!IsTypedefNameForLinkage) + return Found; + + // If we found a typedef declaration that gives a name to some other + // declaration, then we want that inner declaration. Declarations from + // AST files are handled via ImportedTypedefNamesForLinkage. + if (Found->isFromASTFile()) return 0; + if (auto *TND = dyn_cast(Found)) { + if (auto *TT = TND->getTypeSourceInfo()->getType()->getAs()) + if (TT->getDecl()->getTypedefNameForAnonDecl() == TND) + return TT->getDecl(); + } + + return 0; +} + ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { - DeclarationName Name = D->getDeclName(); + bool IsTypedefNameForLinkage = false; + DeclarationName Name = getNameForMerging(D, IsTypedefNameForLinkage); + if (!Name) { // Don't bother trying to find unnamed declarations. FindExistingResult Result(Reader, D, /*Existing=*/nullptr); @@ -2441,6 +2489,15 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { // necessary merging already. DeclContext *DC = D->getDeclContext()->getRedeclContext(); + if (IsTypedefNameForLinkage) { + auto It = Reader.ImportedTypedefNamesForLinkage.find( + std::make_pair(DC, Name.getAsIdentifierInfo())); + if (It != Reader.ImportedTypedefNamesForLinkage.end()) + if (isSameEntity(It->second, D)) + return FindExistingResult(Reader, D, It->second); + // Go on to check in other places in case an existing typedef name + // was not imported. + } if (DC->isTranslationUnit() && Reader.SemaObj) { IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver; @@ -2470,14 +2527,16 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { for (IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); I != IEnd; ++I) { - if (isSameEntity(*I, D)) - return FindExistingResult(Reader, D, *I); + if (NamedDecl *Existing = getDeclForMerging(*I, IsTypedefNameForLinkage)) + if (isSameEntity(*I, D)) + return FindExistingResult(Reader, D, Existing); } } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) { DeclContext::lookup_result R = MergeDC->noload_lookup(Name); for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) { - if (isSameEntity(*I, D)) - return FindExistingResult(Reader, D, *I); + if (NamedDecl *Existing = getDeclForMerging(*I, IsTypedefNameForLinkage)) + if (isSameEntity(Existing, D)) + return FindExistingResult(Reader, D, Existing); } } else { // Not in a mergeable context. diff --git a/test/Modules/Inputs/cxx-decls-imported.h b/test/Modules/Inputs/cxx-decls-imported.h index 38cc00d863..a30db940a1 100644 --- a/test/Modules/Inputs/cxx-decls-imported.h +++ b/test/Modules/Inputs/cxx-decls-imported.h @@ -23,3 +23,8 @@ void *operator new[](__SIZE_TYPE__); extern int mergeUsedFlag; inline int getMergeUsedFlag() { return mergeUsedFlag; } + +typedef struct { + int n; + int m; +} NameForLinkage; diff --git a/test/Modules/Inputs/cxx-decls-merged.h b/test/Modules/Inputs/cxx-decls-merged.h index ccc3b01548..b1ed2a0d93 100644 --- a/test/Modules/Inputs/cxx-decls-merged.h +++ b/test/Modules/Inputs/cxx-decls-merged.h @@ -1 +1,7 @@ extern int mergeUsedFlag; + +typedef struct { + int n; + int m; +} NameForLinkage; +extern NameForLinkage name_for_linkage; diff --git a/test/Modules/cxx-decls.cpp b/test/Modules/cxx-decls.cpp index 5498b47fc9..678f245ed1 100644 --- a/test/Modules/cxx-decls.cpp +++ b/test/Modules/cxx-decls.cpp @@ -30,7 +30,13 @@ void use_implicit_new_again() { operator new[](3); } int importMergeUsedFlag = getMergeUsedFlag(); +int use_name_for_linkage(NameForLinkage &nfl) { + return nfl.n + nfl.m; +} + @import cxx_decls_merged; +int name_for_linkage_test = use_name_for_linkage(name_for_linkage); + // CHECK: VarDecl [[mergeUsedFlag:0x[0-9a-f]*]] {{.*}} in cxx_decls.imported used mergeUsedFlag // CHECK: VarDecl {{0x[0-9a-f]*}} prev [[mergeUsedFlag]] {{.*}} in cxx_decls_merged used mergeUsedFlag