class.c (build_vtable): Do not set DECL_VISIBILITY here.

* class.c (build_vtable): Do not set DECL_VISIBILITY here.
	(check_field_decls): Or here.
	(check_methods): Or here.
	(initialize_array): Don't mess with DECL_CONTEXT.
	* cp-tree.h (start_decl): Adjust prototype.
	(determine_visibility): New function.
	* decl.c (duplicate_decls): Remove checks for hidden "operator
	new".
	(build_library_fn_1): Give all library functions default
	visibility.
	(start_decl): Add pop_scope_p parameter.  Tidy.
	(cp_finish_decl): Do not pop scopes here.  Call
	determine_visibility for variable definitions.
	(start_preparsed_function): Call determine_visibility.
	* decl2.c (determine_visibility): New function.
	* method.c (use_thunk): Fix formatting.
	* parser.c (cp_parser_condition): Adjust calls to start_decl.
	(cp_parser_init_declarator): Likewise.
	* pt.c (instantiate_decl): Always call pop_nested_class.
	* rtti.c (get_tinfo_decl): Do not set DECL_VISIBILITY.
	(tinfo_base_init): Likewise.

	* g++.dg/ext/visibility/assign1.C: New test.
	* g++.dg/ext/visibility/new1.C: Likewise.

From-SVN: r85543
This commit is contained in:
Mark Mitchell 2004-08-04 05:27:52 +00:00 committed by Mark Mitchell
parent aed6152d8c
commit 73a8adb62e
11 changed files with 168 additions and 161 deletions

View File

@ -1,3 +1,27 @@
2004-08-03 Mark Mitchell <mark@codesourcery.com>
* class.c (build_vtable): Do not set DECL_VISIBILITY here.
(check_field_decls): Or here.
(check_methods): Or here.
(initialize_array): Don't mess with DECL_CONTEXT.
* cp-tree.h (start_decl): Adjust prototype.
(determine_visibility): New function.
* decl.c (duplicate_decls): Remove checks for hidden "operator
new".
(build_library_fn_1): Give all library functions default
visibility.
(start_decl): Add pop_scope_p parameter. Tidy.
(cp_finish_decl): Do not pop scopes here. Call
determine_visibility for variable definitions.
(start_preparsed_function): Call determine_visibility.
* decl2.c (determine_visibility): New function.
* method.c (use_thunk): Fix formatting.
* parser.c (cp_parser_condition): Adjust calls to start_decl.
(cp_parser_init_declarator): Likewise.
* pt.c (instantiate_decl): Always call pop_nested_class.
* rtti.c (get_tinfo_decl): Do not set DECL_VISIBILITY.
(tinfo_base_init): Likewise.
2004-08-02 Mark Mitchell <mark@codesourcery.com>
PR c++/16707

View File

@ -659,11 +659,6 @@ build_vtable (tree class_type, tree name, tree vtable_type)
require more intrusive changes to the g++ front end. */
DECL_IGNORED_P (decl) = 1;
/* 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);
return decl;
}
@ -2971,25 +2966,7 @@ check_field_decls (tree t, tree *access_decls,
continue;
if (TREE_CODE (x) == CONST_DECL || TREE_CODE (x) == VAR_DECL)
{
/* 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;
}
continue;
/* Now it can only be a FIELD_DECL. */
@ -3744,23 +3721,6 @@ 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. */
if (DECL_VINDEX (x))
@ -6740,13 +6700,8 @@ initialize_vtable (tree binfo, tree inits)
static void
initialize_array (tree decl, tree inits)
{
tree context;
context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = NULL_TREE;
DECL_INITIAL (decl) = build_constructor (NULL_TREE, inits);
cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
DECL_CONTEXT (decl) = context;
}
/* Build the VTT (virtual table table) for T.

View File

@ -3740,7 +3740,7 @@ extern int init_type_desc (void);
extern tree check_tag_decl (cp_decl_specifier_seq *);
extern tree shadow_tag (cp_decl_specifier_seq *);
extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *);
extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree);
extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, bool *);
extern void start_decl_1 (tree);
extern void cp_finish_decl (tree, tree, tree, int);
extern void finish_decl (tree, tree, tree);
@ -3825,6 +3825,7 @@ extern tree finish_table (tree, tree, tree, int);
extern tree coerce_new_type (tree);
extern tree coerce_delete_type (tree);
extern void comdat_linkage (tree);
extern void determine_visibility (tree);
extern void import_export_decl (tree);
extern tree build_cleanup (tree);
extern tree build_offset_ref_call_from_tree (tree, tree);

View File

@ -1881,11 +1881,12 @@ duplicate_decls (tree newdecl, tree olddecl)
COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
/* Warn about conflicting visibility specifications. */
if (DECL_VISIBILITY_SPECIFIED (olddecl) && DECL_VISIBILITY_SPECIFIED (newdecl)
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);
newdecl, newdecl);
warning ("%Jconflicts with previous declaration here", olddecl);
}
/* Choose the declaration which specified visibility. */
@ -1894,21 +1895,6 @@ duplicate_decls (tree newdecl, tree 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)
{
@ -3276,6 +3262,10 @@ build_library_fn_1 (tree name, enum tree_code operator_code, tree type)
TREE_NOTHROW (fn) = 1;
SET_OVERLOADED_OPERATOR_CODE (fn, operator_code);
SET_DECL_LANGUAGE (fn, lang_c);
/* Runtime library routines are, by definition, available in an
external shared object. */
DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
DECL_VISIBILITY_SPECIFIED (fn) = 1;
return fn;
}
@ -3607,7 +3597,8 @@ start_decl (const cp_declarator *declarator,
cp_decl_specifier_seq *declspecs,
int initialized,
tree attributes,
tree prefix_attributes)
tree prefix_attributes,
bool *pop_scope_p)
{
tree decl;
tree type, tem;
@ -3642,14 +3633,11 @@ start_decl (const cp_declarator *declarator,
context = DECL_CONTEXT (decl);
if (initialized && context && TREE_CODE (context) == NAMESPACE_DECL
&& context != current_namespace && TREE_CODE (decl) == VAR_DECL)
{
/* When parsing the initializer, lookup should use the object's
namespace. */
push_decl_namespace (context);
}
if (context)
*pop_scope_p = push_scope (context);
else
*pop_scope_p = false;
/* We are only interested in class contexts, later. */
if (context && TREE_CODE (context) == NAMESPACE_DECL)
context = NULL_TREE;
@ -3705,8 +3693,6 @@ start_decl (const cp_declarator *declarator,
if (context && COMPLETE_TYPE_P (complete_type (context)))
{
push_nested_class (context);
if (TREE_CODE (decl) == VAR_DECL)
{
tree field = lookup_field (context, DECL_NAME (decl), 0, false);
@ -4715,20 +4701,10 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
&& (DECL_INITIAL (decl) || init))
DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
if (TREE_CODE (decl) == VAR_DECL
&& DECL_CONTEXT (decl)
&& TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
&& DECL_CONTEXT (decl) != current_namespace
&& init)
{
/* Leave the namespace of the object. */
pop_decl_namespace ();
}
type = TREE_TYPE (decl);
if (type == error_mark_node)
goto finish_end0;
goto finish_end;
if (TYPE_HAS_MUTABLE_P (type))
TREE_READONLY (decl) = 0;
@ -4745,7 +4721,7 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
&& !DECL_PRETTY_FUNCTION_P (decl)
&& !dependent_type_p (TREE_TYPE (decl)))
maybe_deduce_size_from_array_init (decl, init);
goto finish_end0;
goto finish_end;
}
/* Parameters are handled by store_parm_decls, not cp_finish_decl. */
@ -4833,6 +4809,9 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
/* Remember that the initialization for this variable has
taken place. */
DECL_INITIALIZED_P (decl) = 1;
/* 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
@ -4899,26 +4878,6 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
if (TREE_STATIC (decl))
expand_static_init (decl, init);
}
finish_end0:
/* Undo call to `pushclass' that was done in `start_decl'
due to initialization of qualified member variable.
I.e., Foo::x = 10; */
{
tree context = CP_DECL_CONTEXT (decl);
if (context
&& TYPE_P (context)
&& (TREE_CODE (decl) == VAR_DECL
/* We also have a pushclass done that we need to undo here
if we're at top level and declare a method. */
|| TREE_CODE (decl) == FUNCTION_DECL)
/* If size hasn't been set, we're still defining it,
and therefore inside the class body; don't pop
the binding level.. */
&& COMPLETE_TYPE_P (context)
&& context == current_class_type)
pop_nested_class ();
}
}
/* If a CLEANUP_STMT was created to destroy a temporary bound to a
@ -9663,6 +9622,9 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
&& lookup_attribute ("noinline", attrs))
warning ("%Jinline function '%D' given attribute noinline", decl1, decl1);
/* Determine the ELF visibility attribute for the function. */
determine_visibility (decl1);
if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl1))
/* This is a constructor, we must ensure that any default args
introduced by this definition are propagated to the clones

View File

@ -1616,6 +1616,59 @@ maybe_emit_vtables (tree ctype)
return true;
}
/* Determine the ELF symbol visibility for DECL. */
void
determine_visibility (tree decl)
{
tree class_type;
/* Cloned constructors and destructors get the same visibility as
the underlying function. That should be set up in
maybe_clone_body. */
if (DECL_CLONED_FUNCTION_P (decl))
return;
if (DECL_CLASS_SCOPE_P (decl))
class_type = DECL_CONTEXT (decl);
else if (TREE_CODE (decl) == VAR_DECL
&& DECL_TINFO_P (decl)
&& CLASS_TYPE_P (TREE_TYPE (DECL_NAME (decl))))
class_type = TREE_TYPE (DECL_NAME (decl));
else
{
/* Virtual tables have DECL_CONTEXT set to their associated class,
so they are automatically handled above. */
my_friendly_assert (!(TREE_CODE (decl) == VAR_DECL
&& DECL_VTABLE_OR_VTT_P (decl)), 20040803);
/* Entities not associated with any class just get the
visibility specified by their attributes. */
return;
}
/* By default, static data members and function members receive
the visibility of their containing class. */
if (class_type
&& (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL)
&& !lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
{
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)
&& visibility_options.inlines_hidden)
{
DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
DECL_VISIBILITY_SPECIFIED (decl) = 1;
}
else
{
DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
DECL_VISIBILITY_SPECIFIED (decl)
= CLASSTYPE_VISIBILITY_SPECIFIED (class_type);
}
}
}
/* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage
for DECL has not already been determined, do so now by setting
DECL_EXTERNAL, DECL_COMDAT and other related flags. Until this

View File

@ -368,7 +368,8 @@ 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);
DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
= DECL_VISIBILITY_SPECIFIED (function);
if (flag_weak && TREE_PUBLIC (thunk_fndecl))
comdat_linkage (thunk_fndecl);

View File

@ -6312,10 +6312,13 @@ cp_parser_condition (cp_parser* parser)
for sure. */
if (cp_parser_parse_definitely (parser))
{
bool pop_p;
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
/*initialized_p=*/true,
attributes, /*prefix_attributes=*/NULL_TREE);
attributes, /*prefix_attributes=*/NULL_TREE,
&pop_p);
/* Parse the assignment-expression. */
initializer = cp_parser_assignment_expression (parser);
@ -6324,6 +6327,8 @@ cp_parser_condition (cp_parser* parser)
initializer,
asm_specification,
LOOKUP_ONLYCONVERTING);
if (pop_p)
pop_scope (DECL_CONTEXT (decl));
return convert_from_reference (decl);
}
@ -10630,12 +10635,12 @@ cp_parser_init_declarator (cp_parser* parser,
have_extern_spec = false;
}
decl = start_decl (declarator, decl_specifiers,
is_initialized, attributes, prefix_attributes);
is_initialized, attributes, prefix_attributes,
&pop_p);
}
/* Enter the SCOPE. That way unqualified names appearing in the
initializer will be looked up in SCOPE. */
if (scope)
else if (scope)
/* Enter the SCOPE. That way unqualified names appearing in the
initializer will be looked up in SCOPE. */
pop_p = push_scope (scope);
/* Perform deferred access control checks, now that we know in which
@ -10682,17 +10687,12 @@ cp_parser_init_declarator (cp_parser* parser,
if (cp_parser_attributes_opt (parser))
warning ("attributes after parenthesized initializer ignored");
/* Leave the SCOPE, now that we have processed the initializer. It
is important to do this before calling cp_finish_decl because it
makes decisions about whether to create DECL_EXPRs or not based
on the current scope. */
if (pop_p)
pop_scope (scope);
/* For an in-class declaration, use `grokfield' to create the
declaration. */
if (member_p)
{
if (pop_p)
pop_scope (scope);
decl = grokfield (declarator, decl_specifiers,
initializer, /*asmspec=*/NULL_TREE,
/*attributes=*/NULL_TREE);
@ -10703,15 +10703,19 @@ cp_parser_init_declarator (cp_parser* parser,
/* Finish processing the declaration. But, skip friend
declarations. */
if (!friend_p && decl)
cp_finish_decl (decl,
initializer,
asm_specification,
/* If the initializer is in parentheses, then this is
a direct-initialization, which means that an
`explicit' constructor is OK. Otherwise, an
`explicit' constructor cannot be used. */
((is_parenthesized_init || !is_initialized)
{
cp_finish_decl (decl,
initializer,
asm_specification,
/* If the initializer is in parentheses, then this is
a direct-initialization, which means that an
`explicit' constructor is OK. Otherwise, an
`explicit' constructor cannot be used. */
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
if (pop_p)
pop_scope (DECL_CONTEXT (decl));
}
/* Remember whether or not variables were initialized by
constant-expressions. */

View File

@ -11162,20 +11162,13 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok)
we have a chance to determine linkage. */
DECL_EXTERNAL (d) = 0;
/* This is done in analogous to `start_decl'. It is required
for correct access checking. */
/* Enter the scope of D so that access-checking works correctly. */
push_nested_class (DECL_CONTEXT (d));
cp_finish_decl (d,
(!DECL_INITIALIZED_IN_CLASS_P (d)
? DECL_INITIAL (d) : NULL_TREE),
NULL_TREE, 0);
/* Normally, pop_nested_class is called by cp_finish_decl above.
But when instantiate_decl is triggered during
instantiate_class_template processing, its DECL_CONTEXT is
still not completed yet, and pop_nested_class isn't
called. */
if (!COMPLETE_TYPE_P (DECL_CONTEXT (d)))
pop_nested_class ();
pop_nested_class ();
}
else if (TREE_CODE (d) == FUNCTION_DECL)
{

View File

@ -346,6 +346,8 @@ get_tinfo_decl (tree type)
d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
SET_DECL_ASSEMBLER_NAME (d, name);
/* Remember the type it is for. */
TREE_TYPE (name) = type;
DECL_TINFO_P (d) = 1;
DECL_ARTIFICIAL (d) = 1;
TREE_READONLY (d) = 1;
@ -354,19 +356,10 @@ get_tinfo_decl (tree type)
define it later if we need to do so. */
DECL_EXTERNAL (d) = 1;
DECL_NOT_REALLY_EXTERN (d) = 1;
set_linkage_according_to_type (type, d);
pushdecl_top_level_and_finish (d, NULL_TREE);
if (CLASS_TYPE_P (type))
{
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;
CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
set_linkage_according_to_type (type, d);
pushdecl_top_level_and_finish (d, NULL_TREE);
/* Add decl to the global array of tinfo decls. */
my_friendly_assert (unemitted_tinfo_decls != 0, 20030312);
@ -791,18 +784,12 @@ tinfo_base_init (tree desc, tree target)
TREE_TYPE (name_name) = target;
name_decl = build_lang_decl (VAR_DECL, name_name, name_type);
SET_DECL_ASSEMBLER_NAME (name_decl, name_name);
DECL_ARTIFICIAL (name_decl) = 1;
TREE_READONLY (name_decl) = 1;
TREE_STATIC (name_decl) = 1;
DECL_EXTERNAL (name_decl) = 0;
DECL_TINFO_P (name_decl) = 1;
if (CLASS_TYPE_P (target))
{
DECL_VISIBILITY (name_decl) = CLASSTYPE_VISIBILITY (target);
DECL_VISIBILITY_SPECIFIED (name_decl)
= CLASSTYPE_VISIBILITY_SPECIFIED (target);
}
if (involves_incomplete_p (target))
{
TREE_PUBLIC (name_decl) = 0;
@ -811,10 +798,6 @@ tinfo_base_init (tree desc, tree target)
else
set_linkage_according_to_type (target, name_decl);
import_export_decl (name_decl);
/* External name of the string containing the type's name has a
special name. */
SET_DECL_ASSEMBLER_NAME (name_decl,
mangle_typeinfo_string_for_type (target));
DECL_INITIAL (name_decl) = name_string;
mark_used (name_decl);
pushdecl_top_level_and_finish (name_decl, name_string);

View File

@ -0,0 +1,17 @@
/* { dg-do compile } */
/* { dg-require-visibility "" } */
/* { dg-final { scan-assembler "\\.hidden.*_ZN1DaSERKS_" } } */
struct B {
B& operator=(const B&);
};
struct D : public B {
// The implicit assignment operator should be hidden.
} __attribute__((visibility("hidden")));
D d1, d2;
void f() {
d1 = d2;
}

View File

@ -0,0 +1,14 @@
// { dg-require-visibility }
// { dg-do compile }
// { dg-options "-fvisibility=hidden" }
// { dg-final { scan-assembler-not "\\.hidden\[^\n\]*_Znwj" } }
void f() {
new int;
}
void *g();
void *operator new(__SIZE_TYPE__) {
return g();
}