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:
parent
28dab13236
commit
d7afec4b07
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
14
gcc/c-decl.c
14
gcc/c-decl.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
24
gcc/flags.h
24
gcc/flags.h
|
@ -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;
|
||||
|
|
21
gcc/opts.c
21
gcc/opts.c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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;
|
||||
}
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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() { }
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue