re PR c++/51930 (Explicitly instantiated template gets hidden visibility)
authorJason Merrill <jason@redhat.com>
Mon, 5 Mar 2012 18:08:56 +0000 (13:08 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 5 Mar 2012 18:08:56 +0000 (13:08 -0500)
PR c++/51930
* decl2.c (determine_visibility): Correct calculation of class
args depth.
* decl.c (check_tag_decl): Adjust warning.

From-SVN: r184946

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/visibility/template11.C [new file with mode: 0644]

index 71af797f77bed33c76800b51eb3c09d6bb43c004..450d469b4e18ab0e627dfb756288d5729e618823 100644 (file)
@@ -1,5 +1,10 @@
 2012-03-05  Jason Merrill  <jason@redhat.com>
 
+       PR c++/51930
+       * decl2.c (determine_visibility): Correct calculation of class
+       args depth.
+       * decl.c (check_tag_decl): Adjust warning.
+
        * method.c (synthesized_method_walk): Cleanups don't affect the EH
        spec either.
 
index c47f87c30324ce7844934521e121da24b96ab693..a18b312841d2549959245f65f8acee8140cf36f7 100644 (file)
@@ -4216,17 +4216,20 @@ check_tag_decl (cp_decl_specifier_seq *declspecs)
         error ("%<constexpr%> cannot be used for type declarations");
     }
 
-  if (declspecs->attributes)
+  if (declspecs->attributes && warn_attributes)
     {
-      location_t loc = input_location;
+      location_t loc;
       if (!CLASSTYPE_TEMPLATE_INSTANTIATION (declared_type))
-       /* For a non-template class, use the name location; for a template
-          class (an explicit instantiation), use the current location.  */
-       input_location = location_of (declared_type);
-      warning (0, "attribute ignored in declaration of %q#T", declared_type);
-      warning (0, "attribute for %q#T must follow the %qs keyword",
-              declared_type, class_key_or_enum_as_string (declared_type));
-      input_location = loc;
+       /* For a non-template class, use the name location.  */
+       loc = location_of (declared_type);
+      else
+       /* For a template class (an explicit instantiation), use the
+          current location.  */
+       loc = input_location;
+      warning_at (loc, OPT_Wattributes, "attribute ignored in declaration "
+                 "of %q#T", declared_type);
+      inform (loc, "attribute for %q#T must follow the %qs keyword",
+             declared_type, class_key_or_enum_as_string (declared_type));
     }
 
   return declared_type;
index bdc962abcf9be6b77e69201a9a1409a5f4a96ccd..7eccf6725469e854aa07246c49e25ad3e5559619 100644 (file)
@@ -2181,12 +2181,8 @@ determine_visibility (tree decl)
                      ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
                      : DECL_ATTRIBUTES (decl));
       
-      if (args != error_mark_node
-         /* Template argument visibility outweighs #pragma or namespace
-            visibility, but not an explicit attribute.  */
-         && !lookup_attribute ("visibility", attribs))
+      if (args != error_mark_node)
        {
-         int depth = TMPL_ARGS_DEPTH (args);
          tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
 
          if (!DECL_VISIBILITY_SPECIFIED (decl))
@@ -2202,10 +2198,31 @@ determine_visibility (tree decl)
                }
            }
 
-         /* FIXME should TMPL_ARGS_DEPTH really return 1 for null input? */
-         if (args && depth > template_class_depth (class_type))
-           /* Limit visibility based on its template arguments.  */
-           constrain_visibility_for_template (decl, args);
+         if (args
+             /* Template argument visibility outweighs #pragma or namespace
+                visibility, but not an explicit attribute.  */
+             && !lookup_attribute ("visibility", attribs))
+           {
+             int depth = TMPL_ARGS_DEPTH (args);
+             int class_depth = 0;
+             if (class_type && CLASSTYPE_TEMPLATE_INFO (class_type))
+               class_depth = TMPL_ARGS_DEPTH (CLASSTYPE_TI_ARGS (class_type));
+             if (DECL_VISIBILITY_SPECIFIED (decl))
+               {
+                 /* A class template member with explicit visibility
+                    overrides the class visibility, so we need to apply
+                    all the levels of template args directly.  */
+                 int i;
+                 for (i = 1; i <= depth; ++i)
+                   {
+                     tree lev = TMPL_ARGS_LEVEL (args, i);
+                     constrain_visibility_for_template (decl, lev);
+                   }
+               }
+             else if (depth > class_depth)
+               /* Limit visibility based on its template arguments.  */
+               constrain_visibility_for_template (decl, args);
+           }
        }
     }
 
index 5fbd14fcc8ca70fbe420e8d1d9b7511b1f29834a..5ea082ee29333115a594b479898778845da54a67 100644 (file)
@@ -1,5 +1,8 @@
 2012-03-05  Jason Merrill  <jason@redhat.com>
 
+       PR c++/51930
+       * g++.dg/ext/visibility/template11.C: New.
+
        * g++.dg/cpp0x/implicit13.C: New.
 
 2012-03-05  Jakub Jelinek  <jakub@redhat.com>
diff --git a/gcc/testsuite/g++.dg/ext/visibility/template11.C b/gcc/testsuite/g++.dg/ext/visibility/template11.C
new file mode 100644 (file)
index 0000000..fb47fe2
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/51930
+// { dg-require-visibility "" }
+// { dg-options "-fvisibility=hidden" }
+// { dg-final { scan-not-hidden "_ZN13template_testI4testE8functionEv" } }
+
+struct test { };
+
+template<typename T>
+struct template_test
+{
+  __attribute__((visibility("default")))
+  void function();
+};
+
+template<typename T>
+void template_test<T>::function() { }
+
+template
+struct __attribute__((visibility("default")))
+template_test<test>;