re PR c++/9283 (__attribute__((visibility ("hidden"))) not supported for class/struct)

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
This commit is contained in:
Niall Douglas 2004-07-25 22:52:22 +00:00 committed by Giovanni Bajo
parent 28dab13236
commit d7afec4b07
42 changed files with 584 additions and 25 deletions

View File

@ -1,3 +1,28 @@
2004-07-26 Niall Douglas <s_fsfeurope2@nedprod.com>
Brian Ryner <bryner@brianryner.com>
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.
2004-07-25 Bernardo Innocenti <bernie@develer.com>
* basic-block.h (reorder_block_def): Rename to reorder_block_def_p.

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

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

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

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

View 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

View File

@ -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

View 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

View File

@ -1,3 +1,25 @@
2004-07-26 Niall Douglas <s_fsfeurope2@nedprod.com>
Brian Ryner <bryner@brianryner.com>
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.
2004-07-25 Bernardo Innocenti <bernie@develer.com>
* decl.c: Rename all identifiers named `class' to `cl'.

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

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

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

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

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

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

View 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

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

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

View File

@ -1,3 +1,26 @@
2004-07-26 Niall Douglas <s_fsfeurope2@nedprod.com>
Brian Ryner <bryner@brianryner.com>
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.
2004-07-25 Joseph S. Myers <jsm@polyomino.org.uk>
PR c/15360

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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