[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
This commit is contained in:
Richard Smith 2015-03-27 01:37:43 +00:00
parent c9ee4de6ca
commit a523022b53
6 changed files with 57 additions and 8 deletions

View File

@ -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) {

View File

@ -3919,6 +3919,14 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
void TypedefNameDecl::anchor() { }
TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName() const {
if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>())
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);

View File

@ -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<TypedefNameDecl>(Old))
if (auto *OldTD = dyn_cast<TypedefNameDecl>(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<TypedefNameDecl>(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

View File

@ -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<TypedefNameDecl>(Found)) {
if (auto *TT = TND->getTypeSourceInfo()->getType()->getAs<TagType>())
if (TT->getDecl()->getTypedefNameForAnonDecl() == TND)
return TT->getDecl();
}
if (Found->isFromASTFile())
return 0;
if (auto *TND = dyn_cast<TypedefNameDecl>(Found))
return TND->getAnonDeclWithTypedefName();
return 0;
}

View File

@ -14,3 +14,7 @@ template<int N> struct C_Base { struct D { constexpr operator int() const { retu
const int C_Const = 0;
struct C1 : C_Base<C_Base<0>::D{}> {} extern c1;
struct C2 : C_Base<C_Const<0>::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; } }

View File

@ -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;