[CXX] Templates specialization visibility can be wrong

Summary:
Under some conditions, LinkageComputer can get the visibility for
ClassTemplateSpecializationDecl wrong because it failed to find the Decl
that has the explicit visibility.

This fixes:
llvm.org/bugs/pr36810
rdar://problem/38080953

Reviewers: rsmith, arphaman, doug.gregor

Reviewed By: doug.gregor

Subscribers: doug.gregor, cfe-commits

Differential Revision: https://reviews.llvm.org/D44670

llvm-svn: 330338
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 18ef94b..3b4507d 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1092,9 +1092,18 @@
   // If there wasn't explicit visibility there, and this is a
   // specialization of a class template, check for visibility
   // on the pattern.
-  if (const auto *spec = dyn_cast<ClassTemplateSpecializationDecl>(ND))
-    return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
-                           kind);
+  if (const auto *spec = dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+    // Walk all the template decl till this point to see if there are
+    // explicit visibility attributes.
+    const auto *TD = spec->getSpecializedTemplate()->getTemplatedDecl();
+    while (TD != nullptr) {
+      auto Vis = getVisibilityOf(TD, kind);
+      if (Vis != None)
+        return Vis;
+      TD = TD->getPreviousDecl();
+    }
+    return None;
+  }
 
   // Use the most recent declaration.
   if (!IsMostRecent && !isa<NamespaceDecl>(ND)) {