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