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. llvm-svn: 122136
This commit is contained in:
parent
1fa7958eaa
commit
659a337c74
|
@ -33,21 +33,41 @@ using namespace clang;
|
||||||
// NamedDecl Implementation
|
// NamedDecl Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
static const VisibilityAttr *GetExplicitVisibility(const Decl *D) {
|
static const VisibilityAttr *GetExplicitVisibility(const Decl *d) {
|
||||||
// If the decl is redeclarable, make sure we use the explicit
|
// Use the most recent declaration of a variable.
|
||||||
// visibility attribute from the most recent declaration.
|
if (const VarDecl *var = dyn_cast<VarDecl>(d))
|
||||||
//
|
return var->getMostRecentDeclaration()->getAttr<VisibilityAttr>();
|
||||||
// Note that this isn't necessary for tags, which can't have their
|
|
||||||
// visibility adjusted.
|
// Use the most recent declaration of a function, and also handle
|
||||||
if (isa<VarDecl>(D)) {
|
// function template specializations.
|
||||||
return cast<VarDecl>(D)->getMostRecentDeclaration()
|
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(d)) {
|
||||||
->getAttr<VisibilityAttr>();
|
if (const VisibilityAttr *attr
|
||||||
} else if (isa<FunctionDecl>(D)) {
|
= fn->getMostRecentDeclaration()->getAttr<VisibilityAttr>())
|
||||||
return cast<FunctionDecl>(D)->getMostRecentDeclaration()
|
return attr;
|
||||||
->getAttr<VisibilityAttr>();
|
|
||||||
} else {
|
// If the function is a specialization of a template with an
|
||||||
return D->getAttr<VisibilityAttr>();
|
// 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) {
|
static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) {
|
||||||
|
|
|
@ -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
|
// Build the fully-sugared type for this class template
|
||||||
// specialization as the user wrote in the specialization
|
// specialization as the user wrote in the specialization
|
||||||
// itself. This means that we'll pretty-print the type retrieved
|
// itself. This means that we'll pretty-print the type retrieved
|
||||||
|
|
|
@ -356,3 +356,58 @@ namespace Test19 {
|
||||||
foo<int>();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue