r175827 - Ignore visibility from enclosing template arguments
John McCall
rjmccall at apple.com
Thu Feb 21 15:42:58 PST 2013
Author: rjmccall
Date: Thu Feb 21 17:42:58 2013
New Revision: 175827
URL: http://llvm.org/viewvc/llvm-project?rev=175827&view=rev
Log:
Ignore visibility from enclosing template arguments
for explicit member specializations.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/test/CodeGenCXX/visibility.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=175827&r1=175826&r2=175827&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Feb 21 17:42:58 2013
@@ -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.
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=175827&r1=175826&r2=175827&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Feb 21 17:42:58 2013
@@ -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.
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=175827&r1=175826&r2=175827&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Feb 21 17:42:58 2013
@@ -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 &&
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=175827&r1=175826&r2=175827&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Feb 21 17:42:58 2013
@@ -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 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 type that already has
+ /// some sort of explicit visibility. Visibility may only be
+ /// restricted by the visibility of template arguments.
+ LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit),
+
+ /// 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
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 Nam
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 Templ
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.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 shouldConsiderTemplateVisibi
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 getLVForNamespaceScop
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 getLVForNamespaceScop
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(c
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(c
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(c
// 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::getInstantia
return 0;
}
-MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
- return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
-}
-
void
FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
FunctionDecl *FD,
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=175827&r1=175826&r2=175827&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Feb 21 17:42:58 2013
@@ -1120,10 +1120,6 @@ CXXRecordDecl *CXXRecordDecl::getInstant
return 0;
}
-MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
- return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
-}
-
void
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
Modified: cfe/trunk/test/CodeGenCXX/visibility.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/visibility.cpp?rev=175827&r1=175826&r2=175827&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/visibility.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/visibility.cpp Thu Feb 21 17:42:58 2013
@@ -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>;
+}
More information about the cfe-commits
mailing list