OSDN Git Service

PR c++/21764
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 21 Mar 2006 03:19:06 +0000 (03:19 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 21 Mar 2006 03:19:06 +0000 (03:19 +0000)
        * c-pragma.c (visstack): Move out of handle_pragma_visibility.
        (push_visibility, pop_visibility): Likewise.
        * c-pragma.h: Declare them.
        * cp/name-lookup.h (struct cp_binding_level): Add has_visibility
        bitfield.
        * cp/name-lookup.c: Include c-pragma.h.
        (push_namespace_with_attribs): Split out from push_namespace.
        Push visibility if appropriate.  Set TREE_PUBLIC on namespaces.
        (leave_scope): Pop visibility if appropriate.
        * cp/parser.c (cp_parser_declaration, cp_parser_namespace_name): Allow
        attributes on namespace declarations.

        PR c++/19238
        * cp/decl.c (cp_finish_decl): Call determine_visibility later.
        (start_preparsed_function): Likewise.
        * cp/cp-tree.h (CP_TYPE_CONTEXT, TYPE_NAMESPACE_SCOPE_P): New macros.
        (TYPE_CLASS_SCOPE_P, TYPE_FUNCTION_SCOPE_P): New macros.
        * cp/decl2.c (determine_visibility_from_class): Split out from...
        (determine_visibility): ...here.  Handle function scope and
        nested classes.
        (import_export_decl): Move visibility handling to
        determine_visibility_from_class.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@112239 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog
gcc/c-pragma.c
gcc/c-pragma.h
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/testsuite/g++.dg/ext/visibility/local1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/visibility/namespace1.C [new file with mode: 0644]

index 37f3533..fb19e1f 100644 (file)
@@ -1,3 +1,10 @@
+2006-03-20  Jason Merrill  <jason@redhat.com>
+
+       PR c++/21764
+       * c-pragma.c (visstack): Move out of handle_pragma_visibility.
+       (push_visibility, pop_visibility): Likewise.
+       * c-pragma.h: Declare them.
+
 2006-03-20  Kaz Kojima  <kkojima@gcc.gnu.org>
 
        * config/sh/sh.c (untangle_mova): Initialize n_addr and n_target.
index 39c4595..b62352c 100644 (file)
@@ -593,9 +593,42 @@ static void handle_pragma_visibility (cpp_reader *);
 typedef enum symbol_visibility visibility;
 DEF_VEC_I (visibility);
 DEF_VEC_ALLOC_I (visibility, heap);
+static VEC (visibility, heap) *visstack;
+
+/* Push the visibility indicated by STR onto the top of the #pragma
+   visibility stack.  */
+
+void
+push_visibility (const char *str)
+{
+  VEC_safe_push (visibility, heap, visstack,
+                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;
+}
+
+/* Pop a level of the #pragma visibility stack.  */
+
+void
+pop_visibility (void)
+{
+  default_visibility = VEC_pop (visibility, visstack);
+  visibility_options.inpragma
+    = VEC_length (visibility, visstack) != 0;
+}  
 
 /* 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)
 {
@@ -603,7 +636,6 @@ handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED)
   tree x;
   enum cpp_ttype token;
   enum { bad, push, pop } action = bad;
-  static VEC (visibility, heap) *visstack;
  
   token = pragma_lex (&x);
   if (token == CPP_NAME)
@@ -621,15 +653,9 @@ handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED)
       if (pop == action)
         {
           if (!VEC_length (visibility, visstack))
-            {
-              GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>");
-            }
+           GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>");
           else
-            {
-             default_visibility = VEC_pop (visibility, visstack);
-             visibility_options.inpragma
-               = VEC_length (visibility, visstack) != 0;
-            }
+           pop_visibility ();
         }
       else
         {
@@ -637,28 +663,9 @@ handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED)
             GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
           token = pragma_lex (&x);
           if (token != CPP_NAME)
-            {
-              GCC_BAD ("malformed #pragma GCC visibility push");
-            }
+           GCC_BAD ("malformed #pragma GCC visibility push");
           else
-            {
-              const char *str = IDENTIFIER_POINTER (x);
-             VEC_safe_push (visibility, heap, visstack,
-                            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;
-            }
+           push_visibility (IDENTIFIER_POINTER (x));
           if (pragma_lex (&x) != CPP_CLOSE_PAREN)
             GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
         }
index 5868f07..6ebb08b 100644 (file)
@@ -75,6 +75,8 @@ extern struct cpp_reader* parse_in;
    visibility is not supported on the host OS platform the
    statements are ignored.  */
 #define HANDLE_PRAGMA_VISIBILITY 1
+extern void push_visibility (const char *);
+extern void pop_visibility (void);
 
 extern void init_pragma (void);
 
index b3f4111..9831655 100644 (file)
@@ -1,7 +1,28 @@
+2006-03-20  Jason Merrill  <jason@redhat.com>
+
+       PR c++/21764, c++/19238
+       * decl.c (cp_finish_decl): Call determine_visibility later.
+       (start_preparsed_function): Likewise.
+       * cp-tree.h (CP_TYPE_CONTEXT, TYPE_NAMESPACE_SCOPE_P): New macros.
+       (TYPE_CLASS_SCOPE_P, TYPE_FUNCTION_SCOPE_P): New macros.
+       * name-lookup.h (struct cp_binding_level): Add has_visibility 
+       bitfield.
+       * name-lookup.c: Include c-pragma.h.
+       (push_namespace_with_attribs): Split out from push_namespace.
+       Push visibility if appropriate.  Set TREE_PUBLIC on namespaces.
+       (leave_scope): Pop visibility if appropriate.
+       * decl2.c (determine_visibility_from_class): Split out from...
+       (determine_visibility): ...here.  Handle function scope and 
+       nested classes.
+       (import_export_decl): Move visibility handling to 
+       determine_visibility_from_class.
+       * parser.c (cp_parser_declaration, cp_parser_namespace_name): Allow
+       attributes on namespace declarations.
+
 2006-03-15  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>
 
        PR c++/6634
-       decl.c (grokdeclarator): Do not accept long long double.
+       decl.c (grokdeclarator): Do not accept long long double.
        Reorganize checks for invalid (combinations of) type modifiers.
        Quote modifiers in messages.
 
index 69d6466..4b15573 100644 (file)
@@ -1964,6 +1964,8 @@ struct lang_decl GTY(())
 /* NULL_TREE in DECL_CONTEXT represents the global namespace.  */
 #define CP_DECL_CONTEXT(NODE) \
   (DECL_CONTEXT (NODE) ? DECL_CONTEXT (NODE) : global_namespace)
+#define CP_TYPE_CONTEXT(NODE) \
+  (TYPE_CONTEXT (NODE) ? TYPE_CONTEXT (NODE) : global_namespace)
 #define FROB_CONTEXT(NODE)   ((NODE) == global_namespace ? NULL_TREE : (NODE))
 
 /* 1 iff NODE has namespace scope, including the global namespace.  */
@@ -1971,15 +1973,25 @@ struct lang_decl GTY(())
   (!DECL_TEMPLATE_PARM_P (NODE)                                        \
    && TREE_CODE (CP_DECL_CONTEXT (NODE)) == NAMESPACE_DECL)
 
+#define TYPE_NAMESPACE_SCOPE_P(NODE)                           \
+  (TREE_CODE (CP_TYPE_CONTEXT (NODE)) == NAMESPACE_DECL)
+
 /* 1 iff NODE is a class member.  */
 #define DECL_CLASS_SCOPE_P(NODE) \
   (DECL_CONTEXT (NODE) && TYPE_P (DECL_CONTEXT (NODE)))
 
+#define TYPE_CLASS_SCOPE_P(NODE) \
+  (TYPE_CONTEXT (NODE) && TYPE_P (TYPE_CONTEXT (NODE)))
+
 /* 1 iff NODE is function-local.  */
 #define DECL_FUNCTION_SCOPE_P(NODE) \
   (DECL_CONTEXT (NODE) \
    && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL)
 
+#define TYPE_FUNCTION_SCOPE_P(NODE) \
+  (TYPE_CONTEXT (NODE) \
+   && TREE_CODE (TYPE_CONTEXT (NODE)) == FUNCTION_DECL)
+
 /* 1 iff VAR_DECL node NODE is a type-info decl.  This flag is set for
    both the primary typeinfo object and the associated NTBS name.  */
 #define DECL_TINFO_P(NODE) TREE_LANG_FLAG_4 (VAR_DECL_CHECK (NODE))
index bb6a59c..45feb9f 100644 (file)
@@ -5178,9 +5178,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
             the class specifier.  */
          if (!DECL_EXTERNAL (decl))
            var_definition_p = true;
-         /* The variable is being defined, so determine its
-            visibility.  */
-         determine_visibility (decl);
        }
       /* If the variable has an array type, lay out the type, even if
         there is no initializer.  It is valid to index through the
@@ -5244,6 +5241,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
                initialize_local_var (decl, init);
            }
 
+         /* The variable is being defined, so determine its visibility.
+            This needs to happen after the linkage is set. */
+         determine_visibility (decl);
+
          /* If a variable is defined, and then a subsequent
             definition with external linkage is encountered, we will
             get here twice for the same variable.  We want to avoid
@@ -10422,12 +10423,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
        maybe_apply_pragma_weak (decl1);
     }
 
-  /* Determine the ELF visibility attribute for the function.  We must
-     not do this before calling "pushdecl", as we must allow
-     "duplicate_decls" to merge any attributes appropriately.  */
-  if (!DECL_CLONED_FUNCTION_P (decl1))
-    determine_visibility (decl1);
-
   /* Reset these in case the call to pushdecl changed them.  */
   current_function_decl = decl1;
   cfun->decl = decl1;
@@ -10546,6 +10541,13 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
        DECL_INTERFACE_KNOWN (decl1) = 1;
     }
 
+  /* Determine the ELF visibility attribute for the function.  We must not
+     do this before calling "pushdecl", as we must allow "duplicate_decls"
+     to merge any attributes appropriately.  We also need to wait until
+     linkage is set.  */
+  if (!DECL_CLONED_FUNCTION_P (decl1))
+    determine_visibility (decl1);
+
   begin_scope (sk_function_parms, decl1);
 
   ++function_depth;
index b332e6e..88d7e8e 100644 (file)
@@ -82,6 +82,7 @@ static tree prune_vars_needing_no_initialization (tree *);
 static void write_out_vars (tree);
 static void import_export_class (tree);
 static tree get_guard_bits (tree);
+static void determine_visibility_from_class (tree, tree);
 
 /* A list of static class variables.  This is needed, because a
    static class variable can be declared inside the class without
@@ -1566,13 +1567,27 @@ maybe_emit_vtables (tree ctype)
 }
 
 /* Like c_determine_visibility, but with additional C++-specific
-   behavior.  */
+   behavior.
+
+   Function-scope entities can rely on the function's visibility because
+   it is set in start_preparsed_function.
+
+   Class-scope entities cannot rely on the class's visibility until the end
+   of the enclosing class definition.
+
+   Note that because namespaces have multiple independent definitions,
+   namespace visibility is handled elsewhere using the #pragma visibility
+   machinery rather than by decorating the namespace declaration.  */
 
 void
 determine_visibility (tree decl)
 {
   tree class_type;
 
+  /* Only relevant for names with external linkage.  */
+  if (!TREE_PUBLIC (decl))
+    return;
+
   /* Cloned constructors and destructors get the same visibility as
      the underlying function.  That should be set up in
      maybe_clone_body.  */
@@ -1596,6 +1611,14 @@ determine_visibility (tree decl)
         so they are automatically handled above.  */
       gcc_assert (TREE_CODE (decl) != VAR_DECL
                  || !DECL_VTABLE_OR_VTT_P (decl));
+
+      if (DECL_FUNCTION_SCOPE_P (decl))
+       {
+         tree fn = DECL_CONTEXT (decl);
+         DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
+         DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn);
+       }
+
       /* Entities not associated with any class just get the
         visibility specified by their attributes.  */
       return;
@@ -1605,33 +1628,62 @@ determine_visibility (tree decl)
      the visibility of their containing class.  */
   if (class_type)
     {
-      if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
-         && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class_type)))
-       {
-         DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
-         DECL_VISIBILITY_SPECIFIED (decl) = 1;
-       }
-      else if (TREE_CODE (decl) == FUNCTION_DECL
-              && DECL_DECLARED_INLINE_P (decl)
-              && visibility_options.inlines_hidden)
-       {
-         /* Don't change it if it has been set explicitly by user.  */
-         if (!DECL_VISIBILITY_SPECIFIED (decl))
-           {
-             DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
-             DECL_VISIBILITY_SPECIFIED (decl) = 1;
-           }
-       }
-      else if (CLASSTYPE_VISIBILITY_SPECIFIED (class_type))
+      determine_visibility_from_class (decl, class_type);
+
+      /* Give the target a chance to override the visibility associated
+        with DECL.  */
+      if (TREE_CODE (decl) == VAR_DECL
+         && (DECL_TINFO_P (decl)
+             || (DECL_VTABLE_OR_VTT_P (decl)
+                 /* Construction virtual tables are not exported because
+                    they cannot be referred to from other object files;
+                    their name is not standardized by the ABI.  */
+                 && !DECL_CONSTRUCTION_VTABLE_P (decl)))
+         && TREE_PUBLIC (decl)
+         && !DECL_REALLY_EXTERN (decl)
+         && DECL_VISIBILITY_SPECIFIED (decl)
+         && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)))
+       targetm.cxx.determine_class_data_visibility (decl);
+    }      
+}
+
+static void
+determine_visibility_from_class (tree decl, tree class_type)
+{
+  if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+      && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class_type)))
+    {
+      DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (decl) = 1;
+    }
+  else if (TREE_CODE (decl) == FUNCTION_DECL
+          && DECL_DECLARED_INLINE_P (decl)
+          && visibility_options.inlines_hidden)
+    {
+      /* Don't change it if it has been set explicitly by user.  */
+      if (!DECL_VISIBILITY_SPECIFIED (decl))
        {
-         DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
+         DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
          DECL_VISIBILITY_SPECIFIED (decl) = 1;
        }
-      else if (!DECL_VISIBILITY_SPECIFIED (decl))
-       {
-         DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
-         DECL_VISIBILITY_SPECIFIED (decl) = 0;
-       }
+    }
+  else if (CLASSTYPE_VISIBILITY_SPECIFIED (class_type))
+    {
+      DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
+      DECL_VISIBILITY_SPECIFIED (decl) = 1;
+    }
+  else if (TYPE_CLASS_SCOPE_P (class_type))
+    determine_visibility_from_class (decl, TYPE_CONTEXT (class_type));
+  else if (TYPE_FUNCTION_SCOPE_P (class_type))
+    {
+      tree fn = TYPE_CONTEXT (class_type);
+      DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
+      DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn);
+    }
+  else if (!DECL_VISIBILITY_SPECIFIED (decl))
+    {
+      DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
+      DECL_VISIBILITY_SPECIFIED (decl) = 0;
     }
 }
 
@@ -1905,21 +1957,6 @@ import_export_decl (tree decl)
       comdat_linkage (decl);
     }
 
-  /* Give the target a chance to override the visibility associated
-     with DECL.  */
-  if (TREE_CODE (decl) == VAR_DECL
-      && (DECL_TINFO_P (decl)
-         || (DECL_VTABLE_OR_VTT_P (decl)
-             /* Construction virtual tables are not exported because
-                they cannot be referred to from other object files;
-                their name is not standardized by the ABI.  */
-             && !DECL_CONSTRUCTION_VTABLE_P (decl)))
-      && TREE_PUBLIC (decl)
-      && !DECL_REALLY_EXTERN (decl)
-      && DECL_VISIBILITY_SPECIFIED (decl)
-      && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)))
-    targetm.cxx.determine_class_data_visibility (decl);
-
   DECL_INTERFACE_KNOWN (decl) = 1;
 }
 
index ebf8a33..9b10fb4 100644 (file)
@@ -31,6 +31,7 @@ Boston, MA 02110-1301, USA.  */
 #include "toplev.h"
 #include "diagnostic.h"
 #include "debug.h"
+#include "c-pragma.h"
 
 /* The bindings for a particular name in a particular scope.  */
 
@@ -1330,11 +1331,16 @@ leave_scope (void)
       is_class_level = 0;
     }
 
+#ifdef HANDLE_PRAGMA_VISIBILITY
+  if (scope->has_visibility)
+    pop_visibility ();
+#endif
+
   /* Move one nesting level up.  */
   current_binding_level = scope->level_chain;
 
   /* Namespace-scopes are left most probably temporarily, not
-     completely; they can be reopen later, e.g. in namespace-extension
+     completely; they can be reopened later, e.g. in namespace-extension
      or any name binding activity that requires us to resume a
      namespace.  For classes, we cache some binding levels.  For other
      scopes, we just make the structure available for reuse.  */
@@ -2958,6 +2964,15 @@ current_decl_namespace (void)
 void
 push_namespace (tree name)
 {
+  push_namespace_with_attribs (name, NULL_TREE);
+}
+
+/* Same, but specify attributes to apply to the namespace.  The attributes
+   only apply to the current namespace-body, not to any later extensions. */
+
+void
+push_namespace_with_attribs (tree name, tree attributes)
+{
   tree d = NULL_TREE;
   int need_new = 1;
   int implicit_use = 0;
@@ -3004,6 +3019,7 @@ push_namespace (tree name)
       /* Make a new namespace, binding the name to it.  */
       d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
       DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace);
+      TREE_PUBLIC (d) = 1;
       pushdecl (d);
       if (anon)
        {
@@ -3021,6 +3037,36 @@ push_namespace (tree name)
   /* Enter the name space.  */
   current_namespace = d;
 
+#ifdef HANDLE_PRAGMA_VISIBILITY
+  /* Clear has_visibility in case a previous namespace-definition had a
+     visibility attribute and this one doesn't.  */
+  current_binding_level->has_visibility = 0;
+  for (d = attributes; d; d = TREE_CHAIN (d))
+    {
+      tree name = TREE_PURPOSE (d);
+      tree args = TREE_VALUE (d);
+      tree x;
+      
+      if (! is_attribute_p ("visibility", name))
+       {
+         warning (OPT_Wattributes, "%qs attribute directive ignored",
+                  IDENTIFIER_POINTER (name));
+         continue;
+       }
+
+      x = args ? TREE_VALUE (args) : NULL_TREE;
+      if (x == NULL_TREE || TREE_CODE (x) != STRING_CST)
+       {
+         warning (OPT_Wattributes, "%qs attribute requires an NTBS argument",
+                  IDENTIFIER_POINTER (name));
+         continue;
+       }
+
+      current_binding_level->has_visibility = 1;
+      push_visibility (TREE_STRING_POINTER (x));
+    }
+#endif
+
   timevar_pop (TV_NAME_LOOKUP);
 }
 
index 20c8225..ede7747 100644 (file)
@@ -259,7 +259,11 @@ struct cp_binding_level GTY(())
     unsigned more_cleanups_ok : 1;
     unsigned have_cleanups : 1;
 
-    /* 22 bits left to fill a 32-bit word.  */
+    /* Nonzero if this level has associated visibility which we should pop
+       when leaving the scope. */
+    unsigned has_visibility : 1;
+
+    /* 23 bits left to fill a 32-bit word.  */
   };
 
 /* The binding level currently in effect.  */
@@ -307,6 +311,7 @@ extern void pop_inner_scope (tree, tree);
 extern void push_binding_level (struct cp_binding_level *);
 \f
 extern void push_namespace (tree);
+extern void push_namespace_with_attribs (tree, tree);
 extern void pop_namespace (void);
 extern void push_nested_namespace (tree);
 extern void pop_nested_namespace (tree);
index b5c7fc0..e04a8e7 100644 (file)
@@ -7064,7 +7064,7 @@ cp_parser_declaration (cp_parser* parser)
           && (/* A named namespace definition.  */
               (token2.type == CPP_NAME
                && (cp_lexer_peek_nth_token (parser->lexer, 3)->type
-                   == CPP_OPEN_BRACE))
+                   != CPP_EQ))
               /* An unnamed namespace definition.  */
               || token2.type == CPP_OPEN_BRACE))
     cp_parser_namespace_definition (parser);
@@ -10470,7 +10470,7 @@ cp_parser_namespace_name (cp_parser* parser)
 static void
 cp_parser_namespace_definition (cp_parser* parser)
 {
-  tree identifier;
+  tree identifier, attribs;
 
   /* Look for the `namespace' keyword.  */
   cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
@@ -10484,10 +10484,13 @@ cp_parser_namespace_definition (cp_parser* parser)
   else
     identifier = NULL_TREE;
 
+  /* Parse any specified attributes.  */
+  attribs = cp_parser_attributes_opt (parser);
+
   /* Look for the `{' to start the namespace.  */
   cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
   /* Start the namespace.  */
-  push_namespace (identifier);
+  push_namespace_with_attribs (identifier, attribs);
   /* Parse the body of the namespace.  */
   cp_parser_namespace_body (parser);
   /* Finish the namespace.  */
diff --git a/gcc/testsuite/g++.dg/ext/visibility/local1.C b/gcc/testsuite/g++.dg/ext/visibility/local1.C
new file mode 100644 (file)
index 0000000..4871009
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/19238
+// Test that hidden visibility on an inline function is inherited by static
+// local variables and local classes.
+
+// { dg-do compile { target i?86-*-linux* x86_64-*-linux* powerpc*-*-linux* } }
+// { dg-final { scan-assembler "hidden\[ \t\]*_Z1fv" } }
+// { dg-final { scan-assembler "hidden\[ \t\]*_ZZ1fvE1i" } }
+// { dg-final { scan-assembler "hidden\[ \t\]*_ZZ1fvEN1A1fEv" } }
+
+__attribute ((visibility ("hidden"))) inline int
+f()
+{
+  static int i = 2;
+  struct A
+  {
+    void f () { }
+  } a;
+  a.f();
+  return i;
+}
+
+int main()
+{
+  f();
+}
diff --git a/gcc/testsuite/g++.dg/ext/visibility/namespace1.C b/gcc/testsuite/g++.dg/ext/visibility/namespace1.C
new file mode 100644 (file)
index 0000000..903a1f2
--- /dev/null
@@ -0,0 +1,30 @@
+// PR c++/21764
+// Test for namespace visibility attribute semantics.
+
+// { dg-do compile { target i?86-*-linux* x86_64-*-linux* powerpc*-*-linux* } }
+// { dg-final { scan-assembler "hidden\[ \t\]*_ZN3foo1fEv" } }
+// { dg-final { scan-assembler "hidden\[ \t\]*_ZN3foo1gEv" } }
+// { dg-final { scan-assembler "hidden\[ \t\]*_ZN3foo1A1mEv" } }
+// { dg-final { scan-assembler "hidden\[ \t\]*_ZN3foo1tIiEEvv" } }
+// { dg-final { scan-assembler-not "hidden\[ \t\]*_ZN3foo1hEv" } }
+
+namespace foo __attribute ((visibility ("hidden")))
+{
+  int f() { }
+  void g();
+  template <typename T> void t() { }
+  class A
+  {
+    void m ();
+  };
+}
+
+namespace foo
+{
+  void h() {}
+}
+
+void foo::g() { t<int> (); }
+
+void foo::A::m() { }
+