forked from OSchip/llvm-project
Ignore visibility from enclosing template arguments
for explicit member specializations. llvm-svn: 175827
This commit is contained in:
parent
b169f55961
commit
5f46c48514
|
@ -1919,7 +1919,9 @@ public:
|
|||
/// \brief If this function is an instantiation of a member function of a
|
||||
/// class template specialization, retrieves the member specialization
|
||||
/// information.
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const;
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const {
|
||||
return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
|
||||
}
|
||||
|
||||
/// \brief Specify that this record is an instantiation of the
|
||||
/// member function FD.
|
||||
|
|
|
@ -1253,7 +1253,9 @@ public:
|
|||
/// \brief If this class is an instantiation of a member class of a
|
||||
/// class template specialization, retrieves the member specialization
|
||||
/// information.
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const;
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const {
|
||||
return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
|
||||
}
|
||||
|
||||
/// \brief Specify that this record is an instantiation of the
|
||||
/// member class RD.
|
||||
|
|
|
@ -419,6 +419,10 @@ public:
|
|||
return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1);
|
||||
}
|
||||
|
||||
bool isExplicitSpecialization() const {
|
||||
return getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
|
||||
}
|
||||
|
||||
/// \brief Set the template specialization kind.
|
||||
void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
|
||||
assert(TSK != TSK_Undeclared &&
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace clang;
|
||||
|
@ -83,29 +84,37 @@ using namespace clang;
|
|||
// and 'matcher' is a type only matters when looking for attributes
|
||||
// and settings from the immediate context.
|
||||
|
||||
const unsigned IgnoreExplicitVisibilityBit = 2;
|
||||
|
||||
/// Kinds of LV computation. The linkage side of the computation is
|
||||
/// always the same, but different things can change how visibility is
|
||||
/// computed.
|
||||
enum LVComputationKind {
|
||||
/// Do a normal LV computation for, ultimately, a type.
|
||||
/// Do an LV computation for, ultimately, a type.
|
||||
/// Visibility may be restricted by type visibility settings and
|
||||
/// the visibility of template arguments.
|
||||
LVForType = NamedDecl::VisibilityForType,
|
||||
|
||||
/// Do a normal LV computation for, ultimately, a non-type declaration.
|
||||
/// Do an LV computation for, ultimately, a non-type declaration.
|
||||
/// Visibility may be restricted by value visibility settings and
|
||||
/// the visibility of template arguments.
|
||||
LVForValue = NamedDecl::VisibilityForValue,
|
||||
|
||||
/// Do a normal LV computation for, ultimately, a type that already
|
||||
/// has some sort of explicit visibility.
|
||||
LVForExplicitType,
|
||||
/// Do an LV computation for, ultimately, a type that already has
|
||||
/// some sort of explicit visibility. Visibility may only be
|
||||
/// restricted by the visibility of template arguments.
|
||||
LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit),
|
||||
|
||||
/// Do a normal LV computation for, ultimately, a non-type declaration
|
||||
/// that already has some sort of explicit visibility.
|
||||
LVForExplicitValue
|
||||
/// Do an LV computation for, ultimately, a non-type declaration
|
||||
/// that already has some sort of explicit visibility. Visibility
|
||||
/// may only be restricted by the visibility of template arguments.
|
||||
LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit)
|
||||
};
|
||||
|
||||
/// Does this computation kind permit us to consider additional
|
||||
/// visibility settings from attributes and the like?
|
||||
static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
|
||||
return ((unsigned(computation) & 2) != 0);
|
||||
return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0);
|
||||
}
|
||||
|
||||
/// Given an LVComputationKind, return one of the same type/value sort
|
||||
|
@ -113,7 +122,8 @@ static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
|
|||
static LVComputationKind
|
||||
withExplicitVisibilityAlready(LVComputationKind oldKind) {
|
||||
LVComputationKind newKind =
|
||||
static_cast<LVComputationKind>(unsigned(oldKind) | 2);
|
||||
static_cast<LVComputationKind>(unsigned(oldKind) |
|
||||
IgnoreExplicitVisibilityBit);
|
||||
assert(oldKind != LVForType || newKind == LVForExplicitType);
|
||||
assert(oldKind != LVForValue || newKind == LVForExplicitValue);
|
||||
assert(oldKind != LVForExplicitType || newKind == LVForExplicitType);
|
||||
|
@ -138,6 +148,26 @@ static bool usesTypeVisibility(const NamedDecl *D) {
|
|||
isa<ObjCInterfaceDecl>(D);
|
||||
}
|
||||
|
||||
/// Does the given declaration have member specialization information,
|
||||
/// and if so, is it an explicit specialization?
|
||||
template <class T> static typename
|
||||
llvm::enable_if_c<!llvm::is_base_of<RedeclarableTemplateDecl, T>::value,
|
||||
bool>::type
|
||||
isExplicitMemberSpecialization(const T *D) {
|
||||
if (const MemberSpecializationInfo *member =
|
||||
D->getMemberSpecializationInfo()) {
|
||||
return member->isExplicitSpecialization();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// For templates, this question is easier: a member template can't be
|
||||
/// explicitly instantiated, so there's a single bit indicating whether
|
||||
/// or not this is an explicit member specialization.
|
||||
static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) {
|
||||
return D->isMemberSpecialization();
|
||||
}
|
||||
|
||||
/// Given a visibility attribute, return the explicit visibility
|
||||
/// associated with it.
|
||||
template <class T>
|
||||
|
@ -304,23 +334,33 @@ getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
|
|||
return getLVForTemplateArgumentList(TArgs.asArray());
|
||||
}
|
||||
|
||||
static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
|
||||
const FunctionTemplateSpecializationInfo *specInfo) {
|
||||
// Include visibility from the template parameters and arguments
|
||||
// only if this is not an explicit instantiation or specialization
|
||||
// with direct explicit visibility. (Implicit instantiations won't
|
||||
// have a direct attribute.)
|
||||
if (!specInfo->isExplicitInstantiationOrSpecialization())
|
||||
return true;
|
||||
|
||||
return !fn->hasAttr<VisibilityAttr>();
|
||||
}
|
||||
|
||||
/// Merge in template-related linkage and visibility for the given
|
||||
/// function template specialization.
|
||||
///
|
||||
/// We don't need a computation kind here because we can assume
|
||||
/// LVForValue.
|
||||
static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
|
||||
const FunctionTemplateSpecializationInfo *specInfo) {
|
||||
bool hasExplicitVisibility = fn->hasAttr<VisibilityAttr>();
|
||||
FunctionTemplateDecl *temp = specInfo->getTemplate();
|
||||
|
||||
// Include visibility from the template parameters and arguments
|
||||
// only if this is not an explicit instantiation or specialization
|
||||
// with direct explicit visibility. (Implicit instantiations won't
|
||||
// have a direct attribute.)
|
||||
bool considerVisibility = !hasExplicitVisibility;
|
||||
///
|
||||
/// \return the computation to use for the parent
|
||||
static void
|
||||
mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
|
||||
const FunctionTemplateSpecializationInfo *specInfo) {
|
||||
bool considerVisibility =
|
||||
shouldConsiderTemplateVisibility(fn, specInfo);
|
||||
|
||||
// Merge information from the template parameters.
|
||||
FunctionTemplateDecl *temp = specInfo->getTemplate();
|
||||
LinkageInfo tempLV =
|
||||
getLVForTemplateParameterList(temp->getTemplateParameters());
|
||||
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
|
||||
|
@ -331,6 +371,25 @@ static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
|
|||
LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
|
||||
}
|
||||
|
||||
/// Does the given declaration have a direct visibility attribute
|
||||
/// that would match the given rules?
|
||||
static bool hasDirectVisibilityAttribute(const NamedDecl *D,
|
||||
LVComputationKind computation) {
|
||||
switch (computation) {
|
||||
case LVForType:
|
||||
case LVForExplicitType:
|
||||
if (D->hasAttr<TypeVisibilityAttr>())
|
||||
return true;
|
||||
// fallthrough
|
||||
case LVForValue:
|
||||
case LVForExplicitValue:
|
||||
if (D->hasAttr<VisibilityAttr>())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("bad visibility computation kind");
|
||||
}
|
||||
|
||||
/// Should we consider visibility associated with the template
|
||||
/// arguments and parameters of the given class template specialization?
|
||||
static bool shouldConsiderTemplateVisibility(
|
||||
|
@ -364,20 +423,7 @@ static bool shouldConsiderTemplateVisibility(
|
|||
hasExplicitVisibilityAlready(computation))
|
||||
return false;
|
||||
|
||||
// Otherwise, look to see if we have an attribute.
|
||||
switch (computation) {
|
||||
case LVForType:
|
||||
case LVForExplicitType:
|
||||
if (spec->hasAttr<TypeVisibilityAttr>())
|
||||
return false;
|
||||
// fallthrough
|
||||
case LVForValue:
|
||||
case LVForExplicitValue:
|
||||
if (spec->hasAttr<VisibilityAttr>())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("bad visibility computation kind");
|
||||
return !hasDirectVisibilityAttribute(spec, computation);
|
||||
}
|
||||
|
||||
/// Merge in template-related linkage and visibility for the given
|
||||
|
@ -620,8 +666,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
|
|||
Function->getType()->getLinkage() == UniqueExternalLinkage)
|
||||
return LinkageInfo::uniqueExternal();
|
||||
|
||||
// Consider LV from the template and the template arguments unless
|
||||
// this is an explicit specialization with a visibility attribute.
|
||||
// Consider LV from the template and the template arguments.
|
||||
// We're at file scope, so we do not need to worry about nested
|
||||
// specializations.
|
||||
if (FunctionTemplateSpecializationInfo *specInfo
|
||||
= Function->getTemplateSpecializationInfo()) {
|
||||
mergeTemplateLV(LV, Function, specInfo);
|
||||
|
@ -639,7 +686,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
|
|||
return LinkageInfo::none();
|
||||
|
||||
// If this is a class template specialization, consider the
|
||||
// linkage of the template and template arguments.
|
||||
// linkage of the template and template arguments. We're at file
|
||||
// scope, so we do not need to worry about nested specializations.
|
||||
if (const ClassTemplateSpecializationDecl *spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
|
||||
mergeTemplateLV(LV, spec, computation);
|
||||
|
@ -718,20 +766,21 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
|
|||
if (LV.visibilityExplicit())
|
||||
classComputation = withExplicitVisibilityAlready(computation);
|
||||
|
||||
// If this member has an visibility attribute, ClassF will exclude
|
||||
// attributes on the class or command line options, keeping only information
|
||||
// about the template instantiation. If the member has no visibility
|
||||
// attributes, mergeWithMin behaves like merge, so in both cases mergeWithMin
|
||||
// produces the desired result.
|
||||
LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
|
||||
classComputation));
|
||||
if (!isExternalLinkage(LV.linkage()))
|
||||
LinkageInfo classLV =
|
||||
getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
|
||||
if (!isExternalLinkage(classLV.linkage()))
|
||||
return LinkageInfo::none();
|
||||
|
||||
// If the class already has unique-external linkage, we can't improve.
|
||||
if (LV.linkage() == UniqueExternalLinkage)
|
||||
if (classLV.linkage() == UniqueExternalLinkage)
|
||||
return LinkageInfo::uniqueExternal();
|
||||
|
||||
// Otherwise, don't merge in classLV yet, because in certain cases
|
||||
// we need to completely ignore the visibility from it.
|
||||
|
||||
// Specifically, if this decl exists and has an explicit attribute.
|
||||
const NamedDecl *explicitSpecSuppressor = 0;
|
||||
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
|
||||
// If the type of the function uses a type with unique-external
|
||||
// linkage, it's not legally usable from outside this translation unit.
|
||||
|
@ -743,15 +792,29 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
|
|||
if (FunctionTemplateSpecializationInfo *spec
|
||||
= MD->getTemplateSpecializationInfo()) {
|
||||
mergeTemplateLV(LV, MD, spec);
|
||||
if (spec->isExplicitSpecialization()) {
|
||||
explicitSpecSuppressor = MD;
|
||||
} else if (isExplicitMemberSpecialization(spec->getTemplate())) {
|
||||
explicitSpecSuppressor = spec->getTemplate()->getTemplatedDecl();
|
||||
}
|
||||
} else if (isExplicitMemberSpecialization(MD)) {
|
||||
explicitSpecSuppressor = MD;
|
||||
}
|
||||
|
||||
// Note that in contrast to basically every other situation, we
|
||||
// *do* apply -fvisibility to method declarations.
|
||||
|
||||
} else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
|
||||
if (const ClassTemplateSpecializationDecl *spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
|
||||
mergeTemplateLV(LV, spec, computation);
|
||||
if (spec->isExplicitSpecialization()) {
|
||||
explicitSpecSuppressor = spec;
|
||||
} else {
|
||||
const ClassTemplateDecl *temp = spec->getSpecializedTemplate();
|
||||
if (isExplicitMemberSpecialization(temp)) {
|
||||
explicitSpecSuppressor = temp->getTemplatedDecl();
|
||||
}
|
||||
}
|
||||
} else if (isExplicitMemberSpecialization(RD)) {
|
||||
explicitSpecSuppressor = RD;
|
||||
}
|
||||
|
||||
// Static data members.
|
||||
|
@ -759,21 +822,46 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
|
|||
// Modify the variable's linkage by its type, but ignore the
|
||||
// type's visibility unless it's a definition.
|
||||
LinkageInfo typeLV = getLVForType(VD->getType());
|
||||
if (typeLV.linkage() != ExternalLinkage)
|
||||
LV.mergeLinkage(UniqueExternalLinkage);
|
||||
if (!LV.visibilityExplicit())
|
||||
LV.mergeVisibility(typeLV);
|
||||
LV.mergeMaybeWithVisibility(typeLV,
|
||||
!LV.visibilityExplicit() && !classLV.visibilityExplicit());
|
||||
|
||||
if (isExplicitMemberSpecialization(VD)) {
|
||||
explicitSpecSuppressor = VD;
|
||||
}
|
||||
|
||||
// Template members.
|
||||
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
|
||||
bool considerVisibility =
|
||||
(!LV.visibilityExplicit() &&
|
||||
!classLV.visibilityExplicit() &&
|
||||
!hasExplicitVisibilityAlready(computation));
|
||||
LinkageInfo tempLV =
|
||||
getLVForTemplateParameterList(temp->getTemplateParameters());
|
||||
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
|
||||
|
||||
if (const RedeclarableTemplateDecl *redeclTemp =
|
||||
dyn_cast<RedeclarableTemplateDecl>(temp)) {
|
||||
if (isExplicitMemberSpecialization(redeclTemp)) {
|
||||
explicitSpecSuppressor = temp->getTemplatedDecl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We should never be looking for an attribute directly on a template.
|
||||
assert(!explicitSpecSuppressor || !isa<TemplateDecl>(explicitSpecSuppressor));
|
||||
|
||||
// If this member is an explicit member specialization, and it has
|
||||
// an explicit attribute, ignore visibility from the parent.
|
||||
bool considerClassVisibility = true;
|
||||
if (explicitSpecSuppressor &&
|
||||
LV.visibilityExplicit() && // optimization: hasDVA() is true only if this
|
||||
classLV.visibility() != DefaultVisibility &&
|
||||
hasDirectVisibilityAttribute(explicitSpecSuppressor, computation)) {
|
||||
considerClassVisibility = false;
|
||||
}
|
||||
|
||||
// Finally, merge in information from the class.
|
||||
LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
|
||||
return LV;
|
||||
}
|
||||
|
||||
|
@ -2344,10 +2432,6 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
|
||||
return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
|
||||
}
|
||||
|
||||
void
|
||||
FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
|
||||
FunctionDecl *FD,
|
||||
|
|
|
@ -1120,10 +1120,6 @@ CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
|
||||
return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
|
||||
}
|
||||
|
||||
void
|
||||
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
|
||||
TemplateSpecializationKind TSK) {
|
||||
|
|
|
@ -1182,3 +1182,48 @@ namespace test64 {
|
|||
template class B<A>;
|
||||
// CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
|
||||
}
|
||||
|
||||
namespace test65 {
|
||||
class HIDDEN A {};
|
||||
template <class T> struct B {
|
||||
static void func();
|
||||
template <class U> static void funcT1();
|
||||
template <class U> static void funcT2();
|
||||
class Inner {};
|
||||
template <class U> class InnerT {};
|
||||
};
|
||||
template <template <class T> class Temp> struct C {
|
||||
static void foo() {}
|
||||
};
|
||||
|
||||
// CHECK: define void @_ZN6test651BINS_1AEE4funcEv()
|
||||
template <> DEFAULT void B<A>::func() {}
|
||||
|
||||
// CHECK: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv()
|
||||
template <> template <> DEFAULT void B<A>::funcT2<A>() {}
|
||||
|
||||
// CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv()
|
||||
// CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv()
|
||||
template <> template <class T> DEFAULT void B<A>::funcT1() {}
|
||||
|
||||
// CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv()
|
||||
template <> struct DEFAULT B<A>::Inner {
|
||||
static void foo() {}
|
||||
};
|
||||
|
||||
// CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv()
|
||||
// CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv()
|
||||
template <> template <class U> struct DEFAULT B<A>::InnerT {
|
||||
static void foo() {}
|
||||
};
|
||||
|
||||
void test() {
|
||||
B<A>::funcT1<int>();
|
||||
B<A>::funcT1<A>();
|
||||
B<A>::Inner::foo();
|
||||
B<A>::InnerT<int>::foo();
|
||||
B<A>::InnerT<A>::foo();
|
||||
}
|
||||
|
||||
template class C<B<A>::InnerT>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue