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

llvm-svn: 175587
This commit is contained in:
John McCall 2013-02-20 01:54:26 +00:00
parent 98155ad3b5
commit d041a9bf2d
13 changed files with 443 additions and 93 deletions

View File

@ -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.

View File

@ -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];

View File

@ -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>;

View File

@ -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);

View File

@ -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 value.
LVForValue
/// 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 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);
}

View File

@ -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()) {

View File

@ -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()) {

View File

@ -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);

View File

@ -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);

View File

@ -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) {
if (isa<TypedefNameDecl>(D)) {
Diag(Range.getBegin(), diag::warn_attribute_ignored) << "visibility";
return NULL;
}
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>();
}
return ::new (Context) VisibilityAttr(Range, Context, Vis,
AttrSpellingListIndex);
return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis,
AttrSpellingListIndex);
}
static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
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)) {
S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored)
<< Attr.getName();
return;
}
// '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;
}
// 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;

View File

@ -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
}

View File

@ -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()
}

View File

@ -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}}