Apply attributes to explicit specializations.  Specializations which
don't provide their own explicit visibility attributes should get them
from the template.  Fixes rdar://problem/8778497.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122136 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index f40907c..fe3dbeb 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -33,21 +33,41 @@
 // NamedDecl Implementation
 //===----------------------------------------------------------------------===//
 
-static const VisibilityAttr *GetExplicitVisibility(const Decl *D) {
-  // If the decl is redeclarable, make sure we use the explicit
-  // visibility attribute from the most recent declaration.
-  //
-  // Note that this isn't necessary for tags, which can't have their
-  // visibility adjusted.
-  if (isa<VarDecl>(D)) {
-    return cast<VarDecl>(D)->getMostRecentDeclaration()
-      ->getAttr<VisibilityAttr>();
-  } else if (isa<FunctionDecl>(D)) {
-    return cast<FunctionDecl>(D)->getMostRecentDeclaration()
-      ->getAttr<VisibilityAttr>();
-  } else {
-    return D->getAttr<VisibilityAttr>();
+static const VisibilityAttr *GetExplicitVisibility(const Decl *d) {
+  // Use the most recent declaration of a variable.
+  if (const VarDecl *var = dyn_cast<VarDecl>(d))
+    return var->getMostRecentDeclaration()->getAttr<VisibilityAttr>();
+
+  // Use the most recent declaration of a function, and also handle
+  // function template specializations.
+  if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(d)) {
+    if (const VisibilityAttr *attr
+          = fn->getMostRecentDeclaration()->getAttr<VisibilityAttr>())
+      return attr;
+
+    // If the function is a specialization of a template with an
+    // explicit visibility attribute, use that.
+    if (FunctionTemplateSpecializationInfo *templateInfo
+          = fn->getTemplateSpecializationInfo())
+      return templateInfo->getTemplate()->getTemplatedDecl()
+        ->getAttr<VisibilityAttr>();
+
+    return 0;
   }
+
+  // Otherwise, just check the declaration itself first.
+  if (const VisibilityAttr *attr = d->getAttr<VisibilityAttr>())
+    return attr;
+
+  // If there wasn't explicit visibility there, and this is a
+  // specialization of a class template, check for visibility
+  // on the pattern.
+  if (const ClassTemplateSpecializationDecl *spec
+        = dyn_cast<ClassTemplateSpecializationDecl>(d))
+    return spec->getSpecializedTemplate()->getTemplatedDecl()
+      ->getAttr<VisibilityAttr>();
+
+  return 0;
 }
 
 static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) {
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5df84d6..5819362 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4343,6 +4343,9 @@
     }
   }
 
+  if (Attr)
+    ProcessDeclAttributeList(S, Specialization, Attr);
+
   // Build the fully-sugared type for this class template
   // specialization as the user wrote in the specialization
   // itself. This means that we'll pretty-print the type retrieved
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index 8d23da0..431cee3 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -356,3 +356,58 @@
     foo<int>();
   }
 }
+
+// Various things with class template specializations.
+namespace Test20 {
+  template <unsigned> struct HIDDEN A {};
+
+  // An explicit specialization inherits the explicit visibility of
+  // the template.
+  template <> struct A<0> {
+    static void test0();
+    static void test1();
+  };
+
+  // CHECK: define hidden void @_ZN6Test201AILj0EE5test0Ev()
+  void A<0>::test0() {}
+
+  // CHECK: declare hidden void @_ZN6Test201AILj0EE5test1Ev()
+  void test1() {
+    A<0>::test1();
+  }
+
+  // ...unless that's explicitly overridden.
+  template <> struct DEFAULT A<1> {
+    static void test2();
+    static void test3();
+  };
+
+  // CHECK: define void @_ZN6Test201AILj1EE5test2Ev()
+  void A<1>::test2() {}
+
+  // CHECK: declare void @_ZN6Test201AILj1EE5test3Ev()
+  void test3() {
+    A<1>::test3();
+  }
+
+  // <rdar://problem/8778497>
+  // But we should assume that an unknown specialization has the
+  // explicit visibility settings of the template.
+  template <class T> struct B {
+    static void test4() {}
+    static void test5();
+  };
+
+  // CHECK: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev()
+  void test4() {
+    B<A<2> >::test4();
+  }
+
+  // CHECK: declare void @_ZN6Test201BINS_1AILj2EEEE5test4Ev()
+  // (but explicit visibility on a template argument doesn't count as
+  //  explicit visibility for the template for purposes of deciding
+  //  whether an external symbol gets visibility)
+  void test5() {
+    B<A<2> >::test5();
+  }
+}