loladiro created this revision.
loladiro added reviewers: aaron.ballman, rsmith, rnk.
loladiro added a subscriber: cfe-commits.
loladiro set the repository for this revision to rL LLVM.

When we were looking at a template instantiation, that itself was a template 
instantiation
(say a templated member of a templated class), we weren't looking back far 
enough along
the chain of instantiations to find a VisibilityAttr (which we don't copy when 
instantiating
templates). This patch attempts to address that as well as adding a few test 
cases for these
situations.

Repository:
  rL LLVM

http://reviews.llvm.org/D13419

Files:
  lib/AST/Decl.cpp
  lib/AST/DeclCXX.cpp
  test/CodeGenCXX/visibility.cpp

Index: test/CodeGenCXX/visibility.cpp
===================================================================
--- test/CodeGenCXX/visibility.cpp
+++ test/CodeGenCXX/visibility.cpp
@@ -1314,3 +1314,57 @@
   // CHECK-LABEL: define void @_ZN6test693foo1fEv
   // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv
 }
+
+namespace test70 {
+  template < typename T > class foo {
+  public:
+      T x;
+      template < typename S >
+      HIDDEN S AddS(S);
+      template < typename S > class HIDDEN barS {
+    public:
+          static S AddS2(foo<T> x, S);
+      };
+      template < typename S > class HIDDEN barZ {
+          public:
+    template < typename Z >
+          static S AddSZ(foo<T> x, S, Z);
+      };
+  };
+
+  // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4AddSIxEET_S3_
+  // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4AddSIxEET_S3_
+  template < typename T >
+  template < typename S >
+  HIDDEN S foo<T>::AddS(S y) {
+      return ((S) x) + y;
+  }
+
+  // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x
+  // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x
+  template < typename T >
+  template < typename S >
+  HIDDEN S foo<T>::barS<S>::AddS2(foo<T> x, S y) {
+      return ((S) x.x) + y;
+  }
+
+  // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_
+  // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_
+  template < typename T >
+  template < typename S >
+  template < typename Z >
+  HIDDEN S foo<T>::barZ<S>::AddSZ(foo<T> x, S y, Z z) {
+      return ((S) x.x) + y + ((S) z);
+  }
+
+  extern template struct foo<int>;
+  template struct foo<int>;
+
+  void f() {
+      auto var = foo<int>{5};
+      auto bar = var.AddS((long long)3);
+      auto bar2 = decltype(var)::barS<long long>::AddS2(var,3);
+      auto bar3 = decltype(var)::barZ<long long>::AddSZ(var,3,(char)0);
+  }
+}
+
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -1261,20 +1261,22 @@
   if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
     auto From = TD->getInstantiatedFrom();
     if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
-      while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
+      auto *NewCTD = CTD;
+      do {
+        CTD = NewCTD;
         if (NewCTD->isMemberSpecialization())
           break;
-        CTD = NewCTD;
-      }
+      } while ((NewCTD = CTD->getInstantiatedFromMemberTemplate()));
       return CTD->getTemplatedDecl()->getDefinition();
     }
     if (auto *CTPSD =
             From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
+      auto *NewCTPSD = CTPSD;
+      do {
+        CTPSD = NewCTPSD;
         if (NewCTPSD->isMemberSpecialization())
           break;
-        CTPSD = NewCTPSD;
-      }
+      } while ((NewCTPSD = CTPSD->getInstantiatedFromMember()));
       return CTPSD->getDefinition();
     }
   }
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1049,7 +1049,9 @@
   // If this is a member class of a specialization of a class template
   // and the corresponding decl has explicit visibility, use that.
   if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) {
-    CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
+    const CXXRecordDecl *InstantiatedFrom = RD->getTemplateInstantiationPattern();
+    if (!InstantiatedFrom)
+      InstantiatedFrom = RD->getInstantiatedFromMemberClass();
     if (InstantiatedFrom)
       return getVisibilityOf(InstantiatedFrom, kind);
   }
@@ -1084,16 +1086,11 @@
   }
   // Also handle function template specializations.
   if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) {
-    // If the function is a specialization of a template with an
-    // explicit visibility attribute, use that.
-    if (FunctionTemplateSpecializationInfo *templateInfo
-          = fn->getTemplateSpecializationInfo())
-      return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(),
-                             kind);
-
-    // If the function is a member of a specialization of a class template
+    // If the function is a member of a specialization of a some template
     // and the corresponding decl has explicit visibility, use that.
-    FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
+    FunctionDecl *InstantiatedFrom = fn->getTemplateInstantiationPattern();
+    if (!InstantiatedFrom)
+      InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
     if (InstantiatedFrom)
       return getVisibilityOf(InstantiatedFrom, kind);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to