summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-21 03:19:06 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-21 03:19:06 +0000
commit799435d8a91f69e2fe2a0b42cd0af67e4180a929 (patch)
tree6e55c5f98ba55a6fcaf4861b4df4e8d7233c36ef /gcc
parent9d24686a6f8ca3fbccd12cdcce858ab2384a3d81 (diff)
downloadgcc-799435d8a91f69e2fe2a0b42cd0af67e4180a929.tar.gz
PR c++/21764
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/c-pragma.c67
-rw-r--r--gcc/c-pragma.h2
-rw-r--r--gcc/cp/ChangeLog23
-rw-r--r--gcc/cp/cp-tree.h12
-rw-r--r--gcc/cp/decl.c20
-rw-r--r--gcc/cp/decl2.c117
-rw-r--r--gcc/cp/name-lookup.c48
-rw-r--r--gcc/cp/name-lookup.h7
-rw-r--r--gcc/cp/parser.c9
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/local1.C25
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/namespace1.C30
12 files changed, 282 insertions, 85 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 37f35339849..fb19e1f51eb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c
index 39c459528e0..b62352c2e6b 100644
--- a/gcc/c-pragma.c
+++ b/gcc/c-pragma.c
@@ -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");
}
diff --git a/gcc/c-pragma.h b/gcc/c-pragma.h
index 5868f07251c..6ebb08b685c 100644
--- a/gcc/c-pragma.h
+++ b/gcc/c-pragma.h
@@ -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);
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b3f411146eb..983165551be 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 69d64667502..4b155735427 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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))
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bb6a59c4c55..45feb9f0c58 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index b332e6e9113..88d7e8e95f3 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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;
}
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index ebf8a3365ed..9b10fb4a9d7 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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);
}
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 20c82255a4d..ede7747d00d 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -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 *);
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);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b5c7fc011a5..e04a8e7f0d6 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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
index 00000000000..4871009ded2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/visibility/local1.C
@@ -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
index 00000000000..903a1f2524c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/visibility/namespace1.C
@@ -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() { }
+