forked from OSchip/llvm-project
[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:
parent
c9ee4de6ca
commit
a523022b53
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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; } }
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue