re PR c++/9283 (__attribute__((visibility ("hidden"))) not supported for class/struct)
authorNiall Douglas <s_fsfeurope2@nedprod.com>
Sun, 25 Jul 2004 22:52:22 +0000 (22:52 +0000)
committerGiovanni Bajo <giovannibajo@gcc.gnu.org>
Sun, 25 Jul 2004 22:52:22 +0000 (22:52 +0000)
PR c++/9283
PR c++/15000
* c-common.c (c_common_attribute_table): Allow
handle_visibility_attribute to be called for types.
(handle_visibility_attribute) When given a type, set the visibility
bits on the TYPE_NAME.  When given a decl, don't set no_add_attrs
so that we can check later whether the attribute was present. Added
warning if attribute applied to non class type.
* c-decl.c (diagnose_mismatched_decls): Updated rules for merging
decls and checking that they are consistent.
* common.opt: Added -fvisibility.
* c.opt, c-opts.c: Added -fvisibility-inlines-hidden.
* c-pragma.h, c-pragma.c: Added handle_pragma_visibility().
* flags.h, tree.h: Added assorted support defines for overall patch
* opts.c: Added parsing support for -fvisibility.
* tree.c (build_decl): Set visibility for all decls to be whatever
is in force at that time.
* varasm.c (default_binds_local_p_1): Reworked logic determining
when to make a symbol locally bound.
* doc/invoke.texi: Added documentation for -fvisibility and
-fvisibility-inlines-hidden.

PR c++/15000
PR c++/9283
* class.c (check_field_decls): Apply hidden visibility if
-fvisibility-inlines-hidden and inlined unless otherwise specified
(build_vtable): Set vtable visibility to class visibility.
(check_field_decls): Default static member visibility to class
visibility.
(check_methods): Default method visibility to class visibility.
* cp-tree.h: Added CLASSTYPE_VISIBILITY and
CLASSTYPE_VISIBILITY_SPECIFIED macro.
* decl.c (duplicate_decls): New logic for merging definition decls
with declaration decls. Added ignore & warning when non default
applied to global operator new or delete.
* method.c, optimize.c, rtti.c: Added setting of VISIBILITY_SPECIFIED
wherever VISIBILITY was changed
* rtti.c (get_tinfo_decl): Set typeinfo visibility to class
visibility.
(tinfo_base_init): Set typeinfo name visibility to class visibility.

PR c++/9283
PR c++/15000
* gcc.dg/visibility-9.c, gcc.dg/visibility-a.c: New tests.
* g++.dg/ext/visibility/: New directory.
* g++.dg/ext/visibility-1.C, g++.dg/ext/visibility-2.C
g++.dg/ext/visibility-3.C, g++.dg/ext/visibility-4.C,
g++.dg/ext/visibility-5.C, g++.dg/ext/visibility-6.C,
g++.dg/ext/visibility-7.C: Move to g++.dg/ext/visibility/.
* g++.dg/ext/visibility/fvisibility.C,
g++.dg/ext/visibility/fvisibility-inlines-hidden.C,
g++.dg/ext/visibility/fvisibility-override1.C
g++.dg/ext/visibility/fvisibility-override2.C
g++.dg/ext/visibility/memfuncts.C
g++.dg/ext/visibility/noPLT.C
g++.dg/ext/visibility/pragma.C
g++.dg/ext/visibility/pragma-override1.C
g++.dg/ext/visibility/pragma-override2.C
g++.dg/ext/visibility/staticmemfuncts.C
g++.dg/ext/visibility/virtual.C: New tests.

Co-Authored-By: Brian Ryner <bryner@brianryner.com>
From-SVN: r85167

49 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/c-opts.c
gcc/c-pragma.c
gcc/c-pragma.h
gcc/c.opt
gcc/common.opt
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/method.c
gcc/cp/optimize.c
gcc/cp/rtti.c
gcc/doc/invoke.texi
gcc/flags.h
gcc/opts.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/visibility-1.C [deleted file]
gcc/testsuite/g++.dg/ext/visibility-2.C [deleted file]
gcc/testsuite/g++.dg/ext/visibility-3.C [deleted file]
gcc/testsuite/g++.dg/ext/visibility-4.C [deleted file]
gcc/testsuite/g++.dg/ext/visibility-5.C [deleted file]
gcc/testsuite/g++.dg/ext/visibility-6.C [deleted file]
gcc/testsuite/g++.dg/ext/visibility-7.C [deleted file]
gcc/testsuite/g++.dg/ext/visibility/fvisibility-inlines-hidden.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/fvisibility-override1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/fvisibility.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/memfuncts.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/noPLT.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/pragma.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/staticmemfuncts.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/virtual.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/visibility-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/visibility-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/visibility-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/visibility-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/visibility-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/visibility-6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/visibility-7.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/visibility-9.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/visibility-a.c [new file with mode: 0644]
gcc/tree.c
gcc/tree.h
gcc/varasm.c

index 6815008cab5ec3205132a1758869d5f9725a91e1..6c69579d8cc897a6ecbac716affe3a3f2bef495f 100644 (file)
@@ -1,3 +1,28 @@
+2004-07-26  Niall Douglas  <s_fsfeurope2@nedprod.com>\r
+           Brian Ryner  <bryner@brianryner.com>\r
+\r
+       PR c++/9283\r
+       PR c++/15000\r
+       * c-common.c (c_common_attribute_table): Allow\r
+       handle_visibility_attribute to be called for types.\r
+       (handle_visibility_attribute) When given a type, set the visibility\r
+       bits on the TYPE_NAME.  When given a decl, don't set no_add_attrs\r
+       so that we can check later whether the attribute was present. Added\r
+       warning if attribute applied to non class type.\r
+       * c-decl.c (diagnose_mismatched_decls): Updated rules for merging\r
+       decls and checking that they are consistent.\r
+       * common.opt: Added -fvisibility.\r
+       * c.opt, c-opts.c: Added -fvisibility-inlines-hidden.\r
+       * c-pragma.h, c-pragma.c: Added handle_pragma_visibility().\r
+       * flags.h, tree.h: Added assorted support defines for overall patch\r
+       * opts.c: Added parsing support for -fvisibility.\r
+       * tree.c (build_decl): Set visibility for all decls to be whatever\r
+       is in force at that time.\r
+       * varasm.c (default_binds_local_p_1): Reworked logic determining\r
+       when to make a symbol locally bound.\r
+       * doc/invoke.texi: Added documentation for -fvisibility and\r
+       -fvisibility-inlines-hidden.\r
+\r
 2004-07-25  Bernardo Innocenti  <bernie@develer.com>
 
        * basic-block.h (reorder_block_def): Rename to reorder_block_def_p.
index ddd8e8766b0769763f04fa3cdf4bf12cb586db79..2fe696d676cd8cb8b7f82e32aab18563d7e5f6d8 100644 (file)
@@ -616,7 +616,7 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_deprecated_attribute },
   { "vector_size",           1, 1, false, true, false,
                              handle_vector_size_attribute },
-  { "visibility",            1, 1, true,  false, false,
+  { "visibility",            1, 1, false, false, false,
                              handle_visibility_attribute },
   { "tls_model",             1, 1, true,  false, false,
                              handle_tls_model_attribute },
@@ -4563,7 +4563,16 @@ handle_visibility_attribute (tree *node, tree name, tree args,
 
   *no_add_attrs = true;
 
-  if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
+  if (TYPE_P (*node))
+    {
+      if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
+       {
+         warning ("`%s' attribute ignored on non-class types",
+                  IDENTIFIER_POINTER (name));
+         return NULL_TREE;
+       }
+    }
+  else if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
     {
       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
       return NULL_TREE;
@@ -4574,6 +4583,14 @@ handle_visibility_attribute (tree *node, tree name, tree args,
       error ("visibility arg not a string");
       return NULL_TREE;
     }
+  
+  /*  If this is a type, set the visibility on the type decl.  */
+  if (TYPE_P (decl))
+    {
+      decl = TYPE_NAME (decl);
+      if (! decl)
+        return NULL_TREE;
+    }
 
   if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
     DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
@@ -4585,6 +4602,14 @@ handle_visibility_attribute (tree *node, tree name, tree args,
     DECL_VISIBILITY (decl) = VISIBILITY_PROTECTED;
   else
     error ("visibility arg must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+  /* For decls only, go ahead and attach the attribute to the node as well.
+     This is needed so we can determine whether we have VISIBILITY_DEFAULT
+     because the visibility was not specified, or because it was explicitly
+     overridden from the class visibility.  */
+  if (DECL_P (*node))
+    *no_add_attrs = false;
 
   return NULL_TREE;
 }
index 47cfd5cc24f78c9327693b30a0568062a64d5bec..e4c022ff25e954b526fce32c44a6f6cf8b8324d6 100644 (file)
@@ -1367,9 +1367,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
     }
 
   /* warnings */
-  /* All decls must agree on a non-default visibility.  */
-  if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT
-      && DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT
+  /* All decls must agree on a visibility.  */
+  if (DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl)
       && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
     {
       warning ("%Jredeclaration of '%D' with different visibility "
@@ -1570,9 +1569,12 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
      Currently, it can only be defined in the prototype.  */
   COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
 
-  /* If either declaration has a nondefault visibility, use it.  */
-  if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT)
-    DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
+  /* Use visibility of whichever declaration had it specified */
+  if (DECL_VISIBILITY_SPECIFIED (olddecl))
+    {
+      DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
+      DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
+    }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
index 2b4ab9f76dc9b370e7d1812422f8470b7e056683..faa6023b1b9bf1b61c2190eb03404ab9ad76acbe 100644 (file)
@@ -764,6 +764,10 @@ c_common_handle_option (size_t scode, const char *arg, int value)
     case OPT_fuse_cxa_atexit:
       flag_use_cxa_atexit = value;
       break;
+      
+    case OPT_fvisibility_inlines_hidden:
+      visibility_options.inlines_hidden = value;
+      break;
 
     case OPT_fweak:
       flag_weak = value;
index 563e2d7abdc120dc6d289de9cb2cdd42c4267358..0bf2f1231bc22589fb629cd06f91674fa0cefa68 100644 (file)
@@ -566,6 +566,86 @@ maybe_apply_renaming_pragma (tree decl, tree asmname)
   return 0;
 }
 
+
+#ifdef HANDLE_PRAGMA_VISIBILITY
+static void handle_pragma_visibility (cpp_reader *);
+
+/* Sets the default visibility for symbols to something other than that
+   specified on the command line.  */
+static void
+handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED)
+{ /* Form is #pragma GCC visibility push(hidden)|pop */
+  static int visstack [16], visidx;
+  tree x;
+  enum cpp_ttype token;
+  enum { bad, push, pop } action = bad;
+  token = c_lex (&x);
+  if (token == CPP_NAME)
+    {
+      const char *op = IDENTIFIER_POINTER (x);
+      if (!strcmp (op, "push"))
+        action = push;
+      else if (!strcmp (op, "pop"))
+        action = pop;
+    }
+  if (bad == action)
+    GCC_BAD ("#pragma GCC visibility must be followed by push or pop");
+  else
+    {
+      if (pop == action)
+        {
+          if (!visidx)
+            {
+              GCC_BAD ("No matching push for '#pragma GCC visibility pop'");
+            }
+          else
+            {
+              default_visibility = visstack[--visidx];
+              visibility_options.inpragma = (visidx>0);
+            }
+        }
+      else
+        {
+          if (c_lex (&x) != CPP_OPEN_PAREN)
+            GCC_BAD ("missing '(' after '#pragma GCC visibility push' - ignored");
+          token = c_lex (&x);
+          if (token != CPP_NAME)
+            {
+              GCC_BAD ("malformed #pragma GCC visibility push");
+            }
+          else if (visidx >= 16)
+            {
+              GCC_BAD ("No more than sixteen #pragma GCC visibility pushes allowed at once");
+            }
+          else
+            {
+              const char *str = IDENTIFIER_POINTER (x);
+              visstack[visidx++] = default_visibility;
+              if (!strcmp (str, "default"))
+                default_visibility = VISIBILITY_DEFAULT;
+              else if (!strcmp (str, "internal"))
+                default_visibility = VISIBILITY_INTERNAL;
+              else if (!strcmp (str, "hidden"))
+                default_visibility = VISIBILITY_HIDDEN;  
+              else if (!strcmp (str, "protected"))
+                default_visibility = VISIBILITY_PROTECTED;
+              else
+                {
+                  GCC_BAD ("#pragma GCC visibility push() must specify default, internal, hidden or protected");
+                }
+              visibility_options.inpragma = 1;
+            }
+          if (c_lex (&x) != CPP_CLOSE_PAREN)
+            GCC_BAD ("missing '(' after '#pragma GCC visibility push' - ignored");
+        }
+    }
+  if (c_lex (&x) != CPP_EOF)
+    warning ("junk at end of '#pragma GCC visibility'");
+}
+
+#endif
+
 /* Front-end wrapper for pragma registration to avoid dragging
    cpplib.h in almost everywhere.  */
 void
@@ -585,6 +665,9 @@ init_pragma (void)
 #ifdef HANDLE_PRAGMA_WEAK
   c_register_pragma (0, "weak", handle_pragma_weak);
 #endif
+#ifdef HANDLE_PRAGMA_VISIBILITY
+  c_register_pragma ("GCC", "visibility", handle_pragma_visibility);
+#endif
 
   c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname);
   c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
index 6bb10f3af704f9e94d531192413a0ada06d34f0e..64c83ff0c5a22d19050834fc1d56c31d487222e9 100644 (file)
@@ -44,6 +44,11 @@ extern struct cpp_reader* parse_in;
 #define HANDLE_PRAGMA_PACK 1
 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
 
+/* It's safe to always leave visibility pragma enabled as if
+   visibility is not supported on the host OS platform the
+   statements are ignored.  */
+#define HANDLE_PRAGMA_VISIBILITY 1
+
 extern void init_pragma (void);
 
 /* Front-end wrapper for pragma registration to avoid dragging
index 32e600b637d7c6327a72bc72a3468ab71f2d99f9..2f85c8cb35f03960cd5933c978c19d6976a2c536 100644 (file)
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -683,6 +683,10 @@ fuse-cxa-atexit
 C++ ObjC++
 Use __cxa_atexit to register destructors
 
+fvisibility-inlines-hidden
+C++
+Marks all inlined methods as having hidden visibility
+
 fvtable-gc
 C++ ObjC++
 Discard unused virtual functions
index fd3df7c7da35e1f06c3c1570dc4c655cd9a94616..24310f1932275d15141c575658795d3a64c5f020 100644 (file)
@@ -913,6 +913,11 @@ fverbose-asm
 Common Report Var(flag_verbose_asm)
 Add extra commentary to assembler output
 
+fvisibility=
+Common Joined RejectNegative
+-fvisibility=[default|internal|hidden|protected]       Set the default symbol visibility
+
+
 fvpt
 Common Report Var(flag_value_profile_transformations)
 Use expression value profiles in optimizations
index bbcd038f2ac75ca370d75c393cc4c9e094fe2e12..182f373a26af7ad920348edf25938642e614ac3b 100644 (file)
@@ -1,3 +1,25 @@
+2004-07-26  Niall Douglas  <s_fsfeurope2@nedprod.com>\r
+           Brian Ryner  <bryner@brianryner.com>\r
+\r
+       PR c++/15000\r
+       PR c++/9283\r
+       * class.c (check_field_decls): Apply hidden visibility if\r
+       -fvisibility-inlines-hidden and inlined unless otherwise specified\r
+       (build_vtable): Set vtable visibility to class visibility.\r
+       (check_field_decls): Default static member visibility to class\r
+       visibility.\r
+       (check_methods): Default method visibility to class visibility.\r
+       * cp-tree.h: Added CLASSTYPE_VISIBILITY and\r
+       CLASSTYPE_VISIBILITY_SPECIFIED macro.\r
+       * decl.c (duplicate_decls): New logic for merging definition decls\r
+       with declaration decls. Added ignore & warning when non default\r
+       applied to global operator new or delete.\r
+       * method.c, optimize.c, rtti.c: Added setting of VISIBILITY_SPECIFIED\r
+       wherever VISIBILITY was changed\r
+       * rtti.c (get_tinfo_decl): Set typeinfo visibility to class\r
+       visibility.\r
+       (tinfo_base_init): Set typeinfo name visibility to class visibility.\r
+
 2004-07-25  Bernardo Innocenti  <bernie@develer.com>
 
        * decl.c: Rename all identifiers named `class' to `cl'.
index 6c0988c09098bc34965bd632b1824d99607af060..f30d519fe8f8545a67a9c60a76916dcf5e411d0a 100644 (file)
@@ -607,6 +607,10 @@ build_vtable (tree class_type, tree name, tree vtable_type)
   DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
                           DECL_ALIGN (decl));
 
+  /* The vtable's visibility is the class visibility.  There is no way
+     to override the visibility for just the vtable. */
+  DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
+  DECL_VISIBILITY_SPECIFIED (decl) = CLASSTYPE_VISIBILITY_SPECIFIED (class_type);
   import_export_vtable (decl, class_type, 0);
 
   return decl;
@@ -2914,7 +2918,25 @@ check_field_decls (tree t, tree *access_decls,
        continue;
          
       if (TREE_CODE (x) == CONST_DECL || TREE_CODE (x) == VAR_DECL)
-       continue;
+       {
+         /* Apply the class's visibility attribute to static members
+            which do not have a visibility attribute. */
+         if (! lookup_attribute ("visibility", DECL_ATTRIBUTES (x)))
+            {
+              if (visibility_options.inlines_hidden && DECL_INLINE (x))
+                {
+                  DECL_VISIBILITY (x) = VISIBILITY_HIDDEN;
+                  DECL_VISIBILITY_SPECIFIED (x) = 1;
+                }
+              else
+                {
+                  DECL_VISIBILITY (x) = CLASSTYPE_VISIBILITY (current_class_type);
+                  DECL_VISIBILITY_SPECIFIED (x) = CLASSTYPE_VISIBILITY_SPECIFIED (current_class_type);
+                }
+            }
+
+         continue;
+       }
 
       /* Now it can only be a FIELD_DECL.  */
 
@@ -3669,6 +3691,22 @@ check_methods (tree t)
       check_for_override (x, t);
       if (DECL_PURE_VIRTUAL_P (x) && ! DECL_VINDEX (x))
        cp_error_at ("initializer specified for non-virtual method `%D'", x);
+      /* Apply the class's visibility attribute to methods which do
+        not have a visibility attribute. */
+      if (! lookup_attribute ("visibility", DECL_ATTRIBUTES (x)))
+        {
+          if (visibility_options.inlines_hidden && DECL_INLINE (x))
+            {
+              DECL_VISIBILITY (x) = VISIBILITY_HIDDEN;
+              DECL_VISIBILITY_SPECIFIED (x) = 1;
+            }
+          else
+            {
+              DECL_VISIBILITY (x) = CLASSTYPE_VISIBILITY (current_class_type);
+              DECL_VISIBILITY_SPECIFIED (x) = CLASSTYPE_VISIBILITY_SPECIFIED (current_class_type);
+            }
+        }
 
       /* The name of the field is the original field name
         Save this in auxiliary field for later overloading.  */
@@ -7763,3 +7801,4 @@ cp_fold_obj_type_ref (tree ref, tree known_type)
 
   return build_address (fndecl);
 }
+
index bcbf793e27a509c161dcd5797f5635993e4664c2..e7eed5e44377855d6d2959c0f050e3f999f9d83f 100644 (file)
@@ -931,7 +931,12 @@ enum languages { lang_c, lang_cplusplus, lang_java };
 #define PUBLICLY_UNIQUELY_DERIVED_P(PARENT, TYPE) \
   (lookup_base ((TYPE), (PARENT),  ba_not_special | ba_quiet, NULL) \
    != NULL_TREE)
-\f
+
+/* Gives the visibility specification for a class type.  */
+#define CLASSTYPE_VISIBILITY(TYPE)             DECL_VISIBILITY (TYPE_NAME (TYPE))
+#define CLASSTYPE_VISIBILITY_SPECIFIED(TYPE)   DECL_VISIBILITY_SPECIFIED (TYPE_NAME (TYPE))
+
+
 /* This is a few header flags for 'struct lang_type'.  Actually,
    all but the first are used only for lang_type_class; they
    are put in this structure to save space.  */
index 17b391bd49b614fe4648fe3a0f2fa2b967708932..2a9e61fdd390877c341af47906697b9232c232e1 100644 (file)
@@ -1866,17 +1866,34 @@ duplicate_decls (tree newdecl, tree olddecl)
   DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
   COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
 
-  /* If either declaration has a nondefault visibility, use it.  */
-  if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT)
+  /* Warn about conflicting visibility specifications.  */
+  if (DECL_VISIBILITY_SPECIFIED (olddecl) && DECL_VISIBILITY_SPECIFIED (newdecl)
+      && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
+    {
+      warning ("%J'%D': visibility attribute ignored because it",
+        newdecl, newdecl);
+      warning ("%Jconflicts with previous declaration here", olddecl);
+    }
+  /* Choose the declaration which specified visibility.  */
+  if (DECL_VISIBILITY_SPECIFIED (olddecl))
     {
-      if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT
-         && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
-       {
-         warning ("%J'%D': visibility attribute ignored because it",
-                  newdecl, newdecl);
-         warning ("%Jconflicts with previous declaration here", olddecl);
-       }
       DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
+      DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
+    }
+  /* If it's a definition of a global operator new or operator
+     delete, it must be default visibility.  */
+  if (NEW_DELETE_OPNAME_P (DECL_NAME (newdecl)) && DECL_INITIAL (newdecl) != NULL_TREE)
+    {
+      if (!DECL_FUNCTION_MEMBER_P (newdecl) && VISIBILITY_DEFAULT != DECL_VISIBILITY (newdecl))
+        {
+          warning ("%J`%D': ignoring non-default symbol",
+            newdecl, newdecl);
+          warning ("%Jvisibility on global operator new or delete", newdecl);
+          DECL_VISIBILITY (olddecl) = VISIBILITY_DEFAULT;
+          DECL_VISIBILITY_SPECIFIED (olddecl) = 1;
+          DECL_VISIBILITY (newdecl) = VISIBILITY_DEFAULT;
+          DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
+        }
     }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
index d2d52bbf0b9cefaacbf8330f9e169e70c3742f66..07fbacf266a42d5f7594bab95c8aba213e029559 100644 (file)
@@ -368,6 +368,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
      rewrite.  */
   TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
   DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
+  DECL_VISIBILITY_SPECIFIED (thunk_fndecl) = DECL_VISIBILITY_SPECIFIED (function);
   if (flag_weak && TREE_PUBLIC (thunk_fndecl))
     comdat_linkage (thunk_fndecl);
 
index 8a3ebe6ebbeb012c9162bc187aadd49eec4d88d4..000d6cc4c27981f63bd81830918171cd549781ed 100644 (file)
@@ -112,6 +112,7 @@ maybe_clone_body (tree fn)
       DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
       TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
       DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
+      DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);
 
       /* Adjust the parameter names and locations.  */
       parm = DECL_ARGUMENTS (fn);
index b1ae3dda80fbf7e884a84841eb801a3de480d422..7332a9a69140c92f28767d7f0940a00095e96446 100644 (file)
@@ -360,7 +360,11 @@ get_tinfo_decl (tree type)
       pushdecl_top_level_and_finish (d, NULL_TREE);
 
       if (CLASS_TYPE_P (type))
-       CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
+       {
+         CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
+         DECL_VISIBILITY (d) = CLASSTYPE_VISIBILITY (type);
+         DECL_VISIBILITY_SPECIFIED (d) = CLASSTYPE_VISIBILITY_SPECIFIED (type);
+       }
 
       /* Remember the type it is for.  */
       TREE_TYPE (name) = type;
@@ -758,6 +762,11 @@ tinfo_base_init (tree desc, tree target)
     TREE_STATIC (name_decl) = 1;
     DECL_EXTERNAL (name_decl) = 0;
     TREE_PUBLIC (name_decl) = 1;
+    if (CLASS_TYPE_P (target))
+      {
+        DECL_VISIBILITY (name_decl) = CLASSTYPE_VISIBILITY (target);
+        DECL_VISIBILITY_SPECIFIED (name_decl) = CLASSTYPE_VISIBILITY_SPECIFIED (target);
+      }
     import_export_tinfo (name_decl, target, typeinfo_in_lib_p (target));
     /* External name of the string containing the type's name has a
        special name.  */
index efd20a97eed6ff0c2315da8423d1214fc284dde1..2dc69698307a5657f4818a9d3f3408e7776bb538 100644 (file)
@@ -182,7 +182,8 @@ in the following sections.
 -fno-optional-diags  -fpermissive @gol
 -frepo  -fno-rtti  -fstats  -ftemplate-depth-@var{n} @gol
 -fuse-cxa-atexit  -fno-weak  -nostdinc++ @gol
--fno-default-inline  -Wabi  -Wctor-dtor-privacy @gol
+-fno-default-inline  -fvisibility-inlines-hidden @gol
+-Wabi  -Wctor-dtor-privacy @gol
 -Wnon-virtual-dtor  -Wreorder @gol
 -Weffc++  -Wno-deprecated @gol
 -Wno-non-template-friend  -Wold-style-cast @gol
@@ -696,7 +697,8 @@ See S/390 and zSeries Options.
 -fargument-alias  -fargument-noalias @gol
 -fargument-noalias-global  -fleading-underscore @gol
 -ftls-model=@var{model} @gol
--ftrapv  -fwrapv  -fbounds-check}
+-ftrapv  -fwrapv  -fbounds-check @gol
+-fvisibility}
 @end table
 
 @menu
@@ -1457,6 +1459,20 @@ This option is required for fully standards-compliant handling of static
 destructors, but will only work if your C library supports
 @code{__cxa_atexit}.
 
+@item -fvisibility-inlines-hidden
+@opindex fvisibility-inlines-hidden
+Causes all inlined methods to be marked with
+@code{__attribute__ ((visibility ("hidden")))} so that they do not
+appear in the export table of a DSO and do not require a PLT indirection
+when used within the DSO. Enabling this option can have a dramatic effect
+on load and link times of a DSO as it massively reduces the size of the
+dynamic export table when the library makes heavy use of templates. While
+it can cause bloating through duplication of code within each DSO where
+it is used, often the wastage is less than the considerable space occupied
+by a long symbol name in the export table which is typical when using
+templates and namespaces. For even more savings, combine with the
+@code{-fvisibility=hidden} switch.
+
 @item -fno-weak
 @opindex fno-weak
 Do not use weak symbol support, even if it is provided by the linker.
@@ -11630,6 +11646,54 @@ The @var{model} argument should be one of @code{global-dynamic},
 
 The default without @option{-fpic} is @code{initial-exec}; with
 @option{-fpic} the default is @code{global-dynamic}.
+
+@item -fvisibility=@var{default|internal|hidden|protected}
+@opindex fvisibility
+Set the default ELF image symbol visibility to the specified option - all
+symbols will be marked with this unless overrided within the code.
+Using this feature can very substantially improve linking and
+load times of shared object libraries, produce more optimised
+code, provide near-perfect API export and prevent symbol clashes.
+It is @strong{strongly} recommended that you use this in any shared objects
+you distribute.
+     
+Despite the nomenclature, @code{default} always means public ie;
+available to be linked against from outside the shared object.
+@code{protected} and @code{internal} are pretty useless in real-world
+usage so the only other commonly used option will be @code{hidden}.
+The default if -fvisibility isn't specified is @code{default} ie; make every
+symbol public - this causes the same behaviour as previous versions of
+GCC.
+     
+A good explanation of the benefits offered by ensuring ELF
+symbols have the correct visibility is given by ``How To Write
+Shared Libraries'' by Ulrich Drepper (which can be found at
+@w{@uref{http://people.redhat.com/~drepper/}}) - however a superior
+solution made possible by this option to marking things hidden when
+the default is public is to make the default hidden and mark things
+public. This is the norm with DLL's on Windows and with @option{-fvisibility=hidden}
+and @code{__attribute__ ((visibility("default")))} instead of
+@code{__declspec(dllexport)} you get almost identical semantics with
+identical syntax. This is a great boon to those working with
+cross-platform projects.
+
+For those adding visibility support to existing code, you may find
+@samp{#pragma GCC visibility} of use. This works by you enclosing
+the declarations you wish to set visibility for with (for example)
+@samp{#pragma GCC visibility push(hidden)} and
+@samp{#pragma GCC visibility pop}. These can be nested up to sixteen
+times. Bear in mind that symbol visibility should be viewed @strong{as
+part of the API interface contract} and thus all new code should
+always specify visibility when it is not the default ie; declarations
+only for use within the local DSO should @strong{always} be marked explicitly
+as hidden as so to avoid PLT indirection overheads - making this
+abundantly clear also aids readability and self-documentation of the code.
+Note that due to ISO C++ specification requirements, operator new and
+operator delete must always be of default visibility.
+
+An overview of these techniques, their benefits and how to use them
+is at @w{@uref{http://www.nedprod.com/programs/gccvisibility.html}}.
+
 @end table
 
 @c man end
index 1b4a10a7346091fa1537adaf16af45221c2fa943..542a53fea3897cd95b6fc198b6237c188489256c 100644 (file)
@@ -59,6 +59,30 @@ extern enum debug_info_level debug_info_level;
    debugging information.  */
 extern bool use_gnu_debug_info_extensions;
 
+/* Enumerate visibility settings.  */
+#ifndef SYMBOL_VISIBILITY_DEFINED
+#define SYMBOL_VISIBILITY_DEFINED
+enum symbol_visibility
+{
+  VISIBILITY_DEFAULT,
+  VISIBILITY_INTERNAL,
+  VISIBILITY_HIDDEN,
+  VISIBILITY_PROTECTED
+};
+#endif
+
+/* The default visibility for all symbols (unless overridden).  */
+extern enum symbol_visibility default_visibility;
+
+struct visibility_flags
+{
+  unsigned inpragma : 1;       /* True when in #pragma GCC visibility.  */
+  unsigned inlines_hidden : 1; /* True when -finlineshidden in effect.  */
+};
+
+/* Global visibility options.  */
+extern struct visibility_flags visibility_options;
+
 /* Nonzero means do optimizations.  -opt.  */
 
 extern int optimize;
index cb9b5f9360323cb02fb3606ccb2bee3f53726271..01297b0ee53bb2ad882402d1160215a84942c5ef 100644 (file)
@@ -76,6 +76,12 @@ enum debug_info_level debug_info_level = DINFO_LEVEL_NONE;
    write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG.  */
 bool use_gnu_debug_info_extensions;
 
+/* The default visibility for all symbols (unless overridden) */
+enum symbol_visibility default_visibility = VISIBILITY_DEFAULT;
+
+/* Global visibility options.  */
+struct visibility_flags visibility_options;
+
 /* Columns of --help display.  */
 static unsigned int columns = 80;
 
@@ -826,6 +832,21 @@ common_handle_option (size_t scode, const char *arg, int value)
       flag_profile_values_set = true;
       break;
 
+    case OPT_fvisibility_:
+      {
+        if (!strcmp(arg, "default"))
+          default_visibility = VISIBILITY_DEFAULT;
+        else if (!strcmp(arg, "internal"))
+          default_visibility = VISIBILITY_INTERNAL;
+        else if (!strcmp(arg, "hidden"))
+          default_visibility = VISIBILITY_HIDDEN;
+        else if (!strcmp(arg, "protected"))
+          default_visibility = VISIBILITY_PROTECTED;
+        else
+          error ("unrecognised visibility value \"%s\"", arg);
+      }
+      break;
+
     case OPT_fvpt:
       flag_value_profile_transformations_set = value;
       break;
index 2d51e4aed098358bf94c00d69e910cb683bac200..4be1b7e9d1d5f1553468616cb0018335e298c988 100644 (file)
@@ -1,3 +1,26 @@
+2004-07-26  Niall Douglas  <s_fsfeurope2@nedprod.com>\r
+           Brian Ryner  <bryner@brianryner.com>\r
+\r
+       PR c++/9283\r
+       PR c++/15000\r
+       * gcc.dg/visibility-9.c, gcc.dg/visibility-a.c: New tests.
+       * g++.dg/ext/visibility/: New directory.
+       * g++.dg/ext/visibility-1.C, g++.dg/ext/visibility-2.C
+       g++.dg/ext/visibility-3.C, g++.dg/ext/visibility-4.C,
+       g++.dg/ext/visibility-5.C, g++.dg/ext/visibility-6.C,
+       g++.dg/ext/visibility-7.C: Move to g++.dg/ext/visibility/.
+       * g++.dg/ext/visibility/fvisibility.C,
+       g++.dg/ext/visibility/fvisibility-inlines-hidden.C,
+       g++.dg/ext/visibility/fvisibility-override1.C\r
+       g++.dg/ext/visibility/fvisibility-override2.C\r
+       g++.dg/ext/visibility/memfuncts.C\r
+       g++.dg/ext/visibility/noPLT.C\r
+       g++.dg/ext/visibility/pragma.C\r
+       g++.dg/ext/visibility/pragma-override1.C\r
+       g++.dg/ext/visibility/pragma-override2.C\r
+       g++.dg/ext/visibility/staticmemfuncts.C\r
+       g++.dg/ext/visibility/virtual.C: New tests.
+
 2004-07-25  Joseph S. Myers  <jsm@polyomino.org.uk>
 
        PR c/15360
diff --git a/gcc/testsuite/g++.dg/ext/visibility-1.C b/gcc/testsuite/g++.dg/ext/visibility-1.C
deleted file mode 100644 (file)
index d579eb2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/* Test visibility attribute on function definition. */
-/* { dg-do compile { target *86-*-linux* } } */
-/* { dg-final { scan-assembler "\\.hidden.*_Z3foov" } } */
-
-void
-__attribute__((visibility ("hidden")))
-foo()
-{ }
diff --git a/gcc/testsuite/g++.dg/ext/visibility-2.C b/gcc/testsuite/g++.dg/ext/visibility-2.C
deleted file mode 100644 (file)
index 89e853c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* Test that visibility attribute on declaration extends to definition. */
-/* { dg-do compile { target *86-*-linux* } } */
-/* { dg-final { scan-assembler "\\.hidden.*_Z3foov" } } */
-
-void __attribute__((visibility ("hidden"))) foo();
-
-void foo() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility-3.C b/gcc/testsuite/g++.dg/ext/visibility-3.C
deleted file mode 100644 (file)
index d0cc891..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* Test visibility attribute on forward declaration of global variable */
-/* { dg-do compile { target *86-*-linux* } } */
-/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
-
-int
-__attribute__((visibility ("hidden")))
-xyzzy = 5;
diff --git a/gcc/testsuite/g++.dg/ext/visibility-4.C b/gcc/testsuite/g++.dg/ext/visibility-4.C
deleted file mode 100644 (file)
index d217bc9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/* Test visibility attribute on forward declaration of global variable */
-/* { dg-do compile { target *86-*-linux* } } */
-/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
-
-extern int __attribute__ ((visibility ("hidden")))
-xyzzy;
-
-int xyzzy = 5;
diff --git a/gcc/testsuite/g++.dg/ext/visibility-5.C b/gcc/testsuite/g++.dg/ext/visibility-5.C
deleted file mode 100644 (file)
index 9cdc802..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* Test visibility attribute on definition of a function that has
-   already had a forward declaration. */
-/* { dg-do compile { target *86-*-linux* } } */
-/* { dg-final { scan-assembler "\\.hidden.*_Z3foov" } } */
-
-void foo();
-
-void 
- __attribute__((visibility ("hidden")))
-foo() 
-{ }
diff --git a/gcc/testsuite/g++.dg/ext/visibility-6.C b/gcc/testsuite/g++.dg/ext/visibility-6.C
deleted file mode 100644 (file)
index 6e8f0ce..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* Test visibility attribute on definition of global variable that has
-   already had a forward declaration. */
-/* { dg-do compile { target *86-*-linux* } } */
-/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
-
-extern int xyzzy;
-
-int 
-__attribute__((visibility ("hidden")))
-xyzzy = 5;
diff --git a/gcc/testsuite/g++.dg/ext/visibility-7.C b/gcc/testsuite/g++.dg/ext/visibility-7.C
deleted file mode 100644 (file)
index 40acb72..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* Test warning from conflicting visibility specifications. */
-/* { dg-do compile { target *86-*-linux* } } */
-/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
-
-extern int 
-__attribute__((visibility ("hidden")))
-xyzzy; /* { dg-warning "previous declaration here" "" } */
-
-int 
-__attribute__((visibility ("protected")))
-xyzzy = 5; /* { dg-warning "visibility attribute ignored" "" } */
diff --git a/gcc/testsuite/g++.dg/ext/visibility/fvisibility-inlines-hidden.C b/gcc/testsuite/g++.dg/ext/visibility/fvisibility-inlines-hidden.C
new file mode 100644 (file)
index 0000000..4b61022
--- /dev/null
@@ -0,0 +1,18 @@
+/* Test that -fvisibility-inlines-hidden affects class members. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-options "-fvisibility-inlines-hidden" } */
+/* { dg-final { scan-assembler "\\.hidden.*Foo.methodEv" } } */
+
+class Foo
+{
+public:
+  void method() { }
+};
+
+int main(void)
+{
+  Foo f;
+  f.method();
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override1.C b/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override1.C
new file mode 100644 (file)
index 0000000..67d5ef0
--- /dev/null
@@ -0,0 +1,12 @@
+/* Test that -fvisibility does not override class member specific settings. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-options "-fvisibility=hidden" } */
+/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" } } */
+
+class __attribute__ ((visibility ("internal"))) Foo
+{
+  void method();
+};
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C b/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C
new file mode 100644 (file)
index 0000000..a0a2df5
--- /dev/null
@@ -0,0 +1,12 @@
+/* Test that -fvisibility does not override class member specific settings. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-options "-fvisibility=hidden" } */
+/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" } } */
+
+class Foo
+{
+  __attribute__ ((visibility ("internal"))) void method();
+};
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/fvisibility.C b/gcc/testsuite/g++.dg/ext/visibility/fvisibility.C
new file mode 100644 (file)
index 0000000..fd2c7e2
--- /dev/null
@@ -0,0 +1,12 @@
+/* Test that -fvisibility affects class members. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-options "-fvisibility=hidden" } */
+/* { dg-final { scan-assembler "\\.hidden.*Foo.methodEv" } } */
+
+class Foo
+{
+  void method();
+};
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/memfuncts.C b/gcc/testsuite/g++.dg/ext/visibility/memfuncts.C
new file mode 100644 (file)
index 0000000..19a5c9d
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test that setting visibility for class member functions works. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-assembler "\\.hidden.*Foo.methodEv" } } */
+
+class __attribute__ ((visibility ("hidden"))) Foo
+{
+  void method();
+};
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/noPLT.C b/gcc/testsuite/g++.dg/ext/visibility/noPLT.C
new file mode 100644 (file)
index 0000000..0ad981f
--- /dev/null
@@ -0,0 +1,20 @@
+/* Test that -fvisibility=hidden prevents PLT. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-options "-fPIC -fvisibility=hidden" } */
+/* { dg-final { scan-assembler-not "methodEv@PLT" } } */
+
+class Foo
+{
+public:
+  void method();
+};
+
+void Foo::method() { }
+
+int main(void)
+{
+  Foo f;
+  f.method();
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C b/gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C
new file mode 100644 (file)
index 0000000..a2c93eb
--- /dev/null
@@ -0,0 +1,13 @@
+/* Test that #pragma GCC visibility does not override class member specific settings. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" } } */
+
+#pragma GCC visibility push(hidden)
+class __attribute__ ((visibility ("internal"))) Foo
+{
+  void method();
+};
+#pragma GCC visibility pop
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C b/gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C
new file mode 100644 (file)
index 0000000..a4bb42c
--- /dev/null
@@ -0,0 +1,13 @@
+/* Test that #pragma GCC visibility does not override class member specific settings. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" } } */
+
+#pragma GCC visibility push(hidden)
+class Foo
+{
+  __attribute__ ((visibility ("internal"))) void method();
+};
+#pragma GCC visibility pop
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/pragma.C b/gcc/testsuite/g++.dg/ext/visibility/pragma.C
new file mode 100644 (file)
index 0000000..860b228
--- /dev/null
@@ -0,0 +1,13 @@
+/* Test that #pragma GCC visibility affects class members. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-assembler "\\.hidden.*Foo.methodEv" } } */
+
+#pragma GCC visibility push(hidden)
+class Foo
+{
+  void method();
+};
+#pragma GCC visibility pop
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/staticmemfuncts.C b/gcc/testsuite/g++.dg/ext/visibility/staticmemfuncts.C
new file mode 100644 (file)
index 0000000..b49cbd5
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test that setting visibility for static class member functions works. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-assembler "\\.hidden.*Foo.methodEv" } } */
+
+class __attribute__ ((visibility ("hidden"))) Foo
+{
+  static void method();
+};
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/virtual.C b/gcc/testsuite/g++.dg/ext/visibility/virtual.C
new file mode 100644 (file)
index 0000000..604c552
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test that setting visibility for class affects virtual table. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-assembler "\\.hidden.*ZTV3Foo" } } */
+
+class __attribute__ ((visibility ("hidden"))) Foo
+{
+  virtual void method();
+};
+
+void Foo::method() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/visibility-1.C b/gcc/testsuite/g++.dg/ext/visibility/visibility-1.C
new file mode 100644 (file)
index 0000000..d579eb2
--- /dev/null
@@ -0,0 +1,8 @@
+/* Test visibility attribute on function definition. */
+/* { dg-do compile { target *86-*-linux* } } */
+/* { dg-final { scan-assembler "\\.hidden.*_Z3foov" } } */
+
+void
+__attribute__((visibility ("hidden")))
+foo()
+{ }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/visibility-2.C b/gcc/testsuite/g++.dg/ext/visibility/visibility-2.C
new file mode 100644 (file)
index 0000000..89e853c
--- /dev/null
@@ -0,0 +1,7 @@
+/* Test that visibility attribute on declaration extends to definition. */
+/* { dg-do compile { target *86-*-linux* } } */
+/* { dg-final { scan-assembler "\\.hidden.*_Z3foov" } } */
+
+void __attribute__((visibility ("hidden"))) foo();
+
+void foo() { }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/visibility-3.C b/gcc/testsuite/g++.dg/ext/visibility/visibility-3.C
new file mode 100644 (file)
index 0000000..d0cc891
--- /dev/null
@@ -0,0 +1,7 @@
+/* Test visibility attribute on forward declaration of global variable */
+/* { dg-do compile { target *86-*-linux* } } */
+/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
+
+int
+__attribute__((visibility ("hidden")))
+xyzzy = 5;
diff --git a/gcc/testsuite/g++.dg/ext/visibility/visibility-4.C b/gcc/testsuite/g++.dg/ext/visibility/visibility-4.C
new file mode 100644 (file)
index 0000000..d217bc9
--- /dev/null
@@ -0,0 +1,8 @@
+/* Test visibility attribute on forward declaration of global variable */
+/* { dg-do compile { target *86-*-linux* } } */
+/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
+
+extern int __attribute__ ((visibility ("hidden")))
+xyzzy;
+
+int xyzzy = 5;
diff --git a/gcc/testsuite/g++.dg/ext/visibility/visibility-5.C b/gcc/testsuite/g++.dg/ext/visibility/visibility-5.C
new file mode 100644 (file)
index 0000000..9cdc802
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test visibility attribute on definition of a function that has
+   already had a forward declaration. */
+/* { dg-do compile { target *86-*-linux* } } */
+/* { dg-final { scan-assembler "\\.hidden.*_Z3foov" } } */
+
+void foo();
+
+void 
+ __attribute__((visibility ("hidden")))
+foo() 
+{ }
diff --git a/gcc/testsuite/g++.dg/ext/visibility/visibility-6.C b/gcc/testsuite/g++.dg/ext/visibility/visibility-6.C
new file mode 100644 (file)
index 0000000..6e8f0ce
--- /dev/null
@@ -0,0 +1,10 @@
+/* Test visibility attribute on definition of global variable that has
+   already had a forward declaration. */
+/* { dg-do compile { target *86-*-linux* } } */
+/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
+
+extern int xyzzy;
+
+int 
+__attribute__((visibility ("hidden")))
+xyzzy = 5;
diff --git a/gcc/testsuite/g++.dg/ext/visibility/visibility-7.C b/gcc/testsuite/g++.dg/ext/visibility/visibility-7.C
new file mode 100644 (file)
index 0000000..40acb72
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test warning from conflicting visibility specifications. */
+/* { dg-do compile { target *86-*-linux* } } */
+/* { dg-final { scan-assembler "\\.hidden.*xyzzy" } } */
+
+extern int 
+__attribute__((visibility ("hidden")))
+xyzzy; /* { dg-warning "previous declaration here" "" } */
+
+int 
+__attribute__((visibility ("protected")))
+xyzzy = 5; /* { dg-warning "visibility attribute ignored" "" } */
diff --git a/gcc/testsuite/gcc.dg/visibility-9.c b/gcc/testsuite/gcc.dg/visibility-9.c
new file mode 100644 (file)
index 0000000..ac6493e
--- /dev/null
@@ -0,0 +1,9 @@
+/* Test that -fvisibility works. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-options "-fvisibility=hidden" } */
+/* { dg-final { scan-assembler "\\.hidden.*foo" } } */
+
+void foo();
+
+void foo() { }
diff --git a/gcc/testsuite/gcc.dg/visibility-a.c b/gcc/testsuite/gcc.dg/visibility-a.c
new file mode 100644 (file)
index 0000000..1749234
--- /dev/null
@@ -0,0 +1,10 @@
+/* Test that #pragma GCC visibility works. */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-assembler "\\.hidden.*foo" } } */
+
+#pragma GCC visibility push(hidden)
+void foo();
+#pragma GCC visibility pop
+
+void foo() { }
index bba53fd5727f361d77cad525080a4b2c948bc003..46479be7d3951b4cc3f02d32f9fdfdec3a326aa9 100644 (file)
@@ -2700,6 +2700,11 @@ build_decl_stat (enum tree_code code, tree name, tree type MEM_STAT_DECL)
     layout_decl (t, 0);
   else if (code == FUNCTION_DECL)
     DECL_MODE (t) = FUNCTION_MODE;
+    
+  /* Set default visibility to whatever the user supplied with
+     visibility_specified depending on #pragma GCC visibility.  */
+  DECL_VISIBILITY (t) = default_visibility;
+  DECL_VISIBILITY_SPECIFIED (t) = visibility_options.inpragma;
 
   return t;
 }
index f9567c33b73dd1e7582051d5c0e607b0d05b6bc8..692716e0cc20ab6021a36e406332a1460d97e9d7 100644 (file)
@@ -2008,6 +2008,10 @@ struct tree_binfo GTY (())
 /* Value of the decls's visibility attribute */
 #define DECL_VISIBILITY(NODE) (DECL_CHECK (NODE)->decl.visibility)
 
+/* Nonzero means that the decl had its visibility specified rather than
+   being inferred.  */
+#define DECL_VISIBILITY_SPECIFIED(NODE) (DECL_CHECK (NODE)->decl.visibility_specified)
+
 /* In a FUNCTION_DECL, nonzero if the function cannot be inlined.  */
 #define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
 
@@ -2162,7 +2166,8 @@ struct tree_binfo GTY (())
   FUNCTION_DECL_CHECK (DECL)->decl.possibly_inlined
 
 /* Enumerate visibility settings.  */
-
+#ifndef SYMBOL_VISIBILITY_DEFINED
+#define SYMBOL_VISIBILITY_DEFINED
 enum symbol_visibility
 {
   VISIBILITY_DEFAULT,
@@ -2170,6 +2175,7 @@ enum symbol_visibility
   VISIBILITY_HIDDEN,
   VISIBILITY_PROTECTED
 };
+#endif
 
 struct function;
 union alias_var_def;
@@ -2214,6 +2220,7 @@ struct tree_decl GTY(())
   unsigned declared_inline_flag : 1;
   unsigned seen_in_bind_expr : 1;
   ENUM_BITFIELD(symbol_visibility) visibility : 2;
+  unsigned visibility_specified : 1;
 
   unsigned lang_flag_0 : 1;
   unsigned lang_flag_1 : 1;
index 95ac3775136a9f271622d32fdd5b587403f50fa8..b73c6542231916b583d314ad66e5c9dc7c12b812 100644 (file)
@@ -4956,8 +4956,8 @@ default_binds_local_p_1 (tree exp, int shlib)
   /* Static variables are always local.  */
   else if (! TREE_PUBLIC (exp))
     local_p = true;
-  /* A variable is local if the user tells us so.  */
-  else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+  /* A variable is local if the user explicitly tells us so.  */
+  else if (DECL_VISIBILITY_SPECIFIED (exp) && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Otherwise, variables defined outside this object may not be local.  */
   else if (DECL_EXTERNAL (exp))
@@ -4965,6 +4965,9 @@ default_binds_local_p_1 (tree exp, int shlib)
   /* Linkonce and weak data are never local.  */
   else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
     local_p = false;
+  /* If none of the above and visibility is not default, make local.  */
+  else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+    local_p = true;
   /* If PIC, then assume that any global name can be overridden by
      symbols resolved from other modules.  */
   else if (shlib)