diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index f50d774..4b109ac 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -419,6 +419,10 @@ public:
     return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1);
   }
 
+  bool isExplicitSpecialization() const {
+    return getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+  }
+
   /// \brief Set the template specialization kind.
   void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
     assert(TSK != TSK_Undeclared &&
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 3124261..c7406c8 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -183,6 +183,14 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
   return None;
 }
 
+static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
+                                            LVComputationKind kind) {
+  assert(!hasExplicitVisibilityAlready(kind) &&
+         "asking for explicit visibility when we shouldn't be");
+  return getVisibilityOf(D, (NamedDecl::ExplicitVisibilityKind) kind);
+}
+
+
 static LinkageInfo getLVForType(QualType T) {
   std::pair<Linkage,Visibility> P = T->getLinkageAndVisibility();
   return LinkageInfo(P.first, P.second, T->isVisibilityExplicit());
@@ -684,6 +692,17 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
   return LV;
 }
 
+static MemberSpecializationInfo *
+getMemberSpecializationInfo(const NamedDecl *D) {
+  if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+    return VD->getMemberSpecializationInfo();
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+    return FD->getMemberSpecializationInfo();
+  if (const EnumDecl *ED = dyn_cast<EnumDecl>(D))
+    return ED->getMemberSpecializationInfo();
+  return NULL;
+}
+
 static LinkageInfo getLVForClassMember(const NamedDecl *D,
                                        LVComputationKind computation) {
   // Only certain class members have linkage.  Note that fields don't
@@ -698,6 +717,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
 
   LinkageInfo LV;
 
+  bool isMemberSpecializationWithVis = false;
   // If we have an explicit visibility attribute, merge that in.
   if (!hasExplicitVisibilityAlready(computation)) {
     if (Optional<Visibility> Vis = getExplicitVisibility(D, computation))
@@ -709,22 +729,27 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
     // the class visibility.
     if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D))
       LV.mergeVisibility(HiddenVisibility, true);
+
+    MemberSpecializationInfo *Info = getMemberSpecializationInfo(D);
+    isMemberSpecializationWithVis = Info &&
+      Info->isExplicitSpecialization() && getVisibilityOf(D, computation);
+  }
+
+  if (!isMemberSpecializationWithVis) {
+    // If this class member has an explicit visibility attribute, the only
+    // thing that can change its visibility is the template arguments, so
+    // only look for them when processing the class.
+    LVComputationKind classComputation = computation;
+    if (LV.visibilityExplicit())
+      classComputation = withExplicitVisibilityAlready(computation);
+
+    // If this member has an visibility attribute, classComputation will exclude
+    // attributes on the class or command line options, keeping only information
+    // about the template instantiation.
+    LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
+                          classComputation));
   }
 
-  // If this class member has an explicit visibility attribute, the only
-  // thing that can change its visibility is the template arguments, so
-  // only look for them when processing the class.
-  LVComputationKind classComputation = computation;
-  if (LV.visibilityExplicit())
-    classComputation = withExplicitVisibilityAlready(computation);
-
-  // If this member has an visibility attribute, ClassF will exclude
-  // attributes on the class or command line options, keeping only information
-  // about the template instantiation. If the member has no visibility
-  // attributes, mergeWithMin behaves like merge, so in both cases mergeWithMin
-  // produces the desired result.
-  LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
-                        classComputation));
   if (!isExternalLinkage(LV.linkage()))
     return LinkageInfo::none();
 
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index cfddc8c..acbbd26 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -1182,3 +1182,38 @@ namespace test64 {
   template class B<A>;
   // CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
 }
+
+namespace test65 {
+  class foo {
+  };
+  template<typename T>
+  class bar {
+    void g();
+  };
+  template<>
+  __attribute__((visibility("default"))) void bar<foo>::g();
+
+  template<>
+  void bar<foo>::g() {
+  }
+
+  // CHECK: define void @_ZN6test653barINS_3fooEE1gEv
+  // CHECK-HIDDEN: define void @_ZN6test653barINS_3fooEE1gEv
+}
+
+namespace test66 {
+  class foo {
+  };
+  template<typename T>
+  class bar {
+    __attribute__((visibility("default"))) void g();
+  };
+  template<>
+  void bar<foo>::g();
+
+  template<>
+  void bar<foo>::g() {
+  }
+  // CHECK: define void @_ZN6test663barINS_3fooEE1gEv
+  // CHECK-HIDDEN: define hidden void @_ZN6test663barINS_3fooEE1gEv
+}
