diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/Serialization/ASTReader.h | 5 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 73 | ||||
| -rw-r--r-- | clang/test/Modules/Inputs/cxx-decls-imported.h | 5 | ||||
| -rw-r--r-- | clang/test/Modules/Inputs/cxx-decls-merged.h | 6 | ||||
| -rw-r--r-- | clang/test/Modules/cxx-decls.cpp | 6 |
5 files changed, 88 insertions, 7 deletions
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 49faafbe49b..3738c37ae93 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/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<std::pair<DeclContext*, IdentifierInfo*>, NamedDecl*> + ImportedTypedefNamesForLinkage; + struct FileDeclsInfo { ModuleFile *Mod; ArrayRef<serialization::LocalDeclID> Decls; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 3e24145075e..3ac67071f0d 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/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<TagDecl>(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<TypedefNameDecl>(Found)) { + if (auto *TT = TND->getTypeSourceInfo()->getType()->getAs<TagType>()) + 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/clang/test/Modules/Inputs/cxx-decls-imported.h b/clang/test/Modules/Inputs/cxx-decls-imported.h index 38cc00d863f..a30db940a19 100644 --- a/clang/test/Modules/Inputs/cxx-decls-imported.h +++ b/clang/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/clang/test/Modules/Inputs/cxx-decls-merged.h b/clang/test/Modules/Inputs/cxx-decls-merged.h index ccc3b015487..b1ed2a0d932 100644 --- a/clang/test/Modules/Inputs/cxx-decls-merged.h +++ b/clang/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/clang/test/Modules/cxx-decls.cpp b/clang/test/Modules/cxx-decls.cpp index 5498b47fc9f..678f245ed10 100644 --- a/clang/test/Modules/cxx-decls.cpp +++ b/clang/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 |

