r233345 - [modules] Handle defining a tag with a typedef name for linkage purposes on top of an existing imported-but-not-visible definition.
Richard Smith
richard-llvm at metafoo.co.uk
Thu Mar 26 18:37:43 PDT 2015
Author: rsmith
Date: Thu Mar 26 20:37:43 2015
New Revision: 233345
URL: http://llvm.org/viewvc/llvm-project?rev=233345&view=rev
Log:
[modules] Handle defining a tag with a typedef name for linkage purposes on top of an existing imported-but-not-visible definition.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h
cfe/trunk/test/Modules/submodules-merge-defs.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=233345&r1=233344&r2=233345&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Mar 26 20:37:43 2015
@@ -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) {
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=233345&r1=233344&r2=233345&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Mar 26 20:37:43 2015
@@ -3919,6 +3919,14 @@ TypedefDecl *TypedefDecl::Create(ASTCont
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);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=233345&r1=233344&r2=233345&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Mar 26 20:37:43 2015
@@ -1836,11 +1836,18 @@ static void filterNonConflictingPrevious
// 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(TypedefN
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(TypedefN
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
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=233345&r1=233344&r2=233345&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu Mar 26 20:37:43 2015
@@ -2652,12 +2652,11 @@ static NamedDecl *getDeclForMerging(Name
// 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;
}
Modified: cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h?rev=233345&r1=233344&r2=233345&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h (original)
+++ cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h Thu Mar 26 20:37:43 2015
@@ -14,3 +14,7 @@ template<int N> struct C_Base { struct D
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; } }
Modified: cfe/trunk/test/Modules/submodules-merge-defs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/submodules-merge-defs.cpp?rev=233345&r1=233344&r2=233345&view=diff
==============================================================================
--- cfe/trunk/test/Modules/submodules-merge-defs.cpp (original)
+++ cfe/trunk/test/Modules/submodules-merge-defs.cpp Thu Mar 26 20:37:43 2015
@@ -18,6 +18,10 @@ C1 pre_c1; // expected-error +{{must be
C2 pre_c2; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
// expected-note at defs.h:16 +{{here}}
+D::X pre_dx; // expected-error +{{must be imported}}
+// expected-note at defs.h:18 +{{here}}
+// expected-note at 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;
More information about the cfe-commits
mailing list