diff options
author | John McCall <rjmccall@apple.com> | 2010-12-18 03:30:47 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-12-18 03:30:47 +0000 |
commit | 7f1b98760d419a09b2261c1ef901f6bc1ff33e19 (patch) | |
tree | d3968efbcb1e3af57942e336b9634200ff838ddd | |
parent | 472ccff00cdbcd095c3ba933b9e3f202719f118f (diff) |
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
-rw-r--r-- | lib/AST/Decl.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 3 | ||||
-rw-r--r-- | test/CodeGenCXX/visibility.cpp | 55 |
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(); + } +} |