minVisibility(L.second, R.visibility()));
}
+/// Flags controlling the computation of linkage and visibility.
+struct LVFlags {
+ bool ConsiderGlobalVisibility;
+ bool ConsiderVisibilityAttributes;
+
+ LVFlags() : ConsiderGlobalVisibility(true),
+ ConsiderVisibilityAttributes(true) {
+ }
+
+ /// Returns a set of flags, otherwise based on these, which ignores
+ /// off all sources of visibility except template arguments.
+ LVFlags onlyTemplateVisibility() const {
+ LVFlags F = *this;
+ F.ConsiderGlobalVisibility = false;
+ F.ConsiderVisibilityAttributes = false;
+ return F;
+ }
+};
+
/// \brief Get the most restrictive linkage for the types in the given
/// template parameter list.
static LVPair
/// getLVForDecl - Get the cached linkage and visibility for the given
/// declaration.
-///
-/// \param ConsiderGlobalVisibility - Whether to honor global visibility
-/// settings. This is generally false when computing the visibility
-/// of the context of a declaration.
-static LinkageInfo getLVForDecl(const NamedDecl *D,
- bool ConsiderGlobalVisibility);
-
-static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
- bool ConsiderGlobalVisibility) {
+static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F);
+
+static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
// external.
LinkageInfo LV;
- if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
- LV.setVisibility(GetVisibilityFromAttr(VA), true);
+ if (F.ConsiderVisibilityAttributes) {
+ if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
+ LV.setVisibility(GetVisibilityFromAttr(VA), true);
+ F.ConsiderGlobalVisibility = false;
+ }
}
// C++ [basic.link]p4:
if (FunctionTemplateSpecializationInfo *SpecInfo
= Function->getTemplateSpecializationInfo()) {
- LV.merge(SpecInfo->getTemplate()->getLinkageAndVisibility());
+ LV.merge(getLVForDecl(SpecInfo->getTemplate(),
+ F.onlyTemplateVisibility()));
const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments;
LV.merge(getLVForTemplateArgumentList(TemplateArgs));
}
// linkage of the template and template arguments.
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
- // From the template. Note below the restrictions on how we
- // compute template visibility.
- LV.merge(Spec->getSpecializedTemplate()->getLinkageAndVisibility());
+ // From the template.
+ LV.merge(getLVForDecl(Spec->getSpecializedTemplate(),
+ F.onlyTemplateVisibility()));
// The arguments at which the template was instantiated.
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
}
// Consider -fvisibility unless the type has C linkage.
- if (ConsiderGlobalVisibility)
- ConsiderGlobalVisibility =
+ if (F.ConsiderGlobalVisibility)
+ F.ConsiderGlobalVisibility =
(Context.getLangOptions().CPlusPlus &&
!Tag->getDeclContext()->isExternCContext());
} else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
LV.merge(getLVForTemplateParameterList(Template->getTemplateParameters()));
- // We do not want to consider attributes or global settings when
- // computing template visibility.
- return LV;
-
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
} else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
// If we didn't end up with hidden visibility, consider attributes
// and -fvisibility.
- if (ConsiderGlobalVisibility && !LV.visibilityExplicit() &&
- LV.visibility() != HiddenVisibility)
+ if (F.ConsiderGlobalVisibility)
LV.mergeVisibility(Context.getLangOptions().getVisibilityMode());
return LV;
}
-static LinkageInfo getLVForClassMember(const NamedDecl *D,
- bool ConsiderGlobalVisibility) {
+static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
// Only certain class members have linkage. Note that fields don't
// really have linkage, but it's convenient to say they do for the
// purposes of calculating linkage of pointer-to-data-member
(D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl()))))
return LinkageInfo::none();
- const VisibilityAttr *VA = GetExplicitVisibility(D);
- if (VA)
- ConsiderGlobalVisibility = false;
+ LinkageInfo LV;
+
+ // The flags we're going to use to compute the class's visibility.
+ LVFlags ClassF = F;
+
+ // If we have an explicit visibility attribute, merge that in.
+ if (F.ConsiderVisibilityAttributes) {
+ if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
+ LV.mergeVisibility(GetVisibilityFromAttr(VA), true);
+
+ // Ignore global visibility later, but not this attribute.
+ F.ConsiderGlobalVisibility = false;
+
+ // Ignore both global visibility and attributes when computing our
+ // parent's visibility.
+ ClassF = F.onlyTemplateVisibility();
+ }
+ }
// Class members only have linkage if their class has external
- // linkage. Consider global visibility only if we have no explicit
- // visibility attributes.
- LinkageInfo ClassLV = getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
- ConsiderGlobalVisibility);
- if (!isExternalLinkage(ClassLV.linkage()))
+ // linkage.
+ LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()), ClassF));
+ if (!isExternalLinkage(LV.linkage()))
return LinkageInfo::none();
// If the class already has unique-external linkage, we can't improve.
- if (ClassLV.linkage() == UniqueExternalLinkage)
+ if (LV.linkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
- // Start with the class's linkage and visibility.
- LinkageInfo LV = ClassLV;
-
- // If we have an explicit visibility attribute, merge that in.
- if (VA)
- LV.mergeVisibility(GetVisibilityFromAttr(VA), true);
-
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
TemplateSpecializationKind TSK = TSK_Undeclared;
// about whether containing classes have visibility attributes,
// and that's intentional.
if (TSK != TSK_ExplicitInstantiationDeclaration &&
- ConsiderGlobalVisibility &&
+ F.ConsiderGlobalVisibility &&
MD->getASTContext().getLangOptions().InlineVisibilityHidden) {
// InlineVisibilityHidden only applies to definitions, and
// isInlined() only gives meaningful answers on definitions
LV.mergeVisibility(TypeLV.second);
}
- ConsiderGlobalVisibility &= !LV.visibilityExplicit();
+ F.ConsiderGlobalVisibility &= !LV.visibilityExplicit();
// Apply -fvisibility if desired.
- if (ConsiderGlobalVisibility && LV.visibility() != HiddenVisibility) {
+ if (F.ConsiderGlobalVisibility && LV.visibility() != HiddenVisibility) {
LV.mergeVisibility(D->getASTContext().getLangOptions().getVisibilityMode());
}
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
- return getLVForDecl(this, /*ConsiderGlobalSettings*/ true);
+ return getLVForDecl(this, LVFlags());
}
-static LinkageInfo getLVForDecl(const NamedDecl *D,
- bool ConsiderGlobalVisibility) {
+static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
// Handle linkage for namespace-scope names.
if (D->getDeclContext()->getRedeclContext()->isFileContext())
- return getLVForNamespaceScopeDecl(D, ConsiderGlobalVisibility);
+ return getLVForNamespaceScopeDecl(D, Flags);
// C++ [basic.link]p5:
// In addition, a member function, static data member, a named
// purposes (7.1.3), has external linkage if the name of the class
// has external linkage.
if (D->getDeclContext()->isRecord())
- return getLVForClassMember(D, ConsiderGlobalVisibility);
+ return getLVForClassMember(D, Flags);
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
a.foo();
}
}
+
+namespace Test17 {
+ struct HIDDEN A {
+ static void foo();
+ static void DEFAULT bar();
+ static void HIDDEN baz();
+
+ struct DEFAULT B {
+ static void foo();
+ static void DEFAULT bar();
+ static void HIDDEN baz();
+ };
+ };
+
+ void test() {
+ A::foo();
+ A::bar();
+ A::baz();
+ A::B::foo();
+ A::B::bar();
+ A::B::baz();
+ }
+ // CHECK: declare hidden void @_ZN6Test171A3fooEv()
+ // CHECK: declare void @_ZN6Test171A3barEv()
+ // CHECK: declare hidden void @_ZN6Test171A3bazEv()
+ // CHECK: declare void @_ZN6Test171A1B3fooEv()
+ // CHECK: declare void @_ZN6Test171A1B3barEv()
+ // CHECK: declare hidden void @_ZN6Test171A1B3bazEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test171A3fooEv()
+ // CHECK-HIDDEN: declare void @_ZN6Test171A3barEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test171A3bazEv()
+ // CHECK-HIDDEN: declare void @_ZN6Test171A1B3fooEv()
+ // CHECK-HIDDEN: declare void @_ZN6Test171A1B3barEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test171A1B3bazEv()
+}
+
+namespace Test18 {
+ template <class T> struct HIDDEN A {
+ static void foo();
+ static void DEFAULT bar();
+ static void HIDDEN baz();
+
+ struct DEFAULT B {
+ static void foo();
+ static void DEFAULT bar();
+ static void HIDDEN baz();
+ };
+ };
+ struct HIDDEN H;
+
+ void test() {
+ A<int>::foo();
+ A<int>::bar();
+ A<int>::baz();
+ A<int>::B::foo();
+ A<int>::B::bar();
+ A<int>::B::baz();
+ A<H>::foo();
+ A<H>::bar();
+ A<H>::baz();
+ A<H>::B::foo();
+ A<H>::B::bar();
+ A<H>::B::baz();
+ }
+ // CHECK: declare hidden void @_ZN6Test181AIiE3fooEv()
+ // CHECK: declare void @_ZN6Test181AIiE3barEv()
+ // CHECK: declare hidden void @_ZN6Test181AIiE3bazEv()
+ // CHECK: declare void @_ZN6Test181AIiE1B3fooEv()
+ // CHECK: declare void @_ZN6Test181AIiE1B3barEv()
+ // CHECK: declare hidden void @_ZN6Test181AIiE1B3bazEv()
+ // CHECK: declare hidden void @_ZN6Test181AINS_1HEE3fooEv()
+ // CHECK: declare hidden void @_ZN6Test181AINS_1HEE3barEv()
+ // CHECK: declare hidden void @_ZN6Test181AINS_1HEE3bazEv()
+ // CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3fooEv()
+ // CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3barEv()
+ // CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3bazEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE3fooEv()
+ // CHECK-HIDDEN: declare void @_ZN6Test181AIiE3barEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE3bazEv()
+ // CHECK-HIDDEN: declare void @_ZN6Test181AIiE1B3fooEv()
+ // CHECK-HIDDEN: declare void @_ZN6Test181AIiE1B3barEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE1B3bazEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3fooEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3barEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3bazEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3fooEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3barEv()
+ // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3bazEv()
+}