[cfe-commits] r151236 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/Decl.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/visibility.cpp

Rafael Espindola rafael.espindola at gmail.com
Wed Feb 22 20:17:32 PST 2012


Author: rafael
Date: Wed Feb 22 22:17:32 2012
New Revision: 151236

URL: http://llvm.org/viewvc/llvm-project?rev=151236&view=rev
Log:
Two fixes to how we compute visibility:

* Handle some situations where we should never make a decl more visible,
  even when merging in an explicit visibility.

* Handle attributes in members of classes that are explicitly specialized.

Thanks Nico for the report and testing, Eric for the initial review, and dgregor
for the awesome test27 :-)

Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CodeGenCXX/visibility.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=151236&r1=151235&r2=151236&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Feb 22 22:17:32 2012
@@ -251,6 +251,10 @@
       mergeLinkage(Other.linkage());
     }
 
+    // Merge the visibility V giving preference to explicit ones.
+    // This is used, for example, when merging the visibility of a class
+    // down to one of its members. If the member has no explicit visibility,
+    // the class visibility wins.
     void mergeVisibility(Visibility V, bool E = false) {
       // If one has explicit visibility and the other doesn't, keep the
       // explicit one.
@@ -262,14 +266,35 @@
       // If both are explicit or both are implicit, keep the minimum.
       setVisibility(minVisibility(visibility(), V), visibilityExplicit() || E);
     }
+    // Merge the visibility V, keeping the most restrictive one.
+    // This is used for cases like merging the visibility of a template
+    // argument to an instantiation. If we already have a hidden class,
+    // no argument should give it default visibility.
+    void mergeVisibilityWithMin(Visibility V, bool E = false) {
+      // Never increase the visibility
+      if (visibility() < V)
+        return;
+
+      // If this visibility is explicit, keep it.
+      if (visibilityExplicit() && !E)
+        return;
+      setVisibility(V, E);
+    }
     void mergeVisibility(LinkageInfo Other) {
       mergeVisibility(Other.visibility(), Other.visibilityExplicit());
     }
+    void mergeVisibilityWithMin(LinkageInfo Other) {
+      mergeVisibilityWithMin(Other.visibility(), Other.visibilityExplicit());
+    }
 
     void merge(LinkageInfo Other) {
       mergeLinkage(Other);
       mergeVisibility(Other);
     }
+    void mergeWithMin(LinkageInfo Other) {
+      mergeLinkage(Other);
+      mergeVisibilityWithMin(Other);
+    }
 
     friend LinkageInfo merge(LinkageInfo L, LinkageInfo R) {
       L.merge(R);

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=151236&r1=151235&r2=151236&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Feb 22 22:17:32 2012
@@ -176,9 +176,9 @@
       break;
 
     case TemplateArgument::Pack:
-      LV.merge(getLVForTemplateArgumentList(Args[I].pack_begin(),
-                                            Args[I].pack_size(),
-                                            F));
+      LV.mergeWithMin(getLVForTemplateArgumentList(Args[I].pack_begin(),
+                                                   Args[I].pack_size(),
+                                                   F));
       break;
     }
   }
@@ -279,6 +279,7 @@
   //   scope and no storage-class specifier, its linkage is
   //   external.
   LinkageInfo LV;
+  LV.mergeVisibility(Context.getLangOptions().getVisibilityMode());
 
   if (F.ConsiderVisibilityAttributes) {
     if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
@@ -413,7 +414,7 @@
         LV.merge(getLVForDecl(specInfo->getTemplate(),
                               F.onlyTemplateVisibility()));
         const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
-        LV.merge(getLVForTemplateArgumentList(templateArgs, F));
+        LV.mergeWithMin(getLVForTemplateArgumentList(templateArgs, F));
       }
     }
 
@@ -439,7 +440,7 @@
 
         // The arguments at which the template was instantiated.
         const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
-        LV.merge(getLVForTemplateArgumentList(TemplateArgs, F));
+        LV.mergeWithMin(getLVForTemplateArgumentList(TemplateArgs, F));
       }
     }
 
@@ -482,11 +483,6 @@
   if (LV.linkage() != ExternalLinkage)
     return LinkageInfo(LV.linkage(), DefaultVisibility, false);
 
-  // If we didn't end up with hidden visibility, consider attributes
-  // and -fvisibility.
-  if (F.ConsiderGlobalVisibility)
-    LV.mergeVisibility(Context.getLangOptions().getVisibilityMode());
-
   return LV;
 }
 
@@ -503,6 +499,7 @@
     return LinkageInfo::none();
 
   LinkageInfo LV;
+  LV.mergeVisibility(D->getASTContext().getLangOptions().getVisibilityMode());
 
   // The flags we're going to use to compute the class's visibility.
   LVFlags ClassF = F;
@@ -544,7 +541,8 @@
     if (FunctionTemplateSpecializationInfo *spec
            = MD->getTemplateSpecializationInfo()) {
       if (shouldConsiderTemplateLV(MD, spec)) {
-        LV.merge(getLVForTemplateArgumentList(*spec->TemplateArguments, F));
+        LV.mergeWithMin(getLVForTemplateArgumentList(*spec->TemplateArguments,
+                                                     F));
         if (F.ConsiderTemplateParameterTypes)
           LV.merge(getLVForTemplateParameterList(
                               spec->getTemplate()->getTemplateParameters()));
@@ -583,7 +581,8 @@
       if (shouldConsiderTemplateLV(spec)) {
         // Merge template argument/parameter information for member
         // class template specializations.
-        LV.merge(getLVForTemplateArgumentList(spec->getTemplateArgs(), F));
+        LV.mergeWithMin(getLVForTemplateArgumentList(spec->getTemplateArgs(),
+                                                     F));
       if (F.ConsiderTemplateParameterTypes)
         LV.merge(getLVForTemplateParameterList(
                     spec->getSpecializedTemplate()->getTemplateParameters()));
@@ -601,13 +600,6 @@
       LV.mergeVisibility(TypeLV.visibility(), TypeLV.visibilityExplicit());
   }
 
-  F.ConsiderGlobalVisibility &= !LV.visibilityExplicit();
-
-  // Apply -fvisibility if desired.
-  if (F.ConsiderGlobalVisibility && LV.visibility() != HiddenVisibility) {
-    LV.mergeVisibility(D->getASTContext().getLangOptions().getVisibilityMode());
-  }
-
   return LV;
 }
 
@@ -697,6 +689,12 @@
           = fn->getTemplateSpecializationInfo())
       return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
 
+    // 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 llvm::Optional<Visibility>();
   }
 
@@ -711,6 +709,14 @@
         = dyn_cast<ClassTemplateSpecializationDecl>(this))
     return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
 
+  // 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 llvm::Optional<Visibility>();
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=151236&r1=151235&r2=151236&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Feb 22 22:17:32 2012
@@ -5350,6 +5350,7 @@
 /// \brief Strips various properties off an implicit instantiation
 /// that has just been explicitly specialized.
 static void StripImplicitInstantiation(NamedDecl *D) {
+  // FIXME: "make check" is clean if the call to dropAttrs() is commented out.
   D->dropAttrs();
 
   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {

Modified: cfe/trunk/test/CodeGenCXX/visibility.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/visibility.cpp?rev=151236&r1=151235&r2=151236&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/visibility.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/visibility.cpp Wed Feb 22 22:17:32 2012
@@ -5,6 +5,21 @@
 #define PROTECTED __attribute__((visibility("protected")))
 #define DEFAULT __attribute__((visibility("default")))
 
+namespace test25 {
+  template<typename T>
+  struct X {
+    template<typename U>
+    struct definition {
+    };
+  };
+
+  class DEFAULT A { };
+
+  X<int>::definition<A> a;
+  // CHECK: @_ZN6test251aE = global
+  // CHECK-HIDDEN: @_ZN6test251aE = hidden global
+}
+
 // CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10
 // CHECK: @_ZN5Test71aE = hidden global
 // CHECK: @_ZN5Test71bE = global
@@ -22,6 +37,26 @@
 // CHECK-HIDDEN: @_ZN6Test143varE = external global
 // CHECK: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
 // CHECK-HIDDEN: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
+
+namespace test27 {
+  template<typename T>
+  class C {
+    class __attribute__((visibility("default"))) D {
+      void f();
+    };
+  };
+
+  template<>
+  class C<int>::D {
+    virtual void g();
+  };
+
+  void C<int>::D::g() {
+  }
+  // CHECK: _ZTVN6test271CIiE1DE = unnamed_addr constant
+  // CHECK-HIDDEN: _ZTVN6test271CIiE1DE = unnamed_addr constant
+}
+
 // CHECK: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr global
 // CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64
 // CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global
@@ -500,3 +535,65 @@
   // CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
   // CHECK-HIDDEN: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
 }
+
+namespace test23 {
+  // Having a template argument that is explicitly visible should not make
+  // the template instantiation visible.
+  template <typename T>
+  struct X {
+    static void f() {
+    }
+  };
+
+  class DEFAULT A;
+
+  void g() {
+    X<A> y;
+    y.f();
+  }
+  // CHECK: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv
+  // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv
+}
+
+namespace PR12001 {
+  template <typename P1>
+  void Bind(const P1& p1) {
+  }
+
+  class DEFAULT Version { };
+
+  void f() {
+    Bind(Version());
+  }
+  // CHECK: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+  // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+}
+
+namespace test24 {
+  class DEFAULT A { };
+
+  struct S {
+    template <typename T>
+    void mem() {}
+  };
+
+  void test() {
+    S s;
+    s.mem<A>();
+  }
+  // CHECK: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv
+  // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv
+}
+
+namespace test26 {
+  template<typename T>
+  class C {
+    __attribute__((visibility("default")))  void f();
+  };
+
+  template<>
+  void C<int>::f() { }
+
+  // CHECK: define void @_ZN6test261CIiE1fEv
+  // CHECK-HIDDEN: define void @_ZN6test261CIiE1fEv
+}





More information about the cfe-commits mailing list