]> granicus.if.org Git - clang/commitdiff
Ignore visibility from enclosing template arguments
authorJohn McCall <rjmccall@apple.com>
Thu, 21 Feb 2013 23:42:58 +0000 (23:42 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 21 Feb 2013 23:42:58 +0000 (23:42 +0000)
for explicit member specializations.

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

include/clang/AST/Decl.h
include/clang/AST/DeclCXX.h
include/clang/AST/DeclTemplate.h
lib/AST/Decl.cpp
lib/AST/DeclCXX.cpp
test/CodeGenCXX/visibility.cpp

index 614b2762e629194b479be562688cadf5766ac619..c10080366c1e5c4bb01e2e363af2e54a3f273ff5 100644 (file)
@@ -1919,7 +1919,9 @@ public:
   /// \brief If this function is an instantiation of a member function of a
   /// class template specialization, retrieves the member specialization
   /// information.
-  MemberSpecializationInfo *getMemberSpecializationInfo() const;
+  MemberSpecializationInfo *getMemberSpecializationInfo() const {
+    return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
+  }
 
   /// \brief Specify that this record is an instantiation of the
   /// member function FD.
index 1a37bd6a5d431d551c3c878a0f1cad70c3d24a5e..70d8c33608f7db3b24bafe7a10629491286a0ee2 100644 (file)
@@ -1253,7 +1253,9 @@ public:
   /// \brief If this class is an instantiation of a member class of a
   /// class template specialization, retrieves the member specialization
   /// information.
-  MemberSpecializationInfo *getMemberSpecializationInfo() const;
+  MemberSpecializationInfo *getMemberSpecializationInfo() const {
+    return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
+  }
 
   /// \brief Specify that this record is an instantiation of the
   /// member class RD.
index f50d774bf12f47dc02b6c503ee12d2f59ff50bc7..4b109ac8f8b99fb95f18ad720d10f1bb87d27062 100644 (file)
@@ -419,6 +419,10 @@ public:
     return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1);
   }
 
+  bool isExplicitSpecialization() const {
+    return getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+  }
+
   /// \brief Set the template specialization kind.
   void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
     assert(TSK != TSK_Undeclared &&
index 312426134fc18064f4bd3680f958af9eeb93d737..489a65d2023643f95d36459d5394d65d482fda47 100644 (file)
@@ -29,6 +29,7 @@
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/type_traits.h"
 #include <algorithm>
 
 using namespace clang;
@@ -83,29 +84,37 @@ using namespace clang;
 // and 'matcher' is a type only matters when looking for attributes
 // and settings from the immediate context.
 
+const unsigned IgnoreExplicitVisibilityBit = 2;
+
 /// 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 a normal LV computation for, ultimately, a type.
+  /// Do an LV computation for, ultimately, a type.
+  /// Visibility may be restricted by type visibility settings and
+  /// the visibility of template arguments.
   LVForType = NamedDecl::VisibilityForType,
 
-  /// Do a normal LV computation for, ultimately, a non-type declaration.
+  /// Do an LV computation for, ultimately, a non-type declaration.
+  /// Visibility may be restricted by value visibility settings and
+  /// the visibility of template arguments.
   LVForValue = NamedDecl::VisibilityForValue,
 
-  /// Do a normal LV computation for, ultimately, a type that already
-  /// has some sort of explicit visibility.
-  LVForExplicitType,
+  /// Do an LV computation for, ultimately, a type that already has
+  /// some sort of explicit visibility.  Visibility may only be
+  /// restricted by the visibility of template arguments.
+  LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit),
 
-  /// Do a normal LV computation for, ultimately, a non-type declaration
-  /// that already has some sort of explicit visibility.
-  LVForExplicitValue
+  /// Do an LV computation for, ultimately, a non-type declaration
+  /// that already has some sort of explicit visibility.  Visibility
+  /// may only be restricted by the visibility of template arguments.
+  LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit)
 };
 
 /// 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);
+  return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0);
 }
 
 /// Given an LVComputationKind, return one of the same type/value sort
@@ -113,7 +122,8 @@ static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
 static LVComputationKind
 withExplicitVisibilityAlready(LVComputationKind oldKind) {
   LVComputationKind newKind =
-    static_cast<LVComputationKind>(unsigned(oldKind) | 2);
+    static_cast<LVComputationKind>(unsigned(oldKind) |
+                                   IgnoreExplicitVisibilityBit);
   assert(oldKind != LVForType          || newKind == LVForExplicitType);
   assert(oldKind != LVForValue         || newKind == LVForExplicitValue);
   assert(oldKind != LVForExplicitType  || newKind == LVForExplicitType);
@@ -138,6 +148,26 @@ static bool usesTypeVisibility(const NamedDecl *D) {
          isa<ObjCInterfaceDecl>(D);
 }
 
+/// Does the given declaration have member specialization information,
+/// and if so, is it an explicit specialization?
+template <class T> static typename
+llvm::enable_if_c<!llvm::is_base_of<RedeclarableTemplateDecl, T>::value,
+                  bool>::type
+isExplicitMemberSpecialization(const T *D) {
+  if (const MemberSpecializationInfo *member =
+        D->getMemberSpecializationInfo()) {
+    return member->isExplicitSpecialization();
+  }
+  return false;
+}
+
+/// For templates, this question is easier: a member template can't be
+/// explicitly instantiated, so there's a single bit indicating whether
+/// or not this is an explicit member specialization.
+static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) {
+  return D->isMemberSpecialization();
+}
+
 /// Given a visibility attribute, return the explicit visibility
 /// associated with it.
 template <class T>
@@ -304,23 +334,33 @@ getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
   return getLVForTemplateArgumentList(TArgs.asArray());
 }
 
+static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
+                        const FunctionTemplateSpecializationInfo *specInfo) {
+  // Include visibility from the template parameters and arguments
+  // only if this is not an explicit instantiation or specialization
+  // with direct explicit visibility.  (Implicit instantiations won't
+  // have a direct attribute.)
+  if (!specInfo->isExplicitInstantiationOrSpecialization())
+    return true;
+
+  return !fn->hasAttr<VisibilityAttr>();
+}
+
 /// Merge in template-related linkage and visibility for the given
 /// function template specialization.
 ///
 /// We don't need a computation kind here because we can assume
 /// LVForValue.
-static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
-                      const FunctionTemplateSpecializationInfo *specInfo) {
-  bool hasExplicitVisibility = fn->hasAttr<VisibilityAttr>();
-  FunctionTemplateDecl *temp = specInfo->getTemplate();
-
-  // Include visibility from the template parameters and arguments
-  // only if this is not an explicit instantiation or specialization
-  // with direct explicit visibility.  (Implicit instantiations won't
-  // have a direct attribute.)
-  bool considerVisibility = !hasExplicitVisibility;
+///
+/// \return the computation to use for the parent
+static void
+mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
+                const FunctionTemplateSpecializationInfo *specInfo) {
+  bool considerVisibility =
+    shouldConsiderTemplateVisibility(fn, specInfo);
 
   // Merge information from the template parameters.
+  FunctionTemplateDecl *temp = specInfo->getTemplate();
   LinkageInfo tempLV =
     getLVForTemplateParameterList(temp->getTemplateParameters());
   LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
@@ -331,6 +371,25 @@ static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
   LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
 }
 
+/// Does the given declaration have a direct visibility attribute
+/// that would match the given rules?
+static bool hasDirectVisibilityAttribute(const NamedDecl *D,
+                                         LVComputationKind computation) {
+  switch (computation) {
+  case LVForType:
+  case LVForExplicitType:
+    if (D->hasAttr<TypeVisibilityAttr>())
+      return true;
+    // fallthrough
+  case LVForValue:
+  case LVForExplicitValue:
+    if (D->hasAttr<VisibilityAttr>())
+      return true;
+    return false;
+  }
+  llvm_unreachable("bad visibility computation kind");
+}
+
 /// Should we consider visibility associated with the template
 /// arguments and parameters of the given class template specialization?
 static bool shouldConsiderTemplateVisibility(
@@ -364,20 +423,7 @@ static bool shouldConsiderTemplateVisibility(
       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");
+  return !hasDirectVisibilityAttribute(spec, computation);
 }
 
 /// Merge in template-related linkage and visibility for the given
@@ -620,8 +666,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
         Function->getType()->getLinkage() == UniqueExternalLinkage)
       return LinkageInfo::uniqueExternal();
 
-    // Consider LV from the template and the template arguments unless
-    // this is an explicit specialization with a visibility attribute.
+    // Consider LV from the template and the template arguments.
+    // We're at file scope, so we do not need to worry about nested
+    // specializations.
     if (FunctionTemplateSpecializationInfo *specInfo
                                = Function->getTemplateSpecializationInfo()) {
       mergeTemplateLV(LV, Function, specInfo);
@@ -639,7 +686,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
       return LinkageInfo::none();
 
     // If this is a class template specialization, consider the
-    // linkage of the template and template arguments.
+    // linkage of the template and template arguments.  We're at file
+    // scope, so we do not need to worry about nested specializations.
     if (const ClassTemplateSpecializationDecl *spec
           = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
       mergeTemplateLV(LV, spec, computation);
@@ -718,20 +766,21 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
   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
-  // about the template instantiation. If the member has no visibility
-  // attributes, mergeWithMin behaves like merge, so in both cases mergeWithMin
-  // produces the desired result.
-  LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
-                        classComputation));
-  if (!isExternalLinkage(LV.linkage()))
+  LinkageInfo classLV =
+    getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
+  if (!isExternalLinkage(classLV.linkage()))
     return LinkageInfo::none();
 
   // If the class already has unique-external linkage, we can't improve.
-  if (LV.linkage() == UniqueExternalLinkage)
+  if (classLV.linkage() == UniqueExternalLinkage)
     return LinkageInfo::uniqueExternal();
 
+  // Otherwise, don't merge in classLV yet, because in certain cases
+  // we need to completely ignore the visibility from it.
+
+  // Specifically, if this decl exists and has an explicit attribute.
+  const NamedDecl *explicitSpecSuppressor = 0;
+
   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
     // If the type of the function uses a type with unique-external
     // linkage, it's not legally usable from outside this translation unit.
@@ -743,15 +792,29 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
     if (FunctionTemplateSpecializationInfo *spec
            = MD->getTemplateSpecializationInfo()) {
       mergeTemplateLV(LV, MD, spec);
+      if (spec->isExplicitSpecialization()) {
+        explicitSpecSuppressor = MD;
+      } else if (isExplicitMemberSpecialization(spec->getTemplate())) {
+        explicitSpecSuppressor = spec->getTemplate()->getTemplatedDecl();
+      }
+    } else if (isExplicitMemberSpecialization(MD)) {
+      explicitSpecSuppressor = MD;
     }
 
-    // Note that in contrast to basically every other situation, we
-    // *do* apply -fvisibility to method declarations.
-
   } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
     if (const ClassTemplateSpecializationDecl *spec
         = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
       mergeTemplateLV(LV, spec, computation);
+      if (spec->isExplicitSpecialization()) {
+        explicitSpecSuppressor = spec;
+      } else {
+        const ClassTemplateDecl *temp = spec->getSpecializedTemplate();
+        if (isExplicitMemberSpecialization(temp)) {
+          explicitSpecSuppressor = temp->getTemplatedDecl();
+        }
+      }
+    } else if (isExplicitMemberSpecialization(RD)) {
+      explicitSpecSuppressor = RD;
     }
 
   // Static data members.
@@ -759,21 +822,46 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
     // Modify the variable's linkage by its type, but ignore the
     // type's visibility unless it's a definition.
     LinkageInfo typeLV = getLVForType(VD->getType());
-    if (typeLV.linkage() != ExternalLinkage)
-      LV.mergeLinkage(UniqueExternalLinkage);
-    if (!LV.visibilityExplicit())
-      LV.mergeVisibility(typeLV);
+    LV.mergeMaybeWithVisibility(typeLV,
+                  !LV.visibilityExplicit() && !classLV.visibilityExplicit());
+
+    if (isExplicitMemberSpecialization(VD)) {
+      explicitSpecSuppressor = VD;
+    }
 
   // Template members.
   } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
     bool considerVisibility =
       (!LV.visibilityExplicit() &&
+       !classLV.visibilityExplicit() &&
        !hasExplicitVisibilityAlready(computation));
     LinkageInfo tempLV =
       getLVForTemplateParameterList(temp->getTemplateParameters());
     LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
+    if (const RedeclarableTemplateDecl *redeclTemp =
+          dyn_cast<RedeclarableTemplateDecl>(temp)) {
+      if (isExplicitMemberSpecialization(redeclTemp)) {
+        explicitSpecSuppressor = temp->getTemplatedDecl();
+      }
+    }
+  }
+
+  // We should never be looking for an attribute directly on a template.
+  assert(!explicitSpecSuppressor || !isa<TemplateDecl>(explicitSpecSuppressor));
+
+  // If this member is an explicit member specialization, and it has
+  // an explicit attribute, ignore visibility from the parent.
+  bool considerClassVisibility = true;
+  if (explicitSpecSuppressor &&
+      LV.visibilityExplicit() && // optimization: hasDVA() is true only if this
+      classLV.visibility() != DefaultVisibility &&
+      hasDirectVisibilityAttribute(explicitSpecSuppressor, computation)) {
+    considerClassVisibility = false;
   }
 
+  // Finally, merge in information from the class.
+  LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
   return LV;
 }
 
@@ -2344,10 +2432,6 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
   return 0;
 }
 
-MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
-  return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
-}
-
 void 
 FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
                                                FunctionDecl *FD,
index 4dd3694bc4e246828b5c2ff2acbe48067d3ef83a..9ed9b7d363f568e55d0480b359aa01bdeea7d1af 100644 (file)
@@ -1120,10 +1120,6 @@ CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
   return 0;
 }
 
-MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
-  return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
-}
-
 void 
 CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
                                              TemplateSpecializationKind TSK) {
index cfddc8c0c294f0276a297e6cc5e1048da4a25cb7..b9dec173017baddc863d278d879d93fe582099ca 100644 (file)
@@ -1182,3 +1182,48 @@ namespace test64 {
   template class B<A>;
   // CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
 }
+
+namespace test65 {
+  class HIDDEN A {};
+  template <class T> struct B {
+    static void func();
+    template <class U> static void funcT1();
+    template <class U> static void funcT2();
+    class Inner {};
+    template <class U> class InnerT {};
+  };
+  template <template <class T> class Temp> struct C {
+    static void foo() {}
+  };
+
+  // CHECK: define void @_ZN6test651BINS_1AEE4funcEv()
+  template <> DEFAULT void B<A>::func() {}
+
+  // CHECK: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv()
+  template <> template <> DEFAULT void B<A>::funcT2<A>() {}
+
+  // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv()
+  // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv()
+  template <> template <class T> DEFAULT void B<A>::funcT1() {}
+
+  // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv()
+  template <> struct DEFAULT B<A>::Inner {
+    static void foo() {}
+  };
+
+  // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv()
+  // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv()
+  template <> template <class U> struct DEFAULT B<A>::InnerT {
+    static void foo() {}
+  };
+
+  void test() {
+    B<A>::funcT1<int>();
+    B<A>::funcT1<A>();
+    B<A>::Inner::foo();
+    B<A>::InnerT<int>::foo();
+    B<A>::InnerT<A>::foo();
+  }
+
+  template class C<B<A>::InnerT>;
+}