summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2013-02-20 01:54:26 +0000
committerJohn McCall <rjmccall@apple.com>2013-02-20 01:54:26 +0000
commitd4c3d66be70ae2d0bd828329022dc428cc277a1c (patch)
treeb980077d0866c29bcf09476b73c6a1d234727872
parent975d52c759a0da21461668bac840bb5d21061d1b (diff)
downloadclang-d4c3d66be70ae2d0bd828329022dc428cc277a1c.tar.gz
clang-d4c3d66be70ae2d0bd828329022dc428cc277a1c.tar.bz2
clang-d4c3d66be70ae2d0bd828329022dc428cc277a1c.tar.xz
Add a new 'type_visibility' attribute to allow users to
control the visibility of a type for the purposes of RTTI and template argument restrictions independently of how visibility propagates to its non-type member declarations. Also fix r175326 to not ignore template argument visibility on a template explicit instantiation when a member has an explicit attribute but the instantiation does not. The type_visibility work is rdar://11880378 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175587 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h9
-rw-r--r--include/clang/Basic/Attr.td8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--lib/AST/Decl.cpp227
-rw-r--r--lib/CodeGen/CGVTables.cpp2
-rw-r--r--lib/CodeGen/CodeGenModule.cpp2
-rw-r--r--lib/Sema/SemaAttr.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp3
-rw-r--r--lib/Sema/SemaDeclAttr.cpp84
-rw-r--r--test/CodeGenCXX/type_visibility.cpp170
-rw-r--r--test/CodeGenCXX/visibility.cpp12
-rw-r--r--test/Sema/attr-visibility.c4
13 files changed, 441 insertions, 91 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index e9643d2dc7..f6c912a38b 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -300,9 +300,16 @@ public:
/// \brief Determines the linkage and visibility of this entity.
LinkageInfo getLinkageAndVisibility() const;
+ /// Kinds of explicit visibility.
+ enum ExplicitVisibilityKind {
+ VisibilityForType,
+ VisibilityForValue
+ };
+
/// \brief If visibility was explicitly specified for this
/// declaration, return that visibility.
- llvm::Optional<Visibility> getExplicitVisibility() const;
+ llvm::Optional<Visibility>
+ getExplicitVisibility(ExplicitVisibilityKind kind) const;
/// \brief Clear the linkage cache in response to a change
/// to the declaration.
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index e955367761..70217d2beb 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -732,6 +732,14 @@ def Visibility : InheritableAttr {
["Default", "Hidden", "Hidden", "Protected"]>];
}
+def TypeVisibility : InheritableAttr {
+ let Clone = 0;
+ let Spellings = [GNU<"type_visibility">, CXX11<"clang", "type_visibility">];
+ let Args = [EnumArgument<"Visibility", "VisibilityType",
+ ["default", "hidden", "internal", "protected"],
+ ["Default", "Hidden", "Hidden", "Protected"]>];
+}
+
def VecReturn : InheritableAttr {
let Spellings = [GNU<"vecreturn">];
let Subjects = [CXXRecord];
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2bacb2cff9..b69bfda242 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1849,7 +1849,8 @@ def warn_attribute_wrong_decl_type : Warning<
"functions, methods, and parameters|classes|variables|methods|"
"variables, functions and labels|fields and global variables|structs|"
"variables, functions and tag types|thread-local variables|"
- "variables and fields|variables, data members and tag types}1">,
+ "variables and fields|variables, data members and tag types|"
+ "types and namespaces}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<
"%0 attribute only applies to %select{functions|unions|"
@@ -1858,7 +1859,8 @@ def err_attribute_wrong_decl_type : Error<
"functions, methods, and parameters|classes|variables|methods|"
"variables, functions and labels|fields and global variables|structs|"
"variables, functions and tag types|thread-local variables|"
- "variables and fields|variables, data members and tag types}1">;
+ "variables and fields|variables, data members and tag types|"
+ "types and namespaces}1">;
def warn_function_attribute_wrong_type : Warning<
"'%0' only applies to function types; type here is %1">,
InGroup<IgnoredAttributes>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 07f035fa24..9d9014ab9c 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1687,6 +1687,9 @@ public:
StringRef Message,
bool Override,
unsigned AttrSpellingListIndex);
+ TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
+ TypeVisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex);
VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range,
VisibilityAttr::VisibilityType Vis,
unsigned AttrSpellingListIndex);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 6e93dd6415..e29c5e3c9b 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -59,22 +59,75 @@ using namespace clang;
// attribute (or something like it), not a global visibility setting.
// When emitting a reference to an external symbol, visibility
// restrictions are ignored unless they are explicit.
+//
+// 5. When computing the visibility of a non-type, including a
+// non-type member of a class, only non-type visibility restrictions
+// are considered: the 'visibility' attribute, global value-visibility
+// settings, and a few special cases like __private_extern.
+//
+// 6. When computing the visibility of a type, including a type member
+// of a class, only type visibility restrictions are considered:
+// the 'type_visibility' attribute and global type-visibility settings.
+// However, a 'visibility' attribute counts as a 'type_visibility'
+// attribute on any declaration that only has the former.
+//
+// The visibility of a "secondary" entity, like a template argument,
+// is computed using the kind of that entity, not the kind of the
+// primary entity for which we are computing visibility. For example,
+// the visibility of a specialization of either of these templates:
+// template <class T, bool (&compare)(T, X)> bool has_match(list<T>, X);
+// template <class T, bool (&compare)(T, X)> class matcher;
+// is restricted according to the type visibility of the argument 'T',
+// the type visibility of 'bool(&)(T,X)', and the value visibility of
+// the argument function 'compare'. That 'has_match' is a value
+// and 'matcher' is a type only matters when looking for attributes
+// and settings from the immediate context.
/// 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 an LV computation that does everything normal for linkage but
- /// ignores sources of visibility other than template arguments.
- LVOnlyTemplateArguments,
-
/// Do a normal LV computation for, ultimately, a type.
- LVForType,
+ LVForType = NamedDecl::VisibilityForType,
+
+ /// Do a normal LV computation for, ultimately, a non-type declaration.
+ 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 value.
- LVForValue
+ /// Do a normal LV computation for, ultimately, a non-type declaration
+ /// that already has some sort of explicit visibility.
+ LVForExplicitValue
};
+/// 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);
+}
+
+/// Given an LVComputationKind, return one of the same type/value sort
+/// that records that it already has explicit visibility.
+static LVComputationKind
+withExplicitVisibilityAlready(LVComputationKind oldKind) {
+ LVComputationKind newKind =
+ static_cast<LVComputationKind>(unsigned(oldKind) | 2);
+ assert(oldKind != LVForType || newKind == LVForExplicitType);
+ assert(oldKind != LVForValue || newKind == LVForExplicitValue);
+ assert(oldKind != LVForExplicitType || newKind == LVForExplicitType);
+ assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue);
+ return newKind;
+}
+
+static llvm::Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
+ LVComputationKind kind) {
+ assert(!hasExplicitVisibilityAlready(kind) &&
+ "asking for explicit visibility when we shouldn't be");
+ return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind);
+}
+
typedef NamedDecl::LinkageInfo LinkageInfo;
/// Is the given declaration a "type" or a "value" for the purposes of
@@ -85,18 +138,35 @@ static bool usesTypeVisibility(const NamedDecl *D) {
isa<ObjCInterfaceDecl>(D);
}
+/// Given a visibility attribute, return the explicit visibility
+/// associated with it.
+template <class T>
+static Visibility getVisibilityFromAttr(const T *attr) {
+ switch (attr->getVisibility()) {
+ case T::Default:
+ return DefaultVisibility;
+ case T::Hidden:
+ return HiddenVisibility;
+ case T::Protected:
+ return ProtectedVisibility;
+ }
+ llvm_unreachable("bad visibility kind");
+}
+
/// Return the explicit visibility of the given declaration.
-static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
+static llvm::Optional<Visibility> getVisibilityOf(const NamedDecl *D,
+ NamedDecl::ExplicitVisibilityKind kind) {
+ // If we're ultimately computing the visibility of a type, look for
+ // a 'type_visibility' attribute before looking for 'visibility'.
+ if (kind == NamedDecl::VisibilityForType) {
+ if (const TypeVisibilityAttr *A = D->getAttr<TypeVisibilityAttr>()) {
+ return getVisibilityFromAttr(A);
+ }
+ }
+
// If this declaration has an explicit visibility attribute, use it.
if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) {
- switch (A->getVisibility()) {
- case VisibilityAttr::Default:
- return DefaultVisibility;
- case VisibilityAttr::Hidden:
- return HiddenVisibility;
- case VisibilityAttr::Protected:
- return ProtectedVisibility;
- }
+ return getVisibilityFromAttr(A);
}
// If we're on Mac OS X, an 'availability' for Mac OS X attribute
@@ -261,23 +331,19 @@ static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
}
-/// Merge in template-related linkage and visibility for the given
-/// class template specialization.
-static void mergeTemplateLV(LinkageInfo &LV,
- const ClassTemplateSpecializationDecl *spec,
- LVComputationKind computation) {
- // FIXME: type visibility
- bool hasExplicitVisibility = spec->hasAttr<VisibilityAttr>();
- ClassTemplateDecl *temp = spec->getSpecializedTemplate();
-
+/// Should we consider visibility associated with the template
+/// arguments and parameters of the given class template specialization?
+static bool shouldConsiderTemplateVisibility(
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
// Include visibility from the template parameters and arguments
// only if this is not an explicit instantiation or specialization
// with direct explicit visibility (and note that implicit
// instantiations won't have a direct attribute).
//
// Furthermore, we want to ignore template parameters and arguments
- // for an explicit instantiation or specialization when computing
- // the visibility of a member thereof with explicit visibility.
+ // for an explicit specialization when computing the visibility of a
+ // member thereof with explicit visibility.
//
// This is a bit complex; let's unpack it.
//
@@ -286,21 +352,49 @@ static void mergeTemplateLV(LinkageInfo &LV,
// explicit visibility attribute, that must directly express the
// user's intent, and we should honor it. The same logic applies to
// an explicit instantiation of a member of such a thing.
- //
- // That we're doing this for a member with explicit visibility
- // is encoded by the computation kind being OnlyTemplateArguments.
- bool considerVisibility =
- !(hasExplicitVisibility ||
- (computation == LVOnlyTemplateArguments &&
- spec->isExplicitInstantiationOrSpecialization()));
+
+ // Fast path: if this is not an explicit instantiation or
+ // specialization, we always want to consider template-related
+ // visibility restrictions.
+ if (!spec->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ // This is the 'member thereof' check.
+ if (spec->isExplicitSpecialization() &&
+ 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");
+}
+
+/// Merge in template-related linkage and visibility for the given
+/// class template specialization.
+static void mergeTemplateLV(LinkageInfo &LV,
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
// Merge information from the template parameters, but ignore
// visibility if we're only considering template arguments.
+ ClassTemplateDecl *temp = spec->getSpecializedTemplate();
LinkageInfo tempLV =
getLVForTemplateParameterList(temp->getTemplateParameters());
LV.mergeMaybeWithVisibility(tempLV,
- considerVisibility && computation != LVOnlyTemplateArguments);
+ considerVisibility && !hasExplicitVisibilityAlready(computation));
// Merge information from the template arguments. We ignore
// template-argument visibility if we've got an explicit
@@ -422,8 +516,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// external.
LinkageInfo LV;
- if (computation != LVOnlyTemplateArguments) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (llvm::Optional<Visibility> Vis
+ = getExplicitVisibility(D, computation)) {
LV.mergeVisibility(*Vis, true);
} else {
// If we're declared in a namespace with a visibility attribute,
@@ -433,7 +528,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
DC = DC->getParent()) {
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND) continue;
- if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) {
+ if (llvm::Optional<Visibility> Vis
+ = getExplicitVisibility(ND, computation)) {
LV.mergeVisibility(*Vis, true);
break;
}
@@ -562,7 +658,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
- bool considerVisibility = (computation != LVOnlyTemplateArguments);
+ bool considerVisibility = !hasExplicitVisibilityAlready(computation);
LinkageInfo tempLV =
getLVForTemplateParameterList(temp->getTemplateParameters());
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
@@ -605,8 +701,9 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
LinkageInfo LV;
// If we have an explicit visibility attribute, merge that in.
- if (computation != LVOnlyTemplateArguments) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility())
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (llvm::Optional<Visibility> Vis
+ = getExplicitVisibility(D, computation))
LV.mergeVisibility(*Vis, true);
// If we're paying attention to global visibility, apply
// -finline-visibility-hidden if this is an inline method.
@@ -620,8 +717,9 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
// If this class member has an explicit visibility attribute, the only
// thing that can change its visibility is the template arguments, so
// only look for them when processing the class.
- LVComputationKind classComputation =
- (LV.visibilityExplicit() ? LVOnlyTemplateArguments : computation);
+ LVComputationKind classComputation = computation;
+ 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
@@ -672,7 +770,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
// Template members.
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
bool considerVisibility =
- (!LV.visibilityExplicit() && computation != LVOnlyTemplateArguments);
+ (!LV.visibilityExplicit() &&
+ !hasExplicitVisibilityAlready(computation));
LinkageInfo tempLV =
getLVForTemplateParameterList(temp->getTemplateParameters());
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
@@ -730,10 +829,9 @@ Linkage NamedDecl::getLinkage() const {
if (HasCachedLinkage)
return Linkage(CachedLinkage);
- // We don't care about visibility here, so suppress all the
- // unnecessary explicit-visibility checks by asking for a
- // template-argument-only analysis.
- CachedLinkage = getLVForDecl(this, LVOnlyTemplateArguments).linkage();
+ // We don't care about visibility here, so ask for the cheapest
+ // possible visibility analysis.
+ CachedLinkage = getLVForDecl(this, LVForExplicitValue).linkage();
HasCachedLinkage = 1;
#ifndef NDEBUG
@@ -785,16 +883,17 @@ void NamedDecl::verifyLinkage() const {
assert(!D || D->CachedLinkage == CachedLinkage);
}
-llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
+llvm::Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
// Use the most recent declaration of a variable.
if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (llvm::Optional<Visibility> V = getVisibilityOf(Var))
+ if (llvm::Optional<Visibility> V = getVisibilityOf(Var, kind))
return V;
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
}
return llvm::Optional<Visibility>();
@@ -802,45 +901,47 @@ llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
// Use the most recent declaration of a function, and also handle
// function template specializations.
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
- if (llvm::Optional<Visibility> V = getVisibilityOf(fn))
+ if (llvm::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
= fn->getTemplateSpecializationInfo())
- return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+ return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(),
+ kind);
// If the function is a member of a specialization of a class template
// and the corresponding decl has explicit visibility, use that.
FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
return llvm::Optional<Visibility>();
}
// Otherwise, just check the declaration itself first.
- if (llvm::Optional<Visibility> V = getVisibilityOf(this))
+ if (llvm::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());
+ 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());
+ 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);
+ return getVisibilityOf(InstantiatedFrom, kind);
}
return llvm::Optional<Visibility>();
@@ -858,8 +959,9 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
return LinkageInfo::internal();
LinkageInfo LV;
- if (computation != LVOnlyTemplateArguments) {
- if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (llvm::Optional<Visibility> Vis
+ = getExplicitVisibility(Function, computation))
LV.mergeVisibility(*Vis, true);
}
@@ -884,8 +986,9 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
LinkageInfo LV;
if (Var->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
- else if (computation != LVOnlyTemplateArguments) {
- if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
+ else if (!hasExplicitVisibilityAlready(computation)) {
+ if (llvm::Optional<Visibility> Vis
+ = getExplicitVisibility(Var, computation))
LV.mergeVisibility(*Vis, true);
}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 0c5d72fd8b..73a69b141d 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -116,7 +116,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
return;
- if (MD->getExplicitVisibility())
+ if (MD->getExplicitVisibility(ValueDecl::VisibilityForValue))
return;
switch (MD->getTemplateSpecializationKind()) {
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f725706f71..5033b56d3a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -347,7 +347,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
return;
// Don't override an explicit visibility attribute.
- if (RD->getExplicitVisibility())
+ if (RD->getExplicitVisibility(NamedDecl::VisibilityForType))
return;
switch (RD->getTemplateSpecializationKind()) {
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index b212b3fee0..e12bbde0d0 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -310,7 +310,7 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) {
return;
NamedDecl *ND = dyn_cast<NamedDecl>(D);
- if (ND && ND->getExplicitVisibility())
+ if (ND && ND->getExplicitVisibility(NamedDecl::VisibilityForValue))
return;
VisStack *Stack = static_cast<VisStack*>(VisContext);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7667681c79..189b3d94e2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1835,6 +1835,9 @@ bool Sema::mergeDeclAttribute(NamedDecl *D, InheritableAttr *Attr,
else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
AttrSpellingListIndex);
+ else if (TypeVisibilityAttr *VA = dyn_cast<TypeVisibilityAttr>(Attr))
+ NewAttr = mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
+ AttrSpellingListIndex);
else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
NewAttr = mergeDLLImportAttr(D, ImportA->getRange(),
AttrSpellingListIndex);
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2f3634a278..e8c42e6f7c 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -50,7 +50,8 @@ enum AttributeDeclKind {
ExpectedVariableFunctionOrTag,
ExpectedTLSVar,
ExpectedVariableOrField,
- ExpectedVariableFieldOrTag
+ ExpectedVariableFieldOrTag,
+ ExpectedTypeOrNamespace
};
//===----------------------------------------------------------------------===//
@@ -2254,29 +2255,57 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
D->addAttr(NewAttr);
}
+template <class T>
+static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range,
+ typename T::VisibilityType value,
+ unsigned attrSpellingListIndex) {
+ T *existingAttr = D->getAttr<T>();
+ if (existingAttr) {
+ typename T::VisibilityType existingValue = existingAttr->getVisibility();
+ if (existingValue == value)
+ return NULL;
+ S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
+ S.Diag(range.getBegin(), diag::note_previous_attribute);
+ D->dropAttr<T>();
+ }
+ return ::new (S.Context) T(range, S.Context, value, attrSpellingListIndex);
+}
+
VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
VisibilityAttr::VisibilityType Vis,
unsigned AttrSpellingListIndex) {
+ return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis,
+ AttrSpellingListIndex);
+}
+
+TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
+ TypeVisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex) {
+ return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, Range, Vis,
+ AttrSpellingListIndex);
+}
+
+static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool isTypeVisibility) {
+ // Visibility attributes don't mean anything on a typedef.
if (isa<TypedefNameDecl>(D)) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "visibility";
- return NULL;
+ S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored)
+ << Attr.getName();
+ return;
}
- VisibilityAttr *ExistingAttr = D->getAttr<VisibilityAttr>();
- if (ExistingAttr) {
- VisibilityAttr::VisibilityType ExistingVis = ExistingAttr->getVisibility();
- if (ExistingVis == Vis)
- return NULL;
- Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility);
- Diag(Range.getBegin(), diag::note_previous_attribute);
- D->dropAttr<VisibilityAttr>();
+
+ // 'type_visibility' can only go on a type or namespace.
+ if (isTypeVisibility &&
+ !(isa<TagDecl>(D) ||
+ isa<ObjCInterfaceDecl>(D) ||
+ isa<NamespaceDecl>(D))) {
+ S.Diag(Attr.getRange().getBegin(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedTypeOrNamespace;
+ return;
}
- return ::new (Context) VisibilityAttr(Range, Context, Vis,
- AttrSpellingListIndex);
-}
-static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if(!checkAttributeNumArgs(S, Attr, 1))
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
Expr *Arg = Attr.getArg(0);
@@ -2285,7 +2314,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "visibility" << 1;
+ << (isTypeVisibility ? "type_visibility" : "visibility") << 1;
return;
}
@@ -2313,10 +2342,16 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
unsigned Index = Attr.getAttributeSpellingListIndex();
- VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type,
- Index);
- if (NewAttr)
- D->addAttr(NewAttr);
+ clang::Attr *newAttr;
+ if (isTypeVisibility) {
+ newAttr = S.mergeTypeVisibilityAttr(D, Attr.getRange(),
+ (TypeVisibilityAttr::VisibilityType) type,
+ Index);
+ } else {
+ newAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type, Index);
+ }
+ if (newAttr)
+ D->addAttr(newAttr);
}
static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
@@ -4693,7 +4728,12 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
handleReturnsTwiceAttr(S, D, Attr);
break;
case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break;
- case AttributeList::AT_Visibility: handleVisibilityAttr (S, D, Attr); break;
+ case AttributeList::AT_Visibility:
+ handleVisibilityAttr(S, D, Attr, false);
+ break;
+ case AttributeList::AT_TypeVisibility:
+ handleVisibilityAttr(S, D, Attr, true);
+ break;
case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
break;
case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break;
diff --git a/test/CodeGenCXX/type_visibility.cpp b/test/CodeGenCXX/type_visibility.cpp
new file mode 100644
index 0000000000..5c45611991
--- /dev/null
+++ b/test/CodeGenCXX/type_visibility.cpp
@@ -0,0 +1,170 @@
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o %t.ll
+// RUN: FileCheck %s -check-prefix=FUNS < %t.ll
+// RUN: FileCheck %s -check-prefix=VARS < %t.ll
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o %t.ll
+// RUN: FileCheck %s -check-prefix=FUNS-HIDDEN < %t.ll
+// RUN: FileCheck %s -check-prefix=VARS-HIDDEN < %t.ll
+
+#define HIDDEN __attribute__((visibility("hidden")))
+#define PROTECTED __attribute__((visibility("protected")))
+#define DEFAULT __attribute__((visibility("default")))
+#define TYPE_HIDDEN __attribute__((type_visibility("hidden")))
+#define TYPE_PROTECTED __attribute__((type_visibility("protected")))
+#define TYPE_DEFAULT __attribute__((type_visibility("default")))
+
+// type_visibility is rdar://11880378
+
+#if !__has_attribute(type_visibility)
+#error No type_visibility attribute!
+#endif
+
+// The template tests come first because IR-gen reorders RTTI wierdly.
+namespace temp0 {
+ struct A;
+ template <class T> struct TYPE_DEFAULT B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp01BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS: @_ZTSN5temp01BINS_1AEEE = weak_odr constant
+ // VARS: @_ZTIN5temp01BINS_1AEEE = weak_odr unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp01BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace temp1 {
+ struct TYPE_DEFAULT A;
+ template <class T> struct TYPE_DEFAULT B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS: @_ZTSN5temp11BINS_1AEEE = weak_odr constant
+ // VARS: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp11BINS_1AEEE = weak_odr constant
+ // VARS-HIDDEN: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+}
+
+namespace temp2 {
+ struct TYPE_DEFAULT A;
+ template <class T> struct B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp21BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS: @_ZTSN5temp21BINS_1AEEE = weak_odr constant
+ // VARS: @_ZTIN5temp21BINS_1AEEE = weak_odr unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp21BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace temp3 {
+ struct TYPE_HIDDEN A;
+ template <class T> struct TYPE_DEFAULT B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant
+ // VARS: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace temp4 {
+ struct TYPE_DEFAULT A;
+ template <class T> struct TYPE_HIDDEN B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant
+ // VARS: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace type0 {
+ struct TYPE_DEFAULT A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define void @_ZN5type01A3fooEv(
+ // VARS: @_ZTVN5type01AE = unnamed_addr constant
+ // VARS: @_ZTSN5type01AE = constant
+ // VARS: @_ZTIN5type01AE = unnamed_addr constant
+ // FUNS-HIDDEN: define hidden void @_ZN5type01A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type01AE = unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type01AE = constant
+ // VARS-HIDDEN: @_ZTIN5type01AE = unnamed_addr constant
+}
+
+namespace type1 {
+ struct HIDDEN TYPE_DEFAULT A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define hidden void @_ZN5type11A3fooEv(
+ // VARS: @_ZTVN5type11AE = unnamed_addr constant
+ // VARS: @_ZTSN5type11AE = constant
+ // VARS: @_ZTIN5type11AE = unnamed_addr constant
+ // FUNS-HIDDEN: define hidden void @_ZN5type11A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type11AE = unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type11AE = constant
+ // VARS-HIDDEN: @_ZTIN5type11AE = unnamed_addr constant
+}
+
+namespace type2 {
+ struct TYPE_HIDDEN A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define void @_ZN5type21A3fooEv(
+ // VARS: @_ZTVN5type21AE = hidden unnamed_addr constant
+ // VARS: @_ZTSN5type21AE = hidden constant
+ // VARS: @_ZTIN5type21AE = hidden unnamed_addr constant
+ // FUNS-HIDDEN: define hidden void @_ZN5type21A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type21AE = hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type21AE = hidden constant
+ // VARS-HIDDEN: @_ZTIN5type21AE = hidden unnamed_addr constant
+}
+
+namespace type3 {
+ struct DEFAULT TYPE_HIDDEN A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define void @_ZN5type31A3fooEv(
+ // VARS: @_ZTVN5type31AE = hidden unnamed_addr constant
+ // VARS: @_ZTSN5type31AE = hidden constant
+ // VARS: @_ZTIN5type31AE = hidden unnamed_addr constant
+ // FUNS-HIDDEN: define void @_ZN5type31A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type31AE = hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type31AE = hidden constant
+ // VARS-HIDDEN: @_ZTIN5type31AE = hidden unnamed_addr constant
+}
+
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index 5564dc4019..cfddc8c0c2 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -1170,3 +1170,15 @@ namespace test63 {
// CHECK: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv()
// CHECK: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv()
}
+
+// Don't ignore the visibility of template arguments just because we
+// explicitly instantiated something.
+namespace test64 {
+ struct HIDDEN A {};
+ template <class P> struct B {
+ static DEFAULT void foo() {}
+ };
+
+ template class B<A>;
+ // CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
+}
diff --git a/test/Sema/attr-visibility.c b/test/Sema/attr-visibility.c
index 77bc39c9e6..7f7fd546f0 100644
--- a/test/Sema/attr-visibility.c
+++ b/test/Sema/attr-visibility.c
@@ -21,4 +21,6 @@ void test6() __attribute__((visibility("hidden"), // expected-note {{previous at
extern int test7 __attribute__((visibility("default"))); // expected-note {{previous attribute is here}}
extern int test7 __attribute__((visibility("hidden"))); // expected-error {{visibility does not match previous declaration}}
-typedef int __attribute__((visibility("default"))) bar; // expected-warning {{visibility attribute ignored}}
+typedef int __attribute__((visibility("default"))) bar; // expected-warning {{'visibility' attribute ignored}}
+
+int x __attribute__((type_visibility("default"))); // expected-error {{'type_visibility' attribute only applies to types and namespaces}}