aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2013-02-26 19:33:14 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2013-02-26 19:33:14 +0000
commitd3b2f0ac1cedad284d860acd652f28a05bcbcbed (patch)
treefaf6df298dabcae78b1c3084b34ca74412aa2de7
parentd7a60ad800d64b7c444b26a58e76ec337dbd7bc2 (diff)
Use the most recent decl in getExplicitVisibility.
Now that implicitly hidden template arguments can make an instantiation hidden, it is important to look at more than just the canonical decl of the argument in order to see if an attribute is available in a more recent decl. This has the disadvantage of exposing when getExplicitVisibility is called, but lets us handle cases like template <typename T> struct __attribute__((visibility("default"))) barT { static void zed() {} }; class foo; class __attribute__((visibility("default"))) foo; template struct barT<foo>; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176112 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/Decl.cpp55
-rw-r--r--test/CodeGenCXX/visibility.cpp33
2 files changed, 59 insertions, 29 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 5e8d130789..d363986745 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -970,11 +970,32 @@ void NamedDecl::verifyLinkage() const {
Optional<Visibility>
NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
- // Use the most recent declaration of a variable.
- if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (Optional<Visibility> V = getVisibilityOf(Var, kind))
- return V;
+ // Check the declaration itself first.
+ if (Optional<Visibility> V = getVisibilityOf(this, kind))
+ return V;
+
+ // If this is a member class of a specialization of a class template
+ // and the corresponding decl has explicit visibility, use that.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
+ if (InstantiatedFrom)
+ return getVisibilityOf(InstantiatedFrom, kind);
+ }
+ // 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>(this))
+ return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
+ kind);
+
+ // Use the most recent declaration.
+ const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl());
+ if (MostRecent != this)
+ return MostRecent->getExplicitVisibility(kind);
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
@@ -983,12 +1004,8 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return None;
}
- // Use the most recent declaration of a function, and also handle
- // function template specializations.
+ // Also handle function template specializations.
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
- if (Optional<Visibility> V = getVisibilityOf(fn, kind))
- return V;
-
// If the function is a specialization of a template with an
// explicit visibility attribute, use that.
if (FunctionTemplateSpecializationInfo *templateInfo
@@ -1005,30 +1022,10 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return None;
}
- // Otherwise, just check the declaration itself first.
- if (Optional<Visibility> V = getVisibilityOf(this, kind))
- return V;
-
// The visibility of a template is stored in the templated decl.
if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
return getVisibilityOf(TD->getTemplatedDecl(), kind);
- // 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>(this))
- return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
- kind);
-
- // If this is a member class of a specialization of a class template
- // and the corresponding decl has explicit visibility, use that.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
- CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
- if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom, kind);
- }
-
return None;
}
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index b9dec17301..5511da7cb3 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -1227,3 +1227,36 @@ namespace test65 {
template class C<B<A>::InnerT>;
}
+
+namespace test66 {
+ template <typename T>
+ struct __attribute__((visibility("default"))) barT {
+ static void zed() {}
+ };
+ class foo;
+ class __attribute__((visibility("default"))) foo;
+ template struct barT<foo>;
+ // CHECK: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
+
+ template <int* I>
+ struct __attribute__((visibility("default"))) barI {
+ static void zed() {}
+ };
+ extern int I;
+ extern int I __attribute__((visibility("default")));
+ template struct barI<&I>;
+ // CHECK: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
+
+ typedef void (*fType)(void);
+ template<fType F>
+ struct __attribute__((visibility("default"))) barF {
+ static void zed() {}
+ };
+ void F();
+ void F() __attribute__((visibility("default")));;
+ template struct barF<F>;
+ // CHECK: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
+}