aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl2.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2006-06-29 21:15:56 -0400
committerJason Merrill <jason@gcc.gnu.org>2006-06-29 21:15:56 -0400
commitb9e75696307f710a22c726e72b00e7a7161ad89f (patch)
tree93c1ec7ec5a70cb4b7384fa239594ed2f1288585 /gcc/cp/decl2.c
parentdc2843f38c04c81e9f20a6e9e6ae9637ace6e08c (diff)
downloadgcc-b9e75696307f710a22c726e72b00e7a7161ad89f.zip
gcc-b9e75696307f710a22c726e72b00e7a7161ad89f.tar.gz
gcc-b9e75696307f710a22c726e72b00e7a7161ad89f.tar.bz2
re PR c++/26905 (default-visibility class symbol improperly resolved as hidden-visibility)
PR c++/26905 PR c++/26612 PR c++/27000 PR c++/26984 PR c++/19134 * tree.c (build_decl_stat): Don't hande #pragma visibility here. * c-common.c (c_determine_visibility): Handle it here. * c-decl.c (finish_decl): Call c_determine_visibility for functions, too. * flags.h (enum symbol_visibility): Sort from most to least visibility. * tree.h: Likewise. * varasm.c (default_assemble_visibility): Likewise. * c-common.c (handle_visibility_attribute): Complain about trying to give visibility to an already defined class, or trying to change declared visibility. Always attach the attribute. * cp/decl2.c (determine_visibility): Overhaul. (determine_visibility_from_class): Likewise. (min_vis_r, type_visibility, constrain_visibility): New fns. (constrain_visibility_for_template): Likewise. (constrain_class_visibility): Likewise. * cp/decl.c (cp_finish_decl): Call determine_visibility for function decls, too. * cp/name-lookup.c (pushtag): Call determine_visibility. * cp/decl.c (duplicate_decls): Don't copy visibility from template to specialization. * cp/pt.c (check_explicit_specialization): Likewise. (lookup_template_class, tsubst_decl): Call determine_visibility. * cp/class.c (finish_struct_1): Call constrain_class_visibility. PR c++/26905 PR c++/21675 PR c++/17470 * cp/parser.c (cp_parser_explicit_instantiation): Pass the attributes to grokdeclarator. (cp_parser_type_specifier): Allow 'enum __attribute ((...)) E'. (cp_parser_enum_specifier): Likewise. (cp_parser_elaborated_type_specifier): Apply attributes if this declares only the class. (cp_parser_class_specifier): Apply leading attributes immediately. * cp/semantics.c (begin_class_definition): Add attributes parameter, apply them to the type. * attribs.c (decl_attributes): Ignore type-in-place attributes once the type has been defined. PR c++/21581 PR c++/25915 * cp/tree.c (decl_anon_ns_mem_p): New function. * cp/cp-tree.h: Declare it. * cp/decl2.c (determine_visibility): Make anonymous namespace members static. (min_vis_r, constrain_visibility): Likewise. * cp/rtti.c (create_pseudo_type_info): Set TREE_PUBLIC on pseudo-types. * cp/decl.c (cxx_init_decl_processing): Set TREE_PUBLIC on global_namespace. * cp/name-lookup.c (push_namespace_with_attribs): Don't set TREE_PUBLIC on anonymous namespaces. From-SVN: r115086
Diffstat (limited to 'gcc/cp/decl2.c')
-rw-r--r--gcc/cp/decl2.c320
1 files changed, 257 insertions, 63 deletions
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 80fcc29..0a12a38 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1533,6 +1533,110 @@ maybe_emit_vtables (tree ctype)
return true;
}
+/* A special return value from type_visibility meaning internal
+ linkage. */
+
+enum { VISIBILITY_STATIC = VISIBILITY_INTERNAL+1 };
+
+/* walk_tree helper function for type_visibility. */
+
+static tree
+min_vis_r (tree *tp, int *walk_subtrees, void *data)
+{
+ int *vis_p = (int *)data;
+ if (! TYPE_P (*tp))
+ {
+ *walk_subtrees = 0;
+ }
+ else if (CLASS_TYPE_P (*tp))
+ {
+ if (!TREE_PUBLIC (TYPE_MAIN_DECL (*tp)))
+ {
+ *vis_p = VISIBILITY_STATIC;
+ return *tp;
+ }
+ else if (CLASSTYPE_VISIBILITY (*tp) > *vis_p)
+ *vis_p = CLASSTYPE_VISIBILITY (*tp);
+ }
+ return NULL;
+}
+
+/* Returns the visibility of TYPE, which is the minimum visibility of its
+ component types. */
+
+static int
+type_visibility (tree type)
+{
+ int vis = VISIBILITY_DEFAULT;
+ walk_tree_without_duplicates (&type, min_vis_r, &vis);
+ return vis;
+}
+
+/* Limit the visibility of DECL to VISIBILITY. SPECIFIED is true if the
+ constraint comes from an attribute or pragma; REASON is the source of
+ the constraint. */
+
+static bool
+constrain_visibility (tree decl, int visibility, bool specified,
+ const char *reason)
+{
+ if (visibility == VISIBILITY_STATIC)
+ {
+ TREE_PUBLIC (decl) = 0;
+ DECL_INTERFACE_KNOWN (decl) = 1;
+ if (DECL_LANG_SPECIFIC (decl))
+ DECL_NOT_REALLY_EXTERN (decl) = 1;
+ }
+ else if (visibility > DECL_VISIBILITY (decl))
+ {
+ if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
+ warning (OPT_Wattributes, "%q+D: visibility attribute requests "
+ "greater visibility than its %s allows", decl, reason);
+ DECL_VISIBILITY (decl) = visibility;
+ if (!DECL_VISIBILITY_SPECIFIED (decl))
+ DECL_VISIBILITY_SPECIFIED (decl) = specified;
+ return true;
+ }
+ return false;
+}
+
+/* Constrain the visibility of DECL based on the visbility of its template
+ arguments. */
+
+static void
+constrain_visibility_for_template (tree decl, tree targs)
+{
+ /* If this is a template instantiation, check the innermost
+ template args for visibility constraints. The outer template
+ args are covered by the class check. */
+ tree args = INNERMOST_TEMPLATE_ARGS (targs);
+ int i;
+ for (i = TREE_VEC_LENGTH (args); i > 0; --i)
+ {
+ int vis = 0;
+
+ tree arg = TREE_VEC_ELT (args, i-1);
+ if (TYPE_P (arg))
+ vis = type_visibility (arg);
+ else if (TREE_TYPE (arg) && POINTER_TYPE_P (TREE_TYPE (arg)))
+ {
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ arg = TREE_OPERAND (arg, 0);
+ if (TREE_CODE (arg) == VAR_DECL
+ || TREE_CODE (arg) == FUNCTION_DECL)
+ {
+ if (! TREE_PUBLIC (arg))
+ vis = VISIBILITY_STATIC;
+ else
+ vis = DECL_VISIBILITY (arg);
+ }
+ }
+ if (vis)
+ constrain_visibility (decl, vis, false, "template parameter");
+ }
+}
+
/* Like c_determine_visibility, but with additional C++-specific
behavior.
@@ -1544,12 +1648,18 @@ maybe_emit_vtables (tree ctype)
Note that because namespaces have multiple independent definitions,
namespace visibility is handled elsewhere using the #pragma visibility
- machinery rather than by decorating the namespace declaration. */
+ machinery rather than by decorating the namespace declaration.
+
+ The goal is for constraints from the type to give a diagnostic, and
+ other constraints to be applied silently. */
void
determine_visibility (tree decl)
{
- tree class_type;
+ tree class_type = NULL_TREE;
+ bool use_template;
+
+ /* Remember that all decls get VISIBILITY_DEFAULT when built. */
/* Only relevant for names with external linkage. */
if (!TREE_PUBLIC (decl))
@@ -1560,9 +1670,30 @@ determine_visibility (tree decl)
maybe_clone_body. */
gcc_assert (!DECL_CLONED_FUNCTION_P (decl));
- /* Give the common code a chance to make a determination. */
- if (c_determine_visibility (decl))
- return;
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ if (CLASS_TYPE_P (TREE_TYPE (decl)))
+ use_template = CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl));
+ else if (TYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
+ use_template = 1;
+ else
+ use_template = 0;
+ }
+ else if (DECL_LANG_SPECIFIC (decl))
+ use_template = DECL_USE_TEMPLATE (decl);
+ else
+ use_template = 0;
+
+ /* Anything that is exported must have default visibility. */
+ if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ && lookup_attribute ("dllexport",
+ TREE_CODE (decl) == TYPE_DECL
+ ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
+ : DECL_ATTRIBUTES (decl)))
+ {
+ DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+ }
/* If DECL is a member of a class, visibility specifiers on the
class can influence the visibility of the DECL. */
@@ -1574,6 +1705,8 @@ determine_visibility (tree decl)
class_type = TREE_TYPE (DECL_NAME (decl));
else
{
+ /* Not a class member. */
+
/* Virtual tables have DECL_CONTEXT set to their associated class,
so they are automatically handled above. */
gcc_assert (TREE_CODE (decl) != VAR_DECL
@@ -1581,77 +1714,138 @@ determine_visibility (tree decl)
if (DECL_FUNCTION_SCOPE_P (decl))
{
+ /* Local statics and classes get the visibility of their
+ containing function. */
tree fn = DECL_CONTEXT (decl);
DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn);
- }
- /* Entities not associated with any class just get the
- visibility specified by their attributes. */
- return;
+ /* Local classes in templates have CLASSTYPE_USE_TEMPLATE set,
+ but have no TEMPLATE_INFO, so don't try to check it. */
+ use_template = 0;
+ }
+ else if (TREE_CODE (decl) == VAR_DECL && DECL_TINFO_P (decl))
+ {
+ /* tinfo visibility is based on the type it's for. */
+ constrain_visibility
+ (decl, type_visibility (TREE_TYPE (DECL_NAME (decl))),
+ false, "type");
+ }
+ else if (use_template)
+ /* Template instantiations and specializations get visibility based
+ on their template unless they override it with an attribute. */;
+ else if (! DECL_VISIBILITY_SPECIFIED (decl))
+ {
+ /* Set default visibility to whatever the user supplied with
+ #pragma GCC visibility or a namespace visibility attribute. */
+ DECL_VISIBILITY (decl) = default_visibility;
+ DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma;
+ }
}
- /* By default, static data members and function members receive
- the visibility of their containing class. */
- if (class_type)
+ if (use_template)
{
- determine_visibility_from_class (decl, class_type);
-
- /* Give the target a chance to override the visibility associated
- with DECL. */
- if (TREE_CODE (decl) == VAR_DECL
- && (DECL_TINFO_P (decl)
- || (DECL_VTABLE_OR_VTT_P (decl)
- /* Construction virtual tables are not exported because
- they cannot be referred to from other object files;
- their name is not standardized by the ABI. */
- && !DECL_CONSTRUCTION_VTABLE_P (decl)))
- && TREE_PUBLIC (decl)
- && !DECL_REALLY_EXTERN (decl)
- && DECL_VISIBILITY_SPECIFIED (decl)
- && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)))
- targetm.cxx.determine_class_data_visibility (decl);
+ tree tinfo = (TREE_CODE (decl) == TYPE_DECL
+ ? TYPE_TEMPLATE_INFO (TREE_TYPE (decl))
+ : DECL_TEMPLATE_INFO (decl));
+ tree args = TI_ARGS (tinfo);
+ int depth = TMPL_ARGS_DEPTH (args);
+
+ /* If the template has explicit visibility and the specialization
+ doesn't, use the visibility from the template. */
+ if (!DECL_VISIBILITY_SPECIFIED (decl))
+ {
+ tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
+ DECL_VISIBILITY (decl) = DECL_VISIBILITY (pattern);
+ }
+
+ /* FIXME should TMPL_ARGS_DEPTH really return 1 for null input? */
+ if (args && depth > template_class_depth (class_type))
+ /* Don't let it have more visibility than its template type
+ arguments. */
+ constrain_visibility_for_template (decl, args);
}
+
+ if (class_type)
+ determine_visibility_from_class (decl, class_type);
+
+ /* Don't let it have more visibility than its type. */
+ if (TREE_CODE (decl) != TYPE_DECL)
+ if (constrain_visibility (decl, type_visibility (TREE_TYPE (decl)),
+ false, "type"))
+ warning (OPT_Wattributes, "\
+%q+D declared with greater visibility than its type",
+ decl);
+
+ if (decl_anon_ns_mem_p (decl))
+ /* Names in an anonymous namespace get internal linkage.
+ This might change once we implement export. */
+ constrain_visibility (decl, VISIBILITY_STATIC,
+ false, "namespace");
}
+/* By default, static data members and function members receive
+ the visibility of their containing class. */
+
static void
determine_visibility_from_class (tree decl, tree class_type)
{
- if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
- && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class_type)))
- {
- DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
- DECL_VISIBILITY_SPECIFIED (decl) = 1;
- }
- else if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_DECLARED_INLINE_P (decl)
- && visibility_options.inlines_hidden)
- {
- /* Don't change it if it has been set explicitly by user. */
- if (!DECL_VISIBILITY_SPECIFIED (decl))
- {
- DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
- DECL_VISIBILITY_SPECIFIED (decl) = 1;
- }
- }
- else if (CLASSTYPE_VISIBILITY_SPECIFIED (class_type))
- {
- DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
- DECL_VISIBILITY_SPECIFIED (decl) = 1;
- }
- else if (TYPE_CLASS_SCOPE_P (class_type))
- determine_visibility_from_class (decl, TYPE_CONTEXT (class_type));
- else if (TYPE_FUNCTION_SCOPE_P (class_type))
- {
- tree fn = TYPE_CONTEXT (class_type);
- DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
- DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn);
- }
- else if (!DECL_VISIBILITY_SPECIFIED (decl))
- {
- DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
- DECL_VISIBILITY_SPECIFIED (decl) = 0;
- }
+ if (visibility_options.inlines_hidden
+ /* Don't do this for inline templates; specializations might not be
+ inline, and we don't want them to inherit the hidden
+ visibility. We'll set it here for all inline instantiations. */
+ && !processing_template_decl
+ && ! DECL_VISIBILITY_SPECIFIED (decl)
+ && TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (decl))
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+
+ /* The decl can't have more visibility than its class. */
+ constrain_visibility (decl, CLASSTYPE_VISIBILITY (class_type),
+ CLASSTYPE_VISIBILITY_SPECIFIED (class_type),
+ "class");
+
+ /* Give the target a chance to override the visibility associated
+ with DECL. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && (DECL_TINFO_P (decl)
+ || (DECL_VTABLE_OR_VTT_P (decl)
+ /* Construction virtual tables are not exported because
+ they cannot be referred to from other object files;
+ their name is not standardized by the ABI. */
+ && !DECL_CONSTRUCTION_VTABLE_P (decl)))
+ && TREE_PUBLIC (decl)
+ && !DECL_REALLY_EXTERN (decl)
+ && DECL_VISIBILITY_SPECIFIED (decl)
+ && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)))
+ targetm.cxx.determine_class_data_visibility (decl);
+}
+
+/* Constrain the visibility of a class TYPE based on the visibility of its
+ field types. Warn if any fields require lesser visibility. */
+
+void
+constrain_class_visibility (tree type)
+{
+ tree decl = TYPE_MAIN_DECL (type);
+ tree binfo = TYPE_BINFO (type);
+ tree t;
+ int i;
+
+ for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) == FIELD_DECL)
+ if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)),
+ false, "field type"))
+ warning (OPT_Wattributes, "\
+%qT declared with greater visibility than the type of its field %qD",
+ type, t);
+
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i)
+ if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)),
+ false, "base type"))
+ warning (OPT_Wattributes, "\
+%qT declared with greater visibility than its base %qT",
+ type, TREE_TYPE (t));
}
/* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage