re PR c++/21764 (visibility attributes on namespace scope)
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. From-SVN: r112239
This commit is contained in:
parent
29c14e849e
commit
0ed5edac59
12 changed files with 282 additions and 85 deletions
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
117
gcc/cp/decl2.c
117
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)))
|
||||
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) = VISIBILITY_DEFAULT;
|
||||
DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
|
||||
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))
|
||||
{
|
||||
DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
@ -2957,6 +2963,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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
25
gcc/testsuite/g++.dg/ext/visibility/local1.C
Normal file
25
gcc/testsuite/g++.dg/ext/visibility/local1.C
Normal file
|
@ -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();
|
||||
}
|
30
gcc/testsuite/g++.dg/ext/visibility/namespace1.C
Normal file
30
gcc/testsuite/g++.dg/ext/visibility/namespace1.C
Normal file
|
@ -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() { }
|
||||
|
Loading…
Add table
Reference in a new issue