From: John McCall Date: Wed, 20 Feb 2013 01:54:26 +0000 (+0000) Subject: Add a new 'type_visibility' attribute to allow users to X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d041a9bf2d99efe9ae4068eff98f5f5066cb717f;p=platform%2Fupstream%2Fllvm.git 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 --- diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index e9643d2..f6c912a 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/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 getExplicitVisibility() const; + llvm::Optional + getExplicitVisibility(ExplicitVisibilityKind kind) const; /// \brief Clear the linkage cache in response to a change /// to the declaration. diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index e955367..70217d2 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/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/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2bacb2c..b69bfda 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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; 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; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 07f035f..9d9014a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/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/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 6e93dd6..e29c5e3 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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 bool has_match(list, X); +// template 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(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 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(D); } +/// Given a visibility attribute, return the explicit visibility +/// associated with it. +template +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 getVisibilityOf(const Decl *D) { +static llvm::Optional 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()) { + return getVisibilityFromAttr(A); + } + } + // If this declaration has an explicit visibility attribute, use it. if (const VisibilityAttr *A = D->getAttr()) { - 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(); - 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()) + return false; + // fallthrough + case LVForValue: + case LVForExplicitValue: + if (spec->hasAttr()) + 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 Vis = D->getExplicitVisibility()) { + if (!hasExplicitVisibilityAlready(computation)) { + if (llvm::Optional 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(DC); if (!ND) continue; - if (llvm::Optional Vis = ND->getExplicitVisibility()) { + if (llvm::Optional 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(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 Vis = D->getExplicitVisibility()) + if (!hasExplicitVisibilityAlready(computation)) { + if (llvm::Optional 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(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 NamedDecl::getExplicitVisibility() const { +llvm::Optional +NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { // Use the most recent declaration of a variable. if (const VarDecl *Var = dyn_cast(this)) { - if (llvm::Optional V = getVisibilityOf(Var)) + if (llvm::Optional 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(); @@ -802,45 +901,47 @@ llvm::Optional NamedDecl::getExplicitVisibility() const { // Use the most recent declaration of a function, and also handle // function template specializations. if (const FunctionDecl *fn = dyn_cast(this)) { - if (llvm::Optional V = getVisibilityOf(fn)) + if (llvm::Optional 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(); } // Otherwise, just check the declaration itself first. - if (llvm::Optional V = getVisibilityOf(this)) + if (llvm::Optional V = getVisibilityOf(this, kind)) return V; // The visibility of a template is stored in the templated decl. if (const TemplateDecl *TD = dyn_cast(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(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(this)) { CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) - return getVisibilityOf(InstantiatedFrom); + return getVisibilityOf(InstantiatedFrom, kind); } return llvm::Optional(); @@ -858,8 +959,9 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, return LinkageInfo::internal(); LinkageInfo LV; - if (computation != LVOnlyTemplateArguments) { - if (llvm::Optional Vis = Function->getExplicitVisibility()) + if (!hasExplicitVisibilityAlready(computation)) { + if (llvm::Optional 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 Vis = Var->getExplicitVisibility()) + else if (!hasExplicitVisibilityAlready(computation)) { + if (llvm::Optional Vis + = getExplicitVisibility(Var, computation)) LV.mergeVisibility(*Vis, true); } diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 0c5d72f..73a69b1 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index f725706..5033b56 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/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/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index b212b3f..e12bbde 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -310,7 +310,7 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) { return; NamedDecl *ND = dyn_cast(D); - if (ND && ND->getExplicitVisibility()) + if (ND && ND->getExplicitVisibility(NamedDecl::VisibilityForValue)) return; VisStack *Stack = static_cast(VisContext); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7667681..189b3d9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1835,6 +1835,9 @@ bool Sema::mergeDeclAttribute(NamedDecl *D, InheritableAttr *Attr, else if (VisibilityAttr *VA = dyn_cast(Attr)) NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), AttrSpellingListIndex); + else if (TypeVisibilityAttr *VA = dyn_cast(Attr)) + NewAttr = mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), + AttrSpellingListIndex); else if (DLLImportAttr *ImportA = dyn_cast(Attr)) NewAttr = mergeDLLImportAttr(D, ImportA->getRange(), AttrSpellingListIndex); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 2f3634a..e8c42e6 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/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 +static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range, + typename T::VisibilityType value, + unsigned attrSpellingListIndex) { + T *existingAttr = D->getAttr(); + 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(); + } + return ::new (S.Context) T(range, S.Context, value, attrSpellingListIndex); +} + VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range, VisibilityAttr::VisibilityType Vis, unsigned AttrSpellingListIndex) { + return ::mergeVisibilityAttr(*this, D, Range, Vis, + AttrSpellingListIndex); +} + +TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range, + TypeVisibilityAttr::VisibilityType Vis, + unsigned AttrSpellingListIndex) { + return ::mergeVisibilityAttr(*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(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(); - 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(); + + // 'type_visibility' can only go on a type or namespace. + if (isTypeVisibility && + !(isa(D) || + isa(D) || + isa(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/clang/test/CodeGenCXX/type_visibility.cpp b/clang/test/CodeGenCXX/type_visibility.cpp new file mode 100644 index 0000000..5c45611 --- /dev/null +++ b/clang/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 struct TYPE_DEFAULT B { + virtual void foo() {} + }; + + template struct B; + // 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 struct TYPE_DEFAULT B { + virtual void foo() {} + }; + + template struct B; + // 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 struct B { + virtual void foo() {} + }; + + template struct B; + // 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 struct TYPE_DEFAULT B { + virtual void foo() {} + }; + + template struct B; + // 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 struct TYPE_HIDDEN B { + virtual void foo() {} + }; + + template struct B; + // 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/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp index 5564dc4..cfddc8c 100644 --- a/clang/test/CodeGenCXX/visibility.cpp +++ b/clang/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 struct B { + static DEFAULT void foo() {} + }; + + template class B; + // CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv() +} diff --git a/clang/test/Sema/attr-visibility.c b/clang/test/Sema/attr-visibility.c index 77bc39c..7f7fd54 100644 --- a/clang/test/Sema/attr-visibility.c +++ b/clang/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}}