From d3ecb597b35d5b8c4176a0b60c10cbfdb40ace8b Mon Sep 17 00:00:00 2001 From: Bryce McKinlay Date: Sat, 10 Jul 2004 05:38:15 +0000 Subject: [PATCH] re PR java/8618 (call to private constructor allowed for anonymous inner class) 2004-07-09 Bryce McKinlay PR java/8618 * parse.y (create_anonymous_class): Remove 'location' argument. Use the WFL from TYPE_NAME to get line number for the decl. Fix comment. (craft_constructor): Inherit access flags for implicit constructor from the enclosing class. (create_class): Fix comment typo. (resolve_qualified_expression_name): Pass type of qualifier to not_accessible_p, not the type in which target field was found. (not_accessible_p): Handle inner classes. Expand protected qualifier-subtype check to enclosing instances, but don't apply this check to static members. Allow protected access to inner classes of a subtype. Allow private access within common enclosing context. (build_super_invocation): Get WFL line number info from current class decl. (build_incomplete_class_ref): Update for new create_anonymous_class signature. * parse.h (INNER_ENCLOSING_SCOPE_CHECK): Use common_enclosing_instance_p. * class.c (common_enclosing_context_p): New. Determine if types share a common enclosing context, even across static contexts. (common_enclosing_instance_p): Renamed from common_enclosing_context_p. Determines if types share a common non-static enclosing instance. * java-tree.h (common_enclosing_instance_p): Declare. * jcf-write.c (get_method_access_flags): New. Surpress private flag for inner class constructors. (generate_classfile): Use get_method_access_flags. From-SVN: r84443 --- gcc/java/ChangeLog | 30 +++++++++++++++ gcc/java/class.c | 26 ++++++++++++- gcc/java/java-tree.h | 1 + gcc/java/jcf-write.c | 18 ++++++++- gcc/java/parse.h | 2 +- gcc/java/parse.y | 88 ++++++++++++++++++++++++++------------------ 6 files changed, 125 insertions(+), 40 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index b2492677b21..fea2c218baf 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,33 @@ +2004-07-09 Bryce McKinlay + + PR java/8618 + * parse.y (create_anonymous_class): Remove 'location' argument. Use + the WFL from TYPE_NAME to get line number for the decl. Fix comment. + (craft_constructor): Inherit access flags for implicit constructor + from the enclosing class. + (create_class): Fix comment typo. + (resolve_qualified_expression_name): Pass type of qualifier to + not_accessible_p, not the type in which target field was found. + (not_accessible_p): Handle inner classes. Expand protected + qualifier-subtype check to enclosing instances, but don't apply this + check to static members. Allow protected access to inner classes + of a subtype. Allow private access within common enclosing context. + (build_super_invocation): Get WFL line number info from current + class decl. + (build_incomplete_class_ref): Update for new create_anonymous_class + signature. + * parse.h (INNER_ENCLOSING_SCOPE_CHECK): Use + common_enclosing_instance_p. + * class.c (common_enclosing_context_p): New. Determine if types + share a common enclosing context, even across static contexts. + (common_enclosing_instance_p): Renamed from + common_enclosing_context_p. Determines if types share a common + non-static enclosing instance. + * java-tree.h (common_enclosing_instance_p): Declare. + * jcf-write.c (get_method_access_flags): New. Surpress private flag + for inner class constructors. + (generate_classfile): Use get_method_access_flags. + 2004-07-09 Bryce McKinlay * class.c (interface_of_p): Check for null TYPE_BINFO. diff --git a/gcc/java/class.c b/gcc/java/class.c index 90f2789c8e8..1273b62155f 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -587,11 +587,33 @@ enclosing_context_p (tree type1, tree type2) return 0; } -/* Return 1 iff there exists a common enclosing context between TYPE1 - and TYPE2. */ + +/* Return 1 iff TYPE1 and TYPE2 share a common enclosing class, regardless of + nesting level. */ int common_enclosing_context_p (tree type1, tree type2) +{ + for (type1; type1; + type1 = (INNER_CLASS_TYPE_P (type1) ? + TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))) : NULL_TREE)) + { + tree current; + for (current = type2; current; + current = (INNER_CLASS_TYPE_P (current) ? + TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current))) : + NULL_TREE)) + if (type1 == current) + return 1; + } + return 0; +} + +/* Return 1 iff there exists a common enclosing "this" between TYPE1 + and TYPE2, without crossing any static context. */ + +int +common_enclosing_instance_p (tree type1, tree type2) { if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2)) return 0; diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 1fef83260d0..d9e641547bd 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -1238,6 +1238,7 @@ extern int get_access_flags_from_decl (tree); extern int interface_of_p (tree, tree); extern int inherits_from_p (tree, tree); extern int common_enclosing_context_p (tree, tree); +extern int common_enclosing_instance_p (tree, tree); extern int enclosing_context_p (tree, tree); extern tree build_result_decl (tree); extern void emit_handlers (void); diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index c95df1eb561..e34543c44c7 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -2903,6 +2903,22 @@ get_classfile_modifiers (tree class) return flags; } +/* Get the access flags (modifiers) for a method to be used in the class + file. */ + +static int +get_method_access_flags (tree decl) +{ + int flags = get_access_flags (decl); + + /* Promote "private" inner-class constructors to package-private. */ + if (DECL_CONSTRUCTOR_P (decl) + && INNER_CLASS_DECL_P (TYPE_NAME (DECL_CONTEXT (decl)))) + flags &= ~(ACC_PRIVATE); + + return flags; +} + /* Generate and return a list of chunks containing the class CLAS in the .class file representation. The list can be written to a .class file using write_chunks. Allocate chunks from obstack WORK. */ @@ -3034,7 +3050,7 @@ generate_classfile (tree clas, struct jcf_partial *state) current_function_decl = part; ptr = append_chunk (NULL, 8, state); - i = get_access_flags (part); PUT2 (i); + i = get_method_access_flags (part); PUT2 (i); i = find_utf8_constant (&state->cpool, name); PUT2 (i); i = find_utf8_constant (&state->cpool, build_java_signature (type)); PUT2 (i); diff --git a/gcc/java/parse.h b/gcc/java/parse.h index cf62dae8446..f0fb67acdb0 100644 --- a/gcc/java/parse.h +++ b/gcc/java/parse.h @@ -842,7 +842,7 @@ struct parser_ctxt GTY(()) { != TYPE_NAME (TREE_TYPE (TREE_TYPE (current_this)))) \ && !inherits_from_p (TREE_TYPE (TREE_TYPE (current_this)), \ TREE_TYPE (DECL_CONTEXT (TYPE_NAME (T)))) \ - && !common_enclosing_context_p (TREE_TYPE (TREE_TYPE (current_this)), \ + && !common_enclosing_instance_p (TREE_TYPE (TREE_TYPE (current_this)),\ (T)) \ && INNER_CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_this))) \ && !inherits_from_p \ diff --git a/gcc/java/parse.y b/gcc/java/parse.y index 3df330d3c25..8d65bd1e52f 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -320,7 +320,7 @@ static int outer_field_expanded_access_p (tree, tree *, static tree outer_field_access_fix (tree, tree, tree); static tree build_incomplete_class_ref (int, tree); static tree patch_incomplete_class_ref (tree); -static tree create_anonymous_class (int, tree); +static tree create_anonymous_class (tree); static void patch_anonymous_class (tree, tree, tree); static void add_inner_class_fields (tree, tree); @@ -2034,7 +2034,7 @@ class_instance_creation_expression: anonymous_class_creation: NEW_TK class_type OP_TK argument_list CP_TK - { create_anonymous_class ($1.location, $2); } + { create_anonymous_class ($2); } class_body { tree id = build_wfl_node (DECL_NAME (GET_CPC ())); @@ -2067,7 +2067,7 @@ anonymous_class_creation: } | NEW_TK class_type OP_TK CP_TK - { create_anonymous_class ($1.location, $2); } + { create_anonymous_class ($2); } class_body { tree id = build_wfl_node (DECL_NAME (GET_CPC ())); @@ -3905,8 +3905,11 @@ patch_anonymous_class (tree type_decl, tree class_decl, tree wfl) } } +/* Create an anonymous class which extends/implements TYPE_NAME, and return + its decl. */ + static tree -create_anonymous_class (int location, tree type_name) +create_anonymous_class (tree type_name) { char buffer [80]; tree super = NULL_TREE, itf = NULL_TREE; @@ -3915,7 +3918,7 @@ create_anonymous_class (int location, tree type_name) /* The unqualified name of the anonymous class. It's just a number. */ sprintf (buffer, "%d", anonymous_class_counter++); id = build_wfl_node (get_identifier (buffer)); - EXPR_WFL_LINECOL (id) = location; + EXPR_WFL_LINECOL (id) = EXPR_WFL_LINECOL (type_name); /* We know about the type to extend/implement. We go ahead */ if ((type_decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (type_name)))) @@ -4035,7 +4038,7 @@ create_class (int flags, tree id, tree super, tree interfaces) /* Add the private this$ field, Replicate final locals still in scope as private final fields mangled like val$. - This doesn't not occur for top level (static) inner classes. */ + This does not occur for top level (static) inner classes. */ if (PURE_INNER_CLASS_DECL_P (decl)) add_inner_class_fields (decl, current_function_decl); @@ -5393,8 +5396,9 @@ craft_constructor (tree class_decl, tree args) { tree class_type = TREE_TYPE (class_decl); tree parm = NULL_TREE; - int flags = (get_access_flags_from_decl (class_decl) & ACC_PUBLIC ? - ACC_PUBLIC : 0); + /* Inherit access flags for the constructor from its enclosing class. */ + int valid_ctor_flags = ACC_PUBLIC | ACC_PROTECTED | ACC_PRIVATE; + int flags = (get_access_flags_from_decl (class_decl) & valid_ctor_flags); int i = 0, artificial = 0; tree decl, ctor_name; char buffer [80]; @@ -9961,7 +9965,7 @@ resolve_qualified_expression_name (tree wfl, tree *found_decl, /* Check on accessibility here */ if (not_accessible_p (current_class, field_decl, - DECL_CONTEXT (field_decl), from_super)) + *type_found, from_super)) return not_accessible_field_error (qual_wfl,field_decl); check_deprecation (qual_wfl, field_decl); @@ -10047,10 +10051,13 @@ static int not_accessible_p (tree reference, tree member, tree where, int from_super) { int access_flag = get_access_flags_from_decl (member); - - /* Inner classes are processed by check_inner_class_access */ - if (INNER_CLASS_TYPE_P (reference)) - return 0; + bool is_static = false; + + if (TREE_CODE (member) == FIELD_DECL || + TREE_CODE (member) == VAR_DECL) + is_static = FIELD_STATIC (member); + else + is_static = METHOD_STATIC (member); /* Access always granted for members declared public */ if (access_flag & ACC_PUBLIC) @@ -10069,26 +10076,34 @@ not_accessible_p (tree reference, tree member, tree where, int from_super) if (from_super) return 0; - /* If where is active, access was made through a - qualifier. Access is granted if the type of the qualifier is - or is a sublass of the type the access made from (6.6.2.1.) */ - if (where && !inherits_from_p (reference, where)) - return 1; - - /* Otherwise, access is granted if occurring from the class where - member is declared or a subclass of it. Find the right - context to perform the check */ - if (PURE_INNER_CLASS_TYPE_P (reference)) + /* If WHERE is active, access was made through a qualifier. For + non-static members, access is granted if the type of the qualifier + is or is a sublass of the type the access is made from (6.6.2.1.) */ + if (where && !is_static) { - while (INNER_CLASS_TYPE_P (reference)) + while (reference) { - if (inherits_from_p (reference, DECL_CONTEXT (member))) - return 0; - reference = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (reference))); - } + if (inherits_from_p (where, reference)) + return 0; + if (PURE_INNER_CLASS_TYPE_P (reference)) + reference = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (reference))); + else + break; + } + return 1; + } + + /* Otherwise, access is granted if occurring from within the class + where member is declared, or a subclass of it. */ + while (reference) + { + if (inherits_from_p (reference, DECL_CONTEXT (member))) + return 0; + if (PURE_INNER_CLASS_TYPE_P (reference)) + reference = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (reference))); + else + break; } - if (inherits_from_p (reference, DECL_CONTEXT (member))) - return 0; return 1; } @@ -10097,9 +10112,8 @@ not_accessible_p (tree reference, tree member, tree where, int from_super) it for innerclasses too. */ if (access_flag & ACC_PRIVATE) { - if (reference == DECL_CONTEXT (member)) - return 0; - if (enclosing_context_p (reference, DECL_CONTEXT (member))) + if (reference == DECL_CONTEXT (member) || + common_enclosing_context_p (DECL_CONTEXT (member), reference)) return 0; return 1; } @@ -10506,8 +10520,6 @@ patch_method_invocation (tree patch, tree primary, tree where, int from_super, IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))); const char *const what = (DECL_CONSTRUCTOR_P (list) ? "constructor" : "method"); - /* FIXME: WFL yields the wrong message here but I don't know - what else to use. */ parse_error_context (wfl, "Can't access %s %s `%s.%s' from `%s'", access, what, klass, fct_name, refklass); @@ -12343,6 +12355,10 @@ build_super_invocation (tree mdecl) else { tree super_wfl = build_wfl_node (super_identifier_node); + /* This is called after parsing is done, so the parser context + won't be accurate. Set location info from current_class decl. */ + tree class_wfl = lookup_cl (TYPE_NAME (current_class)); + EXPR_WFL_LINECOL (super_wfl) = EXPR_WFL_LINECOL (class_wfl); tree a = NULL_TREE, t; /* If we're dealing with an anonymous class, pass the arguments of the crafted constructor along. */ @@ -13922,7 +13938,7 @@ build_incomplete_class_ref (int location, tree class_name) /* We want the generated inner class inside the outermost class. */ GET_CPC_LIST() = cpc; t = build_wfl_node (DECL_NAME (TYPE_NAME (object_type_node))); - inner = create_anonymous_class (0, t); + inner = create_anonymous_class (t); target_class = TREE_TYPE (inner); end_class_declaration (1); GET_CPC_LIST() = cpc_list; -- 2.30.2