This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ patch] [PR 9283] Implement per-class visibility (new patch)
- From: Brian Ryner <bryner at brianryner dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 05 Apr 2004 04:21:21 -0700
- Subject: [C++ patch] [PR 9283] Implement per-class visibility (new patch)
This patch implement per class/struct visibility for C++. I've revised the
patch per suggestions from Jason Merrill, and also improved the testcase based
on suggestions from Jakub Jelinek.
The main change from my previous patch is to use the class type's TYPE_NAME decl
to hold the class visibility, rather than storing it on the class stack.
Additionally, I made the visibility attribute be added to the DECL_ATTRIBUTES
list (previously it was not)... this is needed to determine that a member
explicitly overrides the class visibility with visibility("default").
I do have a couple of things in the patch I'm not 100% sure about:
- In c-common.c (handle_visibility_attribute), is the TREE_CODE (*node) !=
RECORD_TYPE correct?
- In rtti.c (tinfo_base_init), is 'target' the correct type to get the
visibility from?
Bootstrapped and passed all test suites on i686-pc-linux-gnu.
--
-Brian Ryner
bryner@brianryner.com
gcc/
2004-04-05 Brian Ryner <bryner@brianryner.com>
PR c++/9283
* 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.
gcc/cp
2004-04-05 Brian Ryner <bryner@brianryner.com>
PR c++/9283
* class.c (CURRENT_VISIBILITY): Add macro.
(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.
* rtti.c (get_tinfo_decl): Set typeinfo visibility to class visibility.
(tinfo_base_init): Set typeinfo name visibility to class visibility.
Index: c-common.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.494
diff -u -p -c -3 -p -r1.494 c-common.c
*** c-common.c 1 Apr 2004 03:50:26 -0000 1.494
--- c-common.c 5 Apr 2004 10:56:34 -0000
*************** const struct attribute_spec c_common_att
*** 832,838 ****
handle_deprecated_attribute },
{ "vector_size", 1, 1, false, true, false,
handle_vector_size_attribute },
! { "visibility", 1, 1, true, false, false,
handle_visibility_attribute },
{ "tls_model", 1, 1, true, false, false,
handle_tls_model_attribute },
--- 832,838 ----
handle_deprecated_attribute },
{ "vector_size", 1, 1, false, true, false,
handle_vector_size_attribute },
! { "visibility", 1, 1, false, false, false,
handle_visibility_attribute },
{ "tls_model", 1, 1, true, false, false,
handle_tls_model_attribute },
*************** handle_visibility_attribute (tree *node,
*** 4855,4861 ****
*no_add_attrs = true;
! if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
{
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
return NULL_TREE;
--- 4855,4870 ----
*no_add_attrs = true;
! /* 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 (TREE_CODE (*node) != RECORD_TYPE
! && (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl)))
{
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
return NULL_TREE;
*************** handle_visibility_attribute (tree *node,
*** 4877,4882 ****
--- 4886,4898 ----
DECL_VISIBILITY (decl) = VISIBILITY_PROTECTED;
else
error ("visibility arg must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+
+ /* 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;
}
Index: cp/class.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.606
diff -u -p -c -3 -p -r1.606 class.c
*** cp/class.c 1 Apr 2004 13:41:36 -0000 1.606
--- cp/class.c 5 Apr 2004 10:56:38 -0000
*************** typedef int (*subobject_offset_fn) (tree
*** 102,107 ****
--- 102,110 ----
static int current_class_stack_size;
static class_stack_node_t current_class_stack;
+ /* Convenience macro for class visibility. */
+ #define CURRENT_VISIBILITY DECL_VISIBILITY (TYPE_NAME (current_class_type))
+
/* An array of all local classes present in this translation unit, in
declaration order. */
varray_type local_classes;
*************** build_vtable (tree class_type, tree name
*** 524,529 ****
--- 527,535 ----
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) = DECL_VISIBILITY (TYPE_NAME (class_type));
import_export_vtable (decl, class_type, 0);
return decl;
*************** check_field_decls (tree t, tree *access_
*** 2971,2977 ****
continue;
if (TREE_CODE (x) == CONST_DECL || TREE_CODE (x) == VAR_DECL)
! continue;
/* Now it can only be a FIELD_DECL. */
--- 2977,2990 ----
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)))
! DECL_VISIBILITY (x) = CURRENT_VISIBILITY;
!
! continue;
! }
/* Now it can only be a FIELD_DECL. */
*************** check_methods (tree t)
*** 3703,3708 ****
--- 3716,3726 ----
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)))
+ DECL_VISIBILITY (x) = CURRENT_VISIBILITY;
/* The name of the field is the original field name
Save this in auxiliary field for later overloading. */
Index: cp/rtti.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/rtti.c,v
retrieving revision 1.179
diff -u -p -c -3 -p -r1.179 rtti.c
*** cp/rtti.c 8 Mar 2004 22:24:35 -0000 1.179
--- cp/rtti.c 5 Apr 2004 10:56:38 -0000
*************** get_tinfo_decl (tree type)
*** 361,367 ****
pushdecl_top_level_and_finish (d, NULL_TREE);
if (CLASS_TYPE_P (type))
! CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
/* Remember the type it is for. */
TREE_TYPE (name) = type;
--- 361,370 ----
pushdecl_top_level_and_finish (d, NULL_TREE);
if (CLASS_TYPE_P (type))
! {
! CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
! DECL_VISIBILITY (d) = DECL_VISIBILITY (TYPE_NAME (type));
! }
/* Remember the type it is for. */
TREE_TYPE (name) = type;
*************** tinfo_base_init (tree desc, tree target)
*** 759,764 ****
--- 762,769 ----
TREE_STATIC (name_decl) = 1;
DECL_EXTERNAL (name_decl) = 0;
TREE_PUBLIC (name_decl) = 1;
+ if (CLASS_TYPE_P (target))
+ DECL_VISIBILITY (name_decl) = DECL_VISIBILITY (TYPE_NAME (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. */
/* Test class visibility specification. */
/* { dg-do compile { target *86-*-linux* } } */
/* { dg-final { scan-assembler "\.hidden\[ \t\]*_ZN1A7hidden1Ev" } } */
/* { dg-final { scan-assembler "\.hidden\[ \t\]*_ZN1A7hidden2Ev" } } */
/* { dg-final { scan-assembler-not "\.hidden\[ \t\]*_ZN1A8visible1Ev" } } */
/* { dg-final { scan-assembler "\.hidden\[ \t\]*_ZTV1A" } } */
/* { dg-final { scan-assembler "\.hidden\[ \t\]*_ZTI1A" } } */
/* { dg-final { scan-assembler "\.hidden\[ \t\]*_ZTS1A" } } */
struct __attribute__((visibility ("hidden"))) A
{
virtual void hidden1();
void hidden2() __attribute__((visibility ("hidden")));
void visible1() __attribute__((visibility ("default")));
};
void
A::hidden1()
{
}
void
A::hidden2()
{
}
void
A::visible1()
{
}