]> granicus.if.org Git - clang/commitdiff
Add a new 'type_visibility' attribute to allow users to
authorJohn McCall <rjmccall@apple.com>
Wed, 20 Feb 2013 01:54:26 +0000 (01:54 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 20 Feb 2013 01:54:26 +0000 (01:54 +0000)
control the visibility of a type for the purposes of RTTI
and template argument restrictions independently of how
visibility propagates to its non-type member declarations.

Also fix r175326 to not ignore template argument visibility
on a template explicit instantiation when a member has
an explicit attribute but the instantiation does not.

The type_visibility work is rdar://11880378

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175587 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/AST/Decl.h
include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/Decl.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Sema/SemaAttr.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGenCXX/type_visibility.cpp [new file with mode: 0644]
test/CodeGenCXX/visibility.cpp
test/Sema/attr-visibility.c

index e9643d2dc7da4f608db1466980958aaaa62cdfca..f6c912a38b6d9cbc284dfc5dc6ccd4adc4676b32 100644 (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.
index e9553677614c577b346fc4b472a3e51ab53c7315..70217d2beb0e9b02b8d7a80ec116c2e4da5befee 100644 (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];
index 2bacb2cff9743b6ccfa8385a2fd03528473ac949..b69bfda24241057602c8a21fe3691daecad5571a 100644 (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>;
index 07f035fa2431dd35ff21f4985a5f9eb06c2460f0..9d9014ab9ca1313f1df950231377b859e094a66b 100644 (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);
index 6e93dd6415d6e81d2259460e52590f2a9102b945..e29c5e3c9b0fdf41d226e682f3ee5d0cc696ccf4 100644 (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 non-type declaration.
+  LVForValue = NamedDecl::VisibilityForValue,
+
+  /// Do a normal LV computation for, ultimately, a type that already
+  /// has some sort of explicit visibility.
+  LVForExplicitType,
 
-  /// Do a normal LV computation for, ultimately, a value.
-  LVForValue
+  /// Do a normal LV computation for, ultimately, a non-type declaration
+  /// that already has some sort of explicit visibility.
+  LVForExplicitValue
 };
 
+/// Does this computation kind permit us to consider additional
+/// visibility settings from attributes and the like?
+static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
+  return ((unsigned(computation) & 2) != 0);
+}
+
+/// Given an LVComputationKind, return one of the same type/value sort
+/// that records that it already has explicit visibility.
+static LVComputationKind
+withExplicitVisibilityAlready(LVComputationKind oldKind) {
+  LVComputationKind newKind =
+    static_cast<LVComputationKind>(unsigned(oldKind) | 2);
+  assert(oldKind != LVForType          || newKind == LVForExplicitType);
+  assert(oldKind != LVForValue         || newKind == LVForExplicitValue);
+  assert(oldKind != LVForExplicitType  || newKind == LVForExplicitType);
+  assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue);
+  return newKind;
+}
+
+static llvm::Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
+                                                        LVComputationKind kind) {
+  assert(!hasExplicitVisibilityAlready(kind) &&
+         "asking for explicit visibility when we shouldn't be");
+  return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind);
+}
+
 typedef NamedDecl::LinkageInfo LinkageInfo;
 
 /// Is the given declaration a "type" or a "value" for the purposes of
@@ -85,18 +138,35 @@ static bool usesTypeVisibility(const NamedDecl *D) {
          isa<ObjCInterfaceDecl>(D);
 }
 
+/// Given a visibility attribute, return the explicit visibility
+/// associated with it.
+template <class T>
+static Visibility getVisibilityFromAttr(const T *attr) {
+  switch (attr->getVisibility()) {
+  case T::Default:
+    return DefaultVisibility;
+  case T::Hidden:
+    return HiddenVisibility;
+  case T::Protected:
+    return ProtectedVisibility;
+  }
+  llvm_unreachable("bad visibility kind");
+}
+
 /// Return the explicit visibility of the given declaration.
-static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
+static llvm::Optional<Visibility> getVisibilityOf(const NamedDecl *D,
+                                    NamedDecl::ExplicitVisibilityKind kind) {
+  // If we're ultimately computing the visibility of a type, look for
+  // a 'type_visibility' attribute before looking for 'visibility'.
+  if (kind == NamedDecl::VisibilityForType) {
+    if (const TypeVisibilityAttr *A = D->getAttr<TypeVisibilityAttr>()) {
+      return getVisibilityFromAttr(A);
+    }
+  }
+
   // If this declaration has an explicit visibility attribute, use it.
   if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) {
-    switch (A->getVisibility()) {
-    case VisibilityAttr::Default:
-      return DefaultVisibility;
-    case VisibilityAttr::Hidden:
-      return HiddenVisibility;
-    case VisibilityAttr::Protected:
-      return ProtectedVisibility;
-    }
+    return getVisibilityFromAttr(A);
   }
 
   // If we're on Mac OS X, an 'availability' for Mac OS X attribute
@@ -261,23 +331,19 @@ static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
   LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
 }
 
-/// Merge in template-related linkage and visibility for the given
-/// class template specialization.
-static void mergeTemplateLV(LinkageInfo &LV,
-                            const ClassTemplateSpecializationDecl *spec,
-                            LVComputationKind computation) {
-  // FIXME: type visibility
-  bool hasExplicitVisibility = spec->hasAttr<VisibilityAttr>();
-  ClassTemplateDecl *temp = spec->getSpecializedTemplate();
-
+/// Should we consider visibility associated with the template
+/// arguments and parameters of the given class template specialization?
+static bool shouldConsiderTemplateVisibility(
+                                 const ClassTemplateSpecializationDecl *spec,
+                                 LVComputationKind computation) {
   // Include visibility from the template parameters and arguments
   // only if this is not an explicit instantiation or specialization
   // with direct explicit visibility (and note that implicit
   // instantiations won't have a direct attribute).
   //
   // Furthermore, we want to ignore template parameters and arguments
-  // for an explicit instantiation or specialization when computing
-  // the visibility of a member thereof with explicit visibility.
+  // for an explicit specialization when computing the visibility of a
+  // member thereof with explicit visibility.
   //
   // This is a bit complex; let's unpack it.
   //
@@ -286,21 +352,49 @@ static void mergeTemplateLV(LinkageInfo &LV,
   // explicit visibility attribute, that must directly express the
   // user's intent, and we should honor it.  The same logic applies to
   // an explicit instantiation of a member of such a thing.
-  //
-  // That we're doing this for a member with explicit visibility
-  // is encoded by the computation kind being OnlyTemplateArguments.
-  bool considerVisibility =
-   !(hasExplicitVisibility ||
-     (computation == LVOnlyTemplateArguments &&
-      spec->isExplicitInstantiationOrSpecialization()));
+
+  // Fast path: if this is not an explicit instantiation or
+  // specialization, we always want to consider template-related
+  // visibility restrictions.
+  if (!spec->isExplicitInstantiationOrSpecialization())
+    return true;
+
+  // This is the 'member thereof' check.
+  if (spec->isExplicitSpecialization() &&
+      hasExplicitVisibilityAlready(computation))
+    return false;
+
+  // Otherwise, look to see if we have an attribute.
+  switch (computation) {
+  case LVForType:
+  case LVForExplicitType:
+    if (spec->hasAttr<TypeVisibilityAttr>())
+      return false;
+    // fallthrough
+  case LVForValue:
+  case LVForExplicitValue:
+    if (spec->hasAttr<VisibilityAttr>())
+      return false;
+    return true;
+  }
+  llvm_unreachable("bad visibility computation kind");
+}
+
+/// Merge in template-related linkage and visibility for the given
+/// class template specialization.
+static void mergeTemplateLV(LinkageInfo &LV,
+                            const ClassTemplateSpecializationDecl *spec,
+                            LVComputationKind computation) {
+  bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
 
   // Merge information from the template parameters, but ignore
   // visibility if we're only considering template arguments.
 
+  ClassTemplateDecl *temp = spec->getSpecializedTemplate();
   LinkageInfo tempLV =
     getLVForTemplateParameterList(temp->getTemplateParameters());
   LV.mergeMaybeWithVisibility(tempLV,
-               considerVisibility && computation != LVOnlyTemplateArguments);
+           considerVisibility && !hasExplicitVisibilityAlready(computation));
 
   // Merge information from the template arguments.  We ignore
   // template-argument visibility if we've got an explicit
@@ -422,8 +516,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
   //   external.
   LinkageInfo LV;
 
-  if (computation != LVOnlyTemplateArguments) {
-    if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+  if (!hasExplicitVisibilityAlready(computation)) {
+    if (llvm::Optional<Visibility> Vis
+          = getExplicitVisibility(D, computation)) {
       LV.mergeVisibility(*Vis, true);
     } else {
       // If we're declared in a namespace with a visibility attribute,
@@ -433,7 +528,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
            DC = DC->getParent()) {
         const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
         if (!ND) continue;
-        if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) {
+        if (llvm::Optional<Visibility> Vis
+              = getExplicitVisibility(ND, computation)) {
           LV.mergeVisibility(*Vis, true);
           break;
         }
@@ -562,7 +658,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
   //     - a template, unless it is a function template that has
   //       internal linkage (Clause 14);
   } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
-    bool considerVisibility = (computation != LVOnlyTemplateArguments);
+    bool considerVisibility = !hasExplicitVisibilityAlready(computation);
     LinkageInfo tempLV =
       getLVForTemplateParameterList(temp->getTemplateParameters());
     LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
@@ -605,8 +701,9 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
   LinkageInfo LV;
 
   // If we have an explicit visibility attribute, merge that in.
-  if (computation != LVOnlyTemplateArguments) {
-    if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility())
+  if (!hasExplicitVisibilityAlready(computation)) {
+    if (llvm::Optional<Visibility> Vis
+          = getExplicitVisibility(D, computation))
       LV.mergeVisibility(*Vis, true);
     // If we're paying attention to global visibility, apply
     // -finline-visibility-hidden if this is an inline method.
@@ -620,8 +717,9 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
   // If this class member has an explicit visibility attribute, the only
   // thing that can change its visibility is the template arguments, so
   // only look for them when processing the class.
-  LVComputationKind classComputation =
-    (LV.visibilityExplicit() ? LVOnlyTemplateArguments : computation);
+  LVComputationKind classComputation = computation;
+  if (LV.visibilityExplicit())
+    classComputation = withExplicitVisibilityAlready(computation);
 
   // If this member has an visibility attribute, ClassF will exclude
   // attributes on the class or command line options, keeping only information
@@ -672,7 +770,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
   // Template members.
   } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
     bool considerVisibility =
-      (!LV.visibilityExplicit() && computation != LVOnlyTemplateArguments);
+      (!LV.visibilityExplicit() &&
+       !hasExplicitVisibilityAlready(computation));
     LinkageInfo tempLV =
       getLVForTemplateParameterList(temp->getTemplateParameters());
     LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
@@ -730,10 +829,9 @@ Linkage NamedDecl::getLinkage() const {
   if (HasCachedLinkage)
     return Linkage(CachedLinkage);
 
-  // We don't care about visibility here, so suppress all the
-  // unnecessary explicit-visibility checks by asking for a
-  // template-argument-only analysis.
-  CachedLinkage = getLVForDecl(this, LVOnlyTemplateArguments).linkage();
+  // We don't care about visibility here, so ask for the cheapest
+  // possible visibility analysis.
+  CachedLinkage = getLVForDecl(this, LVForExplicitValue).linkage();
   HasCachedLinkage = 1;
 
 #ifndef NDEBUG
@@ -785,16 +883,17 @@ void NamedDecl::verifyLinkage() const {
   assert(!D || D->CachedLinkage == CachedLinkage);
 }
 
-llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
+llvm::Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
   // Use the most recent declaration of a variable.
   if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
-    if (llvm::Optional<Visibility> V = getVisibilityOf(Var))
+    if (llvm::Optional<Visibility> V = getVisibilityOf(Var, kind))
       return V;
 
     if (Var->isStaticDataMember()) {
       VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
       if (InstantiatedFrom)
-        return getVisibilityOf(InstantiatedFrom);
+        return getVisibilityOf(InstantiatedFrom, kind);
     }
 
     return llvm::Optional<Visibility>();
@@ -802,45 +901,47 @@ llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
   // Use the most recent declaration of a function, and also handle
   // function template specializations.
   if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
-    if (llvm::Optional<Visibility> V = getVisibilityOf(fn))
+    if (llvm::Optional<Visibility> V = getVisibilityOf(fn, kind))
       return V;
 
     // If the function is a specialization of a template with an
     // explicit visibility attribute, use that.
     if (FunctionTemplateSpecializationInfo *templateInfo
           = fn->getTemplateSpecializationInfo())
-      return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+      return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(),
+                             kind);
 
     // If the function is a member of a specialization of a class template
     // and the corresponding decl has explicit visibility, use that.
     FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
     if (InstantiatedFrom)
-      return getVisibilityOf(InstantiatedFrom);
+      return getVisibilityOf(InstantiatedFrom, kind);
 
     return llvm::Optional<Visibility>();
   }
 
   // Otherwise, just check the declaration itself first.
-  if (llvm::Optional<Visibility> V = getVisibilityOf(this))
+  if (llvm::Optional<Visibility> V = getVisibilityOf(this, kind))
     return V;
 
   // The visibility of a template is stored in the templated decl.
   if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
-    return getVisibilityOf(TD->getTemplatedDecl());
+    return getVisibilityOf(TD->getTemplatedDecl(), kind);
 
   // If there wasn't explicit visibility there, and this is a
   // specialization of a class template, check for visibility
   // on the pattern.
   if (const ClassTemplateSpecializationDecl *spec
         = dyn_cast<ClassTemplateSpecializationDecl>(this))
-    return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
+    return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
+                           kind);
 
   // If this is a member class of a specialization of a class template
   // and the corresponding decl has explicit visibility, use that.
   if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
     CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
     if (InstantiatedFrom)
-      return getVisibilityOf(InstantiatedFrom);
+      return getVisibilityOf(InstantiatedFrom, kind);
   }
 
   return llvm::Optional<Visibility>();
@@ -858,8 +959,9 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
       return LinkageInfo::internal();
 
     LinkageInfo LV;
-    if (computation != LVOnlyTemplateArguments) {
-      if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
+    if (!hasExplicitVisibilityAlready(computation)) {
+      if (llvm::Optional<Visibility> Vis
+            = getExplicitVisibility(Function, computation))
         LV.mergeVisibility(*Vis, true);
     }
 
@@ -884,8 +986,9 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
       LinkageInfo LV;
       if (Var->getStorageClass() == SC_PrivateExtern)
         LV.mergeVisibility(HiddenVisibility, true);
-      else if (computation != LVOnlyTemplateArguments) {
-        if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
+      else if (!hasExplicitVisibilityAlready(computation)) {
+        if (llvm::Optional<Visibility> Vis
+              = getExplicitVisibility(Var, computation))
           LV.mergeVisibility(*Vis, true);
       }
 
index 0c5d72fd8b1a41841b15f72d72e7c3ad786fa480..73a69b141df094cb6b51241c879cec33eb7a0de8 100644 (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()) {
index f725706f715553467e81dbd42d92a7a614880bba..5033b56d3a7057a2400f10a1a1bd5d2c76453de8 100644 (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()) {
index b212b3fee006603a5de334725a97609ada7fa731..e12bbde0d0dd440e3f1be02400a4f60000961ac2 100644 (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);
index 7667681c7968c3f5810196b805af913f8de70155..189b3d94e2bce0c47c7e65f69b82d15c2cb80f3d 100644 (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);
index 2f3634a278ca78878294fc0fc2dd4c41b72ebad2..e8c42e6f7c990dd138e6f5a3dea3bfce9604815c 100644 (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) {
+  return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis,
+                                               AttrSpellingListIndex);
+}
+
+TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
+                                      TypeVisibilityAttr::VisibilityType Vis,
+                                      unsigned AttrSpellingListIndex) {
+  return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, Range, Vis,
+                                                   AttrSpellingListIndex);
+}
+
+static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                 bool isTypeVisibility) {
+  // Visibility attributes don't mean anything on a typedef.
   if (isa<TypedefNameDecl>(D)) {
-    Diag(Range.getBegin(), diag::warn_attribute_ignored) << "visibility";
-    return NULL;
+    S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored)
+      << Attr.getName();
+    return;
   }
-  VisibilityAttr *ExistingAttr = D->getAttr<VisibilityAttr>();
-  if (ExistingAttr) {
-    VisibilityAttr::VisibilityType ExistingVis = ExistingAttr->getVisibility();
-    if (ExistingVis == Vis)
-      return NULL;
-    Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility);
-    Diag(Range.getBegin(), diag::note_previous_attribute);
-    D->dropAttr<VisibilityAttr>();
+
+  // 'type_visibility' can only go on a type or namespace.
+  if (isTypeVisibility &&
+      !(isa<TagDecl>(D) ||
+        isa<ObjCInterfaceDecl>(D) ||
+        isa<NamespaceDecl>(D))) {
+    S.Diag(Attr.getRange().getBegin(), diag::err_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedTypeOrNamespace;
+    return;
   }
-  return ::new (Context) VisibilityAttr(Range, Context, Vis,
-                                        AttrSpellingListIndex);
-}
 
-static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   // check the attribute arguments.
-  if(!checkAttributeNumArgs(S, Attr, 1))
+  if (!checkAttributeNumArgs(S, Attr, 1))
     return;
 
   Expr *Arg = Attr.getArg(0);
@@ -2285,7 +2314,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
 
   if (!Str || !Str->isAscii()) {
     S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-      << "visibility" << 1;
+      << (isTypeVisibility ? "type_visibility" : "visibility") << 1;
     return;
   }
 
@@ -2313,10 +2342,16 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   }
 
   unsigned Index = Attr.getAttributeSpellingListIndex();
-  VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type,
-                                                  Index);
-  if (NewAttr)
-    D->addAttr(NewAttr);
+  clang::Attr *newAttr;
+  if (isTypeVisibility) {
+    newAttr = S.mergeTypeVisibilityAttr(D, Attr.getRange(),
+                                    (TypeVisibilityAttr::VisibilityType) type,
+                                        Index);
+  } else {
+    newAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type, Index);
+  }
+  if (newAttr)
+    D->addAttr(newAttr);
 }
 
 static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
@@ -4693,7 +4728,12 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
     handleReturnsTwiceAttr(S, D, Attr);
     break;
   case AttributeList::AT_Used:        handleUsedAttr        (S, D, Attr); break;
-  case AttributeList::AT_Visibility:  handleVisibilityAttr  (S, D, Attr); break;
+  case AttributeList::AT_Visibility:
+    handleVisibilityAttr(S, D, Attr, false);
+    break;
+  case AttributeList::AT_TypeVisibility:
+    handleVisibilityAttr(S, D, Attr, true);
+    break;
   case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
     break;
   case AttributeList::AT_Weak:        handleWeakAttr        (S, D, Attr); break;
diff --git a/test/CodeGenCXX/type_visibility.cpp b/test/CodeGenCXX/type_visibility.cpp
new file mode 100644 (file)
index 0000000..5c45611
--- /dev/null
@@ -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
+}
+
index 5564dc401955978c9bd10d4d512bc3023659c0d3..cfddc8c0c294f0276a297e6cc5e1048da4a25cb7 100644 (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()
+}
index 77bc39c9e6e852af47ed185033957fe464d6e521..7f7fd546f0954cd8ca9d70688b58ccd271c9d38e 100644 (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}}