GCC faithfully calculates visibility for variables independently of
whether it's a declaration or not, then ignores that information for
declarations unless it was explicitly given. It's not totally clear
how that should be mapped into a sane system, but make an effort.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117780 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index dbd14e0..2d29a6a 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -255,21 +255,17 @@
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
- if (Context.getLangOptions().CPlusPlus && !ExplicitVisibility &&
- !Var->isExternC()) {
+ if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) {
LVPair TypeLV = Var->getType()->getLinkageAndVisibility();
if (TypeLV.first != ExternalLinkage)
return LVPair(UniqueExternalLinkage, DefaultVisibility);
-
- // Otherwise, ignore type visibility for declarations.
- if (!isDeclaration)
+ if (!isDeclaration && !ExplicitVisibility)
LV.second = minVisibility(LV.second, TypeLV.second);
}
// Don't consider -fvisibility for pure declarations.
- if (isDeclaration) {
+ if (isDeclaration)
ConsiderGlobalVisibility = false;
- }
if (!Context.getLangOptions().CPlusPlus &&
(Var->getStorageClass() == SC_Extern ||
@@ -524,24 +520,24 @@
// Static data members.
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- // If we don't have explicit visibility information in the
- // hierarchy, apply the LV from its type. See the comment about
- // namespace-scope variables for justification for this
- // optimization.
- if (!HasExplicitVisibility) {
- LVPair TypeLV = VD->getType()->getLinkageAndVisibility();
- if (TypeLV.first != ExternalLinkage)
- LV.first = minLinkage(LV.first, UniqueExternalLinkage);
- LV.second = minVisibility(LV.second, TypeLV.second);
+ bool IsDefinition = (VD->getDefinition() &&
+ VD->getTemplateSpecializationKind()
+ != TSK_ExplicitInstantiationDeclaration);
+
+ // GCC just ignores the visibility of a variable declaration
+ // unless it's explicit.
+ if (!IsDefinition && !HasExplicitVisibility) {
+ LV.second = DefaultVisibility;
+ ConsiderGlobalVisibility = false;
}
- // Ignore global visibility if it's an extern template or
- // just a declaration.
- if (ConsiderGlobalVisibility)
- ConsiderGlobalVisibility =
- (VD->getDefinition() &&
- VD->getTemplateSpecializationKind()
- != TSK_ExplicitInstantiationDeclaration);
+ // Modify the variable's linkage by its type, but ignore the
+ // type's visibility unless it's a definition.
+ LVPair TypeLV = VD->getType()->getLinkageAndVisibility();
+ if (TypeLV.first != ExternalLinkage)
+ LV.first = minLinkage(LV.first, UniqueExternalLinkage);
+ if (IsDefinition && !HasExplicitVisibility)
+ LV.second = minVisibility(LV.second, TypeLV.second);
}
// Suppress -fvisibility if we have explicit visibility on any of
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index a555445..2272d1f 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -20,6 +20,8 @@
// CHECK-HIDDEN: @_ZN6Test131C1aE = global
// CHECK: @_ZN6Test143varE = external global
// CHECK-HIDDEN: @_ZN6Test143varE = external global
+// CHECK: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
+// CHECK-HIDDEN: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
// CHECK: @_ZTVN5Test63fooE = weak_odr hidden constant
namespace Test1 {
@@ -218,3 +220,17 @@
struct A *test() { return var; }
}
+
+// rdar://problem/8613093
+namespace Test15 {
+ struct A {};
+ template <class T> struct Temp {
+ struct Inner {
+ static char buffer[0];
+ };
+ };
+
+ char *test() {
+ return Temp<A>::Inner::buffer;
+ }
+}