From: John McCall Date: Sat, 18 Dec 2010 03:30:47 +0000 (+0000) Subject: Apply attributes to explicit specializations. Specializations which X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7f1b98760d419a09b2261c1ef901f6bc1ff33e19;p=clang 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 --- 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(D)) { - return cast(D)->getMostRecentDeclaration() - ->getAttr(); - } else if (isa(D)) { - return cast(D)->getMostRecentDeclaration() - ->getAttr(); - } else { - return D->getAttr(); +static const VisibilityAttr *GetExplicitVisibility(const Decl *d) { + // Use the most recent declaration of a variable. + if (const VarDecl *var = dyn_cast(d)) + return var->getMostRecentDeclaration()->getAttr(); + + // Use the most recent declaration of a function, and also handle + // function template specializations. + if (const FunctionDecl *fn = dyn_cast(d)) { + if (const VisibilityAttr *attr + = fn->getMostRecentDeclaration()->getAttr()) + 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(); + + return 0; } + + // Otherwise, just check the declaration itself first. + if (const VisibilityAttr *attr = d->getAttr()) + 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(d)) + return spec->getSpecializedTemplate()->getTemplatedDecl() + ->getAttr(); + + 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(); } } + +// Various things with class template specializations. +namespace Test20 { + template 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(); + } + + // + // But we should assume that an unknown specialization has the + // explicit visibility settings of the template. + template struct B { + static void test4() {} + static void test5(); + }; + + // CHECK: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev() + void test4() { + B >::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 >::test5(); + } +}