]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/28407 (Issue with anonymous namespace)
authorJason Merrill <jason@redhat.com>
Thu, 20 Jul 2006 16:02:57 +0000 (12:02 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 20 Jul 2006 16:02:57 +0000 (12:02 -0400)
        PR c++/28407
        * cp/decl.c (grokvardecl): Set DECL_THIS_STATIC on file-scope
        const variables with implicit internal linkage.
        * cp/tree.c (decl_linkage): Only return lk_external if it's set.

        PR c++/28409
        * cp/decl2.c (constrain_visibility): Ignore the anonymous namespace
        for extern C decls.
        (VISIBILITY_STATIC): Rename to VISIBILITY_ANON.

        Don't override explicit visibility.
        * cp/decl2.c (constrain_visibility): Remove specified and reason
        parameters.  Don't touch decls that already have explicit visibility.
        (determine_visibility): Do copy DECL_VISIBILITY_SPECIFIED from
        template.
        (determine_visibility_from_class): Reverse sense of
        DECL_VISIBILITY_SPECIFIED test for target-specific visibility rules.
        (constrain_class_visibility): Only complain about member visibility
        if the member type is another class.  Don't change visibility of the
        current class.
        * tree.c (remove_attribute): New fn.
        * tree.h: Declare it.

From-SVN: r115622

14 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/doc/extend.texi
gcc/testsuite/g++.dg/ext/visibility/template6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/warn2.C
gcc/testsuite/g++.dg/ext/visibility/warn3.C
gcc/testsuite/g++.dg/lookup/anon5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/anon4.C [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 5d9e52ecac155282842b8a29035f3a67f2ef2fcd..7163d753157c7dce8aa889332ec5dd5e4b20652f 100644 (file)
@@ -1,3 +1,7 @@
+2006-07-20  Jason Merrill  <jason@redhat.com>
+
+       * tree.c (remove_attribute): New fn.
+
 2006-07-20  Paul Brook  <paul@codesourcery.com>
 
        PR 27363
index da9ab491c73e39cc12ef92b04c9a1a5f41eab523..309a060c3a2d0522c7cfaaa291805513297dc4ba 100644 (file)
@@ -1,3 +1,25 @@
+2006-07-20  Jason Merrill  <jason@redhat.com>
+
+       PR c++/28407
+       * decl.c (grokvardecl): Set DECL_THIS_STATIC on file-scope
+       const variables with implicit internal linkage.
+       * tree.c (decl_linkage): Only return lk_external if it's set.
+
+       PR c++/28409
+       * decl2.c (constrain_visibility): Ignore the anonymous namespace 
+       for extern "C" decls.
+       (VISIBILITY_STATIC): Rename to VISIBILITY_ANON.
+
+       * decl2.c (constrain_visibility): Remove specified and reason 
+       parameters.  Don't touch decls that already have explicit visibility.
+       (determine_visibility): Do copy DECL_VISIBILITY_SPECIFIED from 
+       template.
+       (determine_visibility_from_class): Reverse sense of 
+       DECL_VISIBILITY_SPECIFIED test for target-specific visibility rules.
+       (constrain_class_visibility): Only complain about member visibility
+       if the member type is another class.  Don't change visibility of the
+       current class.
+
 2006-07-19  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/28338
index 124e0448c638264c833284f02c62febd0c11792c..78838b06b2be767375e41a0b19eab0efae73a639 100644 (file)
@@ -5246,6 +5246,14 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
        {
          layout_var_decl (decl);
          maybe_commonize_var (decl);
+         if (DECL_NAMESPACE_SCOPE_P (decl) && !TREE_PUBLIC (decl)
+             && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl))
+           {
+             /* This is a const variable with implicit 'static'.  Set
+                DECL_THIS_STATIC so we can tell it from variables that are
+                !TREE_PUBLIC because of the anonymous namespace.  */
+             DECL_THIS_STATIC (decl) = 1;
+           }
        }
 
       make_rtl_for_nonlocal_decl (decl, init, asmspec);
index 385f8d96c8f3762d123feb67ee399a3c8abc435c..351de049f4c1075a5a5f4bb3f4909ad6ec65584c 100644 (file)
@@ -1536,7 +1536,7 @@ maybe_emit_vtables (tree ctype)
 /* A special return value from type_visibility meaning internal
    linkage.  */
 
-enum { VISIBILITY_STATIC = VISIBILITY_INTERNAL+1 };
+enum { VISIBILITY_ANON = VISIBILITY_INTERNAL+1 };
 
 /* walk_tree helper function for type_visibility.  */
 
@@ -1552,7 +1552,7 @@ min_vis_r (tree *tp, int *walk_subtrees, void *data)
     {
       if (!TREE_PUBLIC (TYPE_MAIN_DECL (*tp)))
        {
-         *vis_p = VISIBILITY_STATIC;
+         *vis_p = VISIBILITY_ANON;
          return *tp;
        }
       else if (CLASSTYPE_VISIBILITY (*tp) > *vis_p)
@@ -1572,29 +1572,28 @@ type_visibility (tree type)
   return vis;
 }
 
-/* Limit the visibility of DECL to VISIBILITY.  SPECIFIED is true if the
-   constraint comes from an attribute or pragma; REASON is the source of
-   the constraint.  */
+/* Limit the visibility of DECL to VISIBILITY, if not explicitly
+   specified (or if VISIBILITY is static).  */
 
 static bool
-constrain_visibility (tree decl, int visibility, bool specified,
-                     const char *reason)
+constrain_visibility (tree decl, int visibility)
 {
-  if (visibility == VISIBILITY_STATIC)
+  if (visibility == VISIBILITY_ANON)
     {
-      TREE_PUBLIC (decl) = 0;
-      DECL_INTERFACE_KNOWN (decl) = 1;
-      if (DECL_LANG_SPECIFIC (decl))
-       DECL_NOT_REALLY_EXTERN (decl) = 1;
+      /* extern "C" declarations aren't affected by the anonymous
+        namespace.  */
+      if (!DECL_EXTERN_C_P (decl))
+       {
+         TREE_PUBLIC (decl) = 0;
+         DECL_INTERFACE_KNOWN (decl) = 1;
+         if (DECL_LANG_SPECIFIC (decl))
+           DECL_NOT_REALLY_EXTERN (decl) = 1;
+       }
     }
-  else if (visibility > DECL_VISIBILITY (decl))
+  else if (visibility > DECL_VISIBILITY (decl)
+          && !DECL_VISIBILITY_SPECIFIED (decl))
     {
-      if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
-       warning (OPT_Wattributes, "%q+D: visibility attribute requests "
-                "greater visibility than its %s allows", decl, reason);
       DECL_VISIBILITY (decl) = visibility;
-      if (!DECL_VISIBILITY_SPECIFIED (decl))
-       DECL_VISIBILITY_SPECIFIED (decl) = specified;
       return true;
     }
   return false;
@@ -1627,13 +1626,13 @@ constrain_visibility_for_template (tree decl, tree targs)
              || TREE_CODE (arg) == FUNCTION_DECL)
            {
              if (! TREE_PUBLIC (arg))
-               vis = VISIBILITY_STATIC;
+               vis = VISIBILITY_ANON;
              else
                vis = DECL_VISIBILITY (arg);
            }
        }
       if (vis)
-       constrain_visibility (decl, vis, false, "template parameter");
+       constrain_visibility (decl, vis);
     }
 }
 
@@ -1735,8 +1734,7 @@ determine_visibility (tree decl)
        {
          /* tinfo visibility is based on the type it's for.  */
          constrain_visibility
-           (decl, type_visibility (TREE_TYPE (DECL_NAME (decl))),
-            false, "type");
+           (decl, type_visibility (TREE_TYPE (DECL_NAME (decl))));
        }
       else if (use_template)
        /* Template instantiations and specializations get visibility based
@@ -1752,43 +1750,42 @@ determine_visibility (tree decl)
 
   if (use_template)
     {
+      /* If the specialization doesn't specify visibility, use the
+        visibility from the template.  */
       tree tinfo = (TREE_CODE (decl) == TYPE_DECL
                    ? TYPE_TEMPLATE_INFO (TREE_TYPE (decl))
                    : DECL_TEMPLATE_INFO (decl));
       tree args = TI_ARGS (tinfo);
       int depth = TMPL_ARGS_DEPTH (args);
+      tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
 
-      /* If the template has explicit visibility and the specialization
-        doesn't, use the visibility from the template.  */
       if (!DECL_VISIBILITY_SPECIFIED (decl))
        {
-         tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
          DECL_VISIBILITY (decl) = DECL_VISIBILITY (pattern);
+         DECL_VISIBILITY_SPECIFIED (decl)
+           = DECL_VISIBILITY_SPECIFIED (pattern);
        }
 
       /* FIXME should TMPL_ARGS_DEPTH really return 1 for null input? */
       if (args && depth > template_class_depth (class_type))
-       /* Don't let it have more visibility than its template type
-          arguments.  */
+       /* Limit visibility based on its template arguments.  */
        constrain_visibility_for_template (decl, args);
     }
-  
+
   if (class_type)
     determine_visibility_from_class (decl, class_type);
 
   /* Don't let it have more visibility than its type.  */
   if (TREE_CODE (decl) != TYPE_DECL)
-    if (constrain_visibility (decl, type_visibility (TREE_TYPE (decl)),
-                             false, "type"))
+    if (constrain_visibility (decl, type_visibility (TREE_TYPE (decl))))
       warning (OPT_Wattributes, "\
-%q+D declared with greater visibility than its type",
+lowering visibility of %q+D to match its type",
               decl);
 
   if (decl_anon_ns_mem_p (decl))
     /* Names in an anonymous namespace get internal linkage.
        This might change once we implement export.  */
-    constrain_visibility (decl, VISIBILITY_STATIC,
-                         false, "namespace");
+    constrain_visibility (decl, VISIBILITY_ANON);
 }
 
 /* By default, static data members and function members receive
@@ -1806,11 +1803,13 @@ determine_visibility_from_class (tree decl, tree class_type)
       && TREE_CODE (decl) == FUNCTION_DECL
       && DECL_DECLARED_INLINE_P (decl))
     DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
-
-  /* The decl can't have more visibility than its class.  */
-  constrain_visibility (decl, CLASSTYPE_VISIBILITY (class_type),
-                       CLASSTYPE_VISIBILITY_SPECIFIED (class_type),
-                       "class");
+  else if (!DECL_VISIBILITY_SPECIFIED (decl))
+    {
+      /* Default to the class visibility.  */
+      DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
+      DECL_VISIBILITY_SPECIFIED (decl)
+       = CLASSTYPE_VISIBILITY_SPECIFIED (class_type);
+    }
 
   /* Give the target a chance to override the visibility associated
      with DECL.  */
@@ -1823,8 +1822,8 @@ determine_visibility_from_class (tree decl, tree class_type)
              && !DECL_CONSTRUCTION_VTABLE_P (decl)))
       && TREE_PUBLIC (decl)
       && !DECL_REALLY_EXTERN (decl)
-      && DECL_VISIBILITY_SPECIFIED (decl)
-      && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)))
+      && !DECL_VISIBILITY_SPECIFIED (decl)
+      && !CLASSTYPE_VISIBILITY_SPECIFIED (class_type))
     targetm.cxx.determine_class_data_visibility (decl);
 }
 
@@ -1834,25 +1833,50 @@ determine_visibility_from_class (tree decl, tree class_type)
 void
 constrain_class_visibility (tree type)
 {
-  tree decl = TYPE_MAIN_DECL (type);
-  tree binfo = TYPE_BINFO (type);
+  tree binfo;
   tree t;
   int i;
 
+  int vis = type_visibility (type);
+
+  if (vis == VISIBILITY_ANON)
+    return;
+
+  /* Don't warn about visibility if the class has explicit visibility.  */
+  if (CLASSTYPE_VISIBILITY_SPECIFIED (type))
+    vis = VISIBILITY_INTERNAL;
+
   for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
-    if (TREE_CODE (t) == FIELD_DECL)
-      if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)),
-                               false, "field type"))
-       warning (OPT_Wattributes, "\
+    if (TREE_CODE (t) == FIELD_DECL && TREE_TYPE (t) != error_mark_node)
+      {
+       int subvis = type_visibility (TREE_TYPE (t));
+
+       if (subvis == VISIBILITY_ANON)
+         warning (0, "\
+%qT has a field %qD whose type uses the anonymous namespace",
+                  type, t);
+       else if (vis < VISIBILITY_HIDDEN
+                && subvis >= VISIBILITY_HIDDEN)
+         warning (OPT_Wattributes, "\
 %qT declared with greater visibility than the type of its field %qD",
-                type, t);
+                  type, t);
+      }
 
+  binfo = TYPE_BINFO (type);
   for (i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i)
-    if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)),
-                             false, "base type"))
-      warning (OPT_Wattributes, "\
+    {
+      int subvis = type_visibility (TREE_TYPE (t));
+
+      if (subvis == VISIBILITY_ANON)
+       warning (0, "\
+%qT has a base %qT whose type uses the anonymous namespace",
+                type, TREE_TYPE (t));
+      else if (vis < VISIBILITY_HIDDEN
+              && subvis >= VISIBILITY_HIDDEN)
+       warning (OPT_Wattributes, "\
 %qT declared with greater visibility than its base %qT",
-              type, TREE_TYPE (t));
+                type, TREE_TYPE (t));
+    }
 }
 
 /* DECL is a FUNCTION_DECL or VAR_DECL.  If the object file linkage
index 7c099644d35a1f1689c5113dd08483324a8ffc95..f65d0ce25a6755923f6fd188fc4ace8c87d97818 100644 (file)
@@ -6589,7 +6589,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
        /* Possibly limit visibility based on template args.  */
        DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
-       DECL_VISIBILITY_SPECIFIED (r) = 0;
+       if (DECL_VISIBILITY_SPECIFIED (t))
+         {
+           DECL_VISIBILITY_SPECIFIED (r) = 0;
+           DECL_ATTRIBUTES (r)
+             = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
+         }
        determine_visibility (r);
       }
       break;
@@ -6791,7 +6796,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
          {
            /* Possibly limit visibility based on template args.  */
            DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
-           DECL_VISIBILITY_SPECIFIED (r) = 0;
+           if (DECL_VISIBILITY_SPECIFIED (t))
+             {
+               DECL_VISIBILITY_SPECIFIED (r) = 0;
+               DECL_ATTRIBUTES (r)
+                 = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
+             }
            determine_visibility (r);
          }
 
index c1c6719e8ef6bfe96e28ec8601aeaf835eb7cde1..0d42502da76410bea6309f8a63f358c4328e57a0 100644 (file)
@@ -2195,6 +2195,9 @@ decl_linkage (tree decl)
   if (TREE_PUBLIC (decl))
     return lk_external;
 
+  if (TREE_CODE (decl) == NAMESPACE_DECL)
+    return lk_external;
+
   /* Linkage of a CONST_DECL depends on the linkage of the enumeration
      type.  */
   if (TREE_CODE (decl) == CONST_DECL)
@@ -2214,6 +2217,14 @@ decl_linkage (tree decl)
   if (decl_function_context (decl))
     return lk_none;
 
+  /* Members of the anonymous namespace also have TREE_PUBLIC unset, but
+     are considered to have external linkage for language purposes.  DECLs
+     really meant to have internal linkage have DECL_THIS_STATIC set.  */
+  if (TREE_CODE (decl) == TYPE_DECL
+      || ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
+         && !DECL_THIS_STATIC (decl)))
+    return lk_external;
+
   /* Everything else has internal linkage.  */
   return lk_internal;
 }
index 7314e520ab5ea4577191f8ef4bd0ca47564d55fa..e6e5e1718c6e12f5f099449c10b78bbeb2de3466 100644 (file)
@@ -2413,16 +2413,16 @@ In C++, the visibility attribute applies to types as well as functions
 and objects, because in C++ types have linkage.  A class must not have
 greater visibility than its non-static data member types and bases,
 and class members default to the visibility of their class.  Also, a
-declaration must not have greater visibility than its type.
+declaration without explicit visibility is limited to the visibility
+of its type.
 
 In C++, you can mark member functions and static member variables of a
 class with the visibility attribute.  This is useful if if you know a
 particular method or static member variable should only be used from
 one shared object; then you can mark it hidden while the rest of the
 class has default visibility.  Care must be taken to avoid breaking
-the One Definition Rule; for example, it is not useful to mark a
-method which is defined inside a class definition as hidden without
-marking the whole class as hidden.
+the One Definition Rule; for example, it is usually not useful to mark
+an inline method as hidden without marking the whole class as hidden.
 
 A C++ namespace declaration can also have the visibility attribute.
 This attribute applies only to the particular namespace body, not to
@@ -2435,6 +2435,9 @@ restriction is implicitly propagated to the template instantiation.
 Otherwise, template instantiations and specializations default to the
 visibility of their template.
 
+If both the template and enclosing class have explicit visibility, the
+visibility from the template is used.
+
 @item warn_unused_result
 @cindex @code{warn_unused_result} attribute
 The @code{warn_unused_result} attribute causes a warning to be emitted
@@ -3668,6 +3671,13 @@ applied to class, struct, union and enum types.  Unlike other type
 attributes, the attribute must appear between the initial keyword and
 the name of the type; it cannot appear after the body of the type.
 
+Note that the type visibility is applied to vague linkage entities
+associated with the class (vtable, typeinfo node, etc.).  In
+particular, if a class is thrown as an exception in one shared object
+and caught in another, the class must have default visibility.
+Otherwise the two shared objects will be unable to use the same
+typeinfo node and exception handling will break.
+
 @subsection ARM Type Attributes
 
 On those ARM targets that support @code{dllimport} (such as Symbian
diff --git a/gcc/testsuite/g++.dg/ext/visibility/template6.C b/gcc/testsuite/g++.dg/ext/visibility/template6.C
new file mode 100644 (file)
index 0000000..7892a46
--- /dev/null
@@ -0,0 +1,17 @@
+// Test for explicit visibility taking precedence
+
+// { dg-require-visibility "" }
+// { dg-final { scan-not-hidden "_ZN1AIiE1fEv" } }
+
+template <class T> struct A
+{
+  // This attribute takes precedence over...
+  __attribute ((visibility ("default"))) void f ();
+};
+
+template <class T>
+void A<T>::f ()
+{ }
+
+// ...this attribute.
+template struct __attribute ((visibility ("hidden"))) A<int>;
index 1baf8b9e83ad981ae46bb679762bac4a692f3aa7..54354b52311cea5123887fd47c4423437c10e791 100644 (file)
@@ -14,6 +14,6 @@ struct B
   N::A a;
 };
 
-B f () { }                     // { dg-warning "visibility" }
+N::A f () { }                  // { dg-warning "visibility" }
 
 struct C: public N::A { };     // { dg-warning "visibility" }
index 705748ad7116a62f10d1b2f49cbe4c79af408872..de64217fd3b173b39bac15b18910028058494649 100644 (file)
@@ -1,11 +1,32 @@
-// Warn when a class member is specified to have greater visibility than
-// its class.
+// Tests for various visibility mismatch situations.
 
 // { dg-require-visibility "" }
 
+// { dg-final { scan-not-hidden "_ZN1A1fEv" } }
+
 struct __attribute ((visibility ("hidden"))) A
 {
-  __attribute ((visibility ("default"))) void f (); // { dg-warning "visibility" }
+  // This is OK, A::f gets default visibility.
+  __attribute ((visibility ("default"))) void f ();
 };
 
 void A::f() { }
+
+// This gets a warning; it should have explicit visibility of some sort.
+A* afactory1() { return new A; }       // { dg-warning "visibility" }
+
+// This is OK.
+__attribute ((visibility ("default"))) A*
+afactory2 () { return new A; }
+
+// This gets a warning.
+struct B
+{                              // { dg-warning "visibility" }
+  A a;
+};
+
+// This one has explicit visibility, so it doesn't get a warning.
+struct __attribute ((visibility ("default"))) C
+{
+  A a;
+};
diff --git a/gcc/testsuite/g++.dg/lookup/anon5.C b/gcc/testsuite/g++.dg/lookup/anon5.C
new file mode 100644 (file)
index 0000000..c3d36c2
--- /dev/null
@@ -0,0 +1,21 @@
+// PR c++/28409
+// shouldIbevisible should be emitted because it's an extern "C" decl with
+// external linkage, even though it's in the anonymous namespace.
+
+namespace
+{
+  extern "C" int shouldIbevisible()
+  {
+    return 0;
+  }
+}
+
+namespace t
+{
+  extern "C" int shouldIbevisible(void);
+}
+
+int main(void)
+{
+  return t::shouldIbevisible();
+}
diff --git a/gcc/testsuite/g++.dg/template/anon4.C b/gcc/testsuite/g++.dg/template/anon4.C
new file mode 100644 (file)
index 0000000..59bfee1
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/28407
+// A declaration in the anonymous namespace still has external linkage.
+
+template <int *P> class A { };
+namespace
+{
+  int i;
+}
+
+A<&i> a;
index 48f4614ceaeb949e8a0d3c4a8ac9d12e840f9420..dc78ad775af92523ec7a43795a8c4057cd2bc167 100644 (file)
@@ -3499,6 +3499,28 @@ lookup_attribute (const char *attr_name, tree list)
   return NULL_TREE;
 }
 
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+tree
+remove_attribute (const char *attr_name, tree list)
+{
+  tree *p;
+  size_t attr_len = strlen (attr_name);
+
+  for (p = &list; *p; )
+    {
+      tree l = *p;
+      gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE);
+      if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l)))
+       *p = TREE_CHAIN (l);
+      else
+       p = &TREE_CHAIN (l);
+    }
+
+  return list;
+}
+
 /* Return an attribute list that is the union of a1 and a2.  */
 
 tree
index dfea92adc1d99a17cc7671b8860631958d918a07..5e47dacc56dfddd71f51f1746acf8aeeadd309c3 100644 (file)
@@ -3696,6 +3696,11 @@ extern int is_attribute_p (const char *, tree);
 
 extern tree lookup_attribute (const char *, tree);
 
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+extern tree remove_attribute (const char *, tree);
+
 /* Given two attributes lists, return a list of their union.  */
 
 extern tree merge_attributes (tree, tree);