Two fixes to how we compute visibility:

* Handle some situations where we should never make a decl more visible,
  even when merging in an explicit visibility.

* Handle attributes in members of classes that are explicitly specialized.

Thanks Nico for the report and testing, Eric for the initial review, and dgregor
for the awesome test27 :-)

llvm-svn: 151236
diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp
index 67ac098..961b508 100644
--- a/clang/test/CodeGenCXX/visibility.cpp
+++ b/clang/test/CodeGenCXX/visibility.cpp
@@ -5,6 +5,21 @@
 #define PROTECTED __attribute__((visibility("protected")))
 #define DEFAULT __attribute__((visibility("default")))
 
+namespace test25 {
+  template<typename T>
+  struct X {
+    template<typename U>
+    struct definition {
+    };
+  };
+
+  class DEFAULT A { };
+
+  X<int>::definition<A> a;
+  // CHECK: @_ZN6test251aE = global
+  // CHECK-HIDDEN: @_ZN6test251aE = hidden global
+}
+
 // CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10
 // CHECK: @_ZN5Test71aE = hidden global
 // CHECK: @_ZN5Test71bE = global
@@ -22,6 +37,26 @@
 // CHECK-HIDDEN: @_ZN6Test143varE = external global
 // CHECK: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
 // CHECK-HIDDEN: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
+
+namespace test27 {
+  template<typename T>
+  class C {
+    class __attribute__((visibility("default"))) D {
+      void f();
+    };
+  };
+
+  template<>
+  class C<int>::D {
+    virtual void g();
+  };
+
+  void C<int>::D::g() {
+  }
+  // CHECK: _ZTVN6test271CIiE1DE = unnamed_addr constant
+  // CHECK-HIDDEN: _ZTVN6test271CIiE1DE = unnamed_addr constant
+}
+
 // CHECK: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr global
 // CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64
 // CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global
@@ -500,3 +535,65 @@
   // CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
   // CHECK-HIDDEN: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
 }
+
+namespace test23 {
+  // Having a template argument that is explicitly visible should not make
+  // the template instantiation visible.
+  template <typename T>
+  struct X {
+    static void f() {
+    }
+  };
+
+  class DEFAULT A;
+
+  void g() {
+    X<A> y;
+    y.f();
+  }
+  // CHECK: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv
+  // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv
+}
+
+namespace PR12001 {
+  template <typename P1>
+  void Bind(const P1& p1) {
+  }
+
+  class DEFAULT Version { };
+
+  void f() {
+    Bind(Version());
+  }
+  // CHECK: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+  // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+}
+
+namespace test24 {
+  class DEFAULT A { };
+
+  struct S {
+    template <typename T>
+    void mem() {}
+  };
+
+  void test() {
+    S s;
+    s.mem<A>();
+  }
+  // CHECK: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv
+  // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv
+}
+
+namespace test26 {
+  template<typename T>
+  class C {
+    __attribute__((visibility("default")))  void f();
+  };
+
+  template<>
+  void C<int>::f() { }
+
+  // CHECK: define void @_ZN6test261CIiE1fEv
+  // CHECK-HIDDEN: define void @_ZN6test261CIiE1fEv
+}