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:
Jason Merrill 2006-03-20 22:19:06 -05:00
parent 29c14e849e
commit 0ed5edac59
12 changed files with 282 additions and 85 deletions

View 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.

View 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");
}

View 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);

View 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.

View 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))

View 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;

View 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)))
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;
}

View 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. */
@ -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);
}

View 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 *);
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);

View 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. */

View 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();
}

View 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() { }