aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/Decl.cpp48
-rw-r--r--lib/Sema/SemaTemplate.cpp3
-rw-r--r--test/CodeGenCXX/visibility.cpp55
3 files changed, 92 insertions, 14 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index f40907cb73..fe3dbebc1f 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -33,21 +33,41 @@ using namespace clang;
// 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 5df84d66a4..5819362e76 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4343,6 +4343,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
}
+ 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 8d23da0a37..431cee303e 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -356,3 +356,58 @@ namespace Test19 {
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();
+ }
+}