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:
parent
98155ad3b5
commit
d041a9bf2d
|
@ -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.
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue