From a523022b5384d7a0901beea7a5f36ee9c09ba339 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 27 Mar 2015 01:37:43 +0000 Subject: [PATCH] [modules] Handle defining a tag with a typedef name for linkage purposes on top of an existing imported-but-not-visible definition. llvm-svn: 233345 --- clang/include/clang/AST/Decl.h | 4 +++ clang/lib/AST/Decl.cpp | 8 +++++ clang/lib/Sema/SemaDecl.cpp | 33 +++++++++++++++++-- clang/lib/Serialization/ASTReaderDecl.cpp | 11 +++---- .../Inputs/submodules-merge-defs/defs.h | 4 +++ clang/test/Modules/submodules-merge-defs.cpp | 5 +++ 6 files changed, 57 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 7f7e437b736f..3e3d79ff29ef 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2579,6 +2579,10 @@ public: TypedefNameDecl *getCanonicalDecl() override { return getFirstDecl(); } const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); } + /// Retrieves the tag declaration for which this is the typedef name for + /// linkage purposes, if any. + TagDecl *getAnonDeclWithTypedefName() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 349877280c69..ba6fd2e103c5 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3919,6 +3919,14 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, void TypedefNameDecl::anchor() { } +TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName() const { + if (auto *TT = getTypeSourceInfo()->getType()->getAs()) + if (TT->getDecl()->getTypedefNameForAnonDecl() == this) + return TT->getDecl(); + + return nullptr; +} + TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e9c40aa2e5d3..9bbfeaf19eff 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1836,11 +1836,18 @@ static void filterNonConflictingPreviousTypedefDecls(ASTContext &Context, // Declarations of the same entity are not ignored, even if they have // different linkages. - if (auto *OldTD = dyn_cast(Old)) + if (auto *OldTD = dyn_cast(Old)) { if (Context.hasSameType(OldTD->getUnderlyingType(), Decl->getUnderlyingType())) continue; + // If both declarations give a tag declaration a typedef name for linkage + // purposes, then they declare the same entity. + if (OldTD->getAnonDeclWithTypedefName() && + Decl->getAnonDeclWithTypedefName()) + continue; + } + if (!Old->isExternallyVisible()) Filter.erase(); } @@ -1950,6 +1957,29 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { if (Old->isInvalidDecl()) return New->setInvalidDecl(); + if (auto *OldTD = dyn_cast(Old)) { + auto *OldTag = OldTD->getAnonDeclWithTypedefName(); + auto *NewTag = New->getAnonDeclWithTypedefName(); + NamedDecl *Hidden = nullptr; + if (getLangOpts().CPlusPlus && OldTag && NewTag && + OldTag->getCanonicalDecl() != NewTag->getCanonicalDecl() && + !hasVisibleDefinition(OldTag, &Hidden)) { + // There is a definition of this tag, but it is not visible. Use it + // instead of our tag. + New->setTypeForDecl(OldTD->getTypeForDecl()); + if (OldTD->isModed()) + New->setModedTypeSourceInfo(OldTD->getTypeSourceInfo(), + OldTD->getUnderlyingType()); + else + New->setTypeSourceInfo(OldTD->getTypeSourceInfo()); + + // Make the old tag definition visible. + if (auto *Listener = getASTMutationListener()) + Listener->RedefinedHiddenDefinition(Hidden, NewTag->getLocation()); + Hidden->setHidden(false); + } + } + // If the typedef types are not identical, reject them in all languages and // with any extensions enabled. if (isIncompatibleTypedef(Old, New)) @@ -2019,7 +2049,6 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { Diag(New->getLocation(), diag::ext_redefinition_of_typedef) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); - return; } /// DeclhasAttr - returns true if decl Declaration already has the target diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 3499c8ea488d..de2c62530692 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2652,12 +2652,11 @@ static NamedDecl *getDeclForMerging(NamedDecl *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(); - } + if (Found->isFromASTFile()) + return 0; + + if (auto *TND = dyn_cast(Found)) + return TND->getAnonDeclWithTypedefName(); return 0; } diff --git a/clang/test/Modules/Inputs/submodules-merge-defs/defs.h b/clang/test/Modules/Inputs/submodules-merge-defs/defs.h index dfb58adcbcd0..16f71840d0a1 100644 --- a/clang/test/Modules/Inputs/submodules-merge-defs/defs.h +++ b/clang/test/Modules/Inputs/submodules-merge-defs/defs.h @@ -14,3 +14,7 @@ template struct C_Base { struct D { constexpr operator int() const { retu const int C_Const = 0; struct C1 : C_Base::D{}> {} extern c1; struct C2 : C_Base::D{} extern c2; + +typedef struct { int a; void f(); struct X; } D; +struct D::X { int dx; } extern dx; +namespace { inline int use_dx(D::X dx) { return dx.dx; } } diff --git a/clang/test/Modules/submodules-merge-defs.cpp b/clang/test/Modules/submodules-merge-defs.cpp index 9b5b13d63fc1..cdda48ea6521 100644 --- a/clang/test/Modules/submodules-merge-defs.cpp +++ b/clang/test/Modules/submodules-merge-defs.cpp @@ -18,6 +18,10 @@ C1 pre_c1; // expected-error +{{must be imported}} expected-error {{must use 'st C2 pre_c2; // expected-error +{{must be imported}} expected-error {{must use 'struct'}} // expected-note@defs.h:16 +{{here}} +D::X pre_dx; // expected-error +{{must be imported}} +// expected-note@defs.h:18 +{{here}} +// expected-note@defs.h:19 +{{here}} + // Make definitions from second module visible. #include "import-and-redefine.h" @@ -26,3 +30,4 @@ B::Inner2 post_bi; C_Base<1> post_cb1; C1 c1; C2 c2; +D::X post_dx;