This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PR java/19870: Generate Synthetic Accessors For Static Private FieldAccesses Across Nested Classes
- From: Ranjit Mathew <rmathew at gmail dot com>
- To: GCJ Patches <java-patches at gcc dot gnu dot org>, GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 26 May 2005 12:57:24 +0530
- Subject: PR java/19870: Generate Synthetic Accessors For Static Private FieldAccesses Across Nested Classes
Hi,
Here is a patch for PR java/19870. This patch generalises
the current synthetic accessor generation support in GCJ for
private fields in outer classes accessed from nested classes
to additionally support:
1. private *static* fields
2. access to private static fields *inside nested classes*
(the original testcase given in PR19870)
3. access from a nested class to a private static field
in a "sibling" nested class.
The attached testsuite patch demonstrates what is now
possible to support in GCJ with this patch.
For static accessors, the initial "this$" parameter
is ommitted now.
Since the accessors work both ways now, I've renamed
all "*outer_field*" methods and macros to "*nested_field*"
for lack of a better name and updated their documentation.
Tested on i686-pc-linux-gnu with Jacks included. The Jacks
testresults were rather disappointing:
FAIL: 8.5.2-accessible-static-member-usage-3
FAIL: 15.8.4-static-2
The first is a failure to consider "foo" constant
in "case foo:" for a switch statement, where foo is
an outer field. The second is a slight corner case
that used to mistakenly pass earlier. I vote to
just XFAIL these two for now.
OK for mainline? Assuming the patch as such is
OK, is the attached testsuite addition also OK?
The new testcase demonstrates all the static
field access (read/write) combinations that
work correctly now.
Thanks,
Ranjit.
--
Ranjit Mathew Email: rmathew AT gmail DOT com
Bangalore, INDIA. Web: http://ranjitmathew.hostingzero.com/
Index: ChangeLog
from Ranjit Mathew <rmathew@hotmail.com>
PR java/19870.
* java-tree.h (OUTER_FIELD_ACCESS_IDENTIFIER_P): Rename to
NESTED_FIELD_ACCESS_IDENTIFIER_P.
(FIELD_INNER_ACCESS): Rename to FIELD_NESTED_ACCESS.
(FIELD_INNER_ACCESS_P): Rename to FIELD_NESTED_ACCESS_P.
* jcf-write.c (generate_classfile): Use
NESTED_FIELD_ACCESS_IDENTIFIER_P instead of
OUTER_FIELD_ACCESS_IDENTIFIER_P.
* parse.y (build_outer_field_access): Rename to
build_nested_field_access. Support static fields and outer-to-inner
class accesses.
(outer_field_access_p): Rename to nested_field_access_p. Support
static fields and generalise to outer-to-inner class and sibling
inner class accesses.
(outer_field_expanded_access_p): Rename to
nested_field_expanded_access_p and support static fields.
(outer_field_access_fix): Rename to nested_field_access_fix and
support static fields.
(build_outer_field_access_expr): Rename to
build_nested_field_access_expr and support static fields.
(build_outer_field_access_methods): Rename to
build_nested_field_access_methods and support static fields. For
static fields, generate accessors without class instance parameters.
(build_outer_field_access_method): Rename to
build_nested_field_access_method and support static fields.
(build_outer_method_access_method): Use
NESTED_FIELD_ACCESS_IDENTIFIER_P instead of
OUTER_FIELD_ACCESS_IDENTIFIER_P.
(resolve_expression_name): Consider static field accesses across
nested classes.
(resolve_qualified_expression_name): Likewise.
(java_complete_lhs): Use nested_field_access_fix instead of
outer_field_access_fix.
(patch_unary_op): Rename outer_field_flag to nested_field_flag.
Use nested_field_expanded_access_p instead of
outer_field_expanded_access_p. Use nested_field_access_fix instead
of outer_field_access_fix.
(check_thrown_exceptions): Use NESTED_FIELD_ACCESS_IDENTIFIER_P
instead of OUTER_FIELD_ACCESS_IDENTIFIER_P.
Index: java-tree.h
===================================================================
*** java-tree.h 2005-05-26 11:12:40.000000000 +0530
--- java-tree.h 2005-05-26 11:16:57.000000000 +0530
*************** struct JCF;
*** 72,76 ****
IS_INIT_CHECKED (in SAVE_EXPR)
6: CAN_COMPLETE_NORMALLY (in statement nodes)
! OUTER_FIELD_ACCESS_IDENTIFIER_P (in IDENTIFIER_NODE)
Usage of TYPE_LANG_FLAG_?:
--- 72,76 ----
IS_INIT_CHECKED (in SAVE_EXPR)
6: CAN_COMPLETE_NORMALLY (in statement nodes)
! NESTED_FIELD_ACCESS_IDENTIFIER_P (in IDENTIFIER_NODE)
Usage of TYPE_LANG_FLAG_?:
*************** union lang_tree_node
*** 897,910 ****
/* The end (bytecode) pc for the valid range of this local variable. */
#define DECL_LOCAL_END_PC(NODE) (DECL_LANG_SPECIFIC (NODE)->u.v.end_pc)
! /* For a VAR_DECLor PARM_DECL, used to chain decls with the same
slot_number in decl_map. */
#define DECL_LOCAL_SLOT_CHAIN(NODE) (DECL_LANG_SPECIFIC(NODE)->u.v.slot_chain)
/* For a FIELD_DECL, holds the name of the access method. Used to
! read/write the content of the field from an inner class. */
! #define FIELD_INNER_ACCESS(DECL) \
(DECL_LANG_SPECIFIC (VAR_OR_FIELD_CHECK (DECL))->u.v.am)
! /* Safely tests whether FIELD_INNER_ACCESS exists or not. */
! #define FIELD_INNER_ACCESS_P(DECL) \
! DECL_LANG_SPECIFIC (DECL) && FIELD_INNER_ACCESS (DECL)
/* True if a final field was initialized upon its declaration
or in an initializer. Set after definite assignment. */
--- 897,910 ----
/* The end (bytecode) pc for the valid range of this local variable. */
#define DECL_LOCAL_END_PC(NODE) (DECL_LANG_SPECIFIC (NODE)->u.v.end_pc)
! /* For a VAR_DECL or PARM_DECL, used to chain decls with the same
slot_number in decl_map. */
#define DECL_LOCAL_SLOT_CHAIN(NODE) (DECL_LANG_SPECIFIC(NODE)->u.v.slot_chain)
/* For a FIELD_DECL, holds the name of the access method. Used to
! read/write the content of the field across nested class boundaries. */
! #define FIELD_NESTED_ACCESS(DECL) \
(DECL_LANG_SPECIFIC (VAR_OR_FIELD_CHECK (DECL))->u.v.am)
! /* Safely tests whether FIELD_NESTED_ACCESS exists or not. */
! #define FIELD_NESTED_ACCESS_P(DECL) \
! DECL_LANG_SPECIFIC (DECL) && FIELD_NESTED_ACCESS (DECL)
/* True if a final field was initialized upon its declaration
or in an initializer. Set after definite assignment. */
*************** extern tree *type_map;
*** 1690,1696 ****
#define CAN_COMPLETE_NORMALLY(NODE) TREE_LANG_FLAG_6 (NODE)
! /* True if NODE (an IDENTIFIER) bears the name of a outer field from
! inner class access function. */
! #define OUTER_FIELD_ACCESS_IDENTIFIER_P(NODE) \
TREE_LANG_FLAG_6 (IDENTIFIER_NODE_CHECK (NODE))
--- 1690,1696 ----
#define CAN_COMPLETE_NORMALLY(NODE) TREE_LANG_FLAG_6 (NODE)
! /* True if NODE (an IDENTIFIER) bears the name of an outer field from
! inner class (or vice versa) access function. */
! #define NESTED_FIELD_ACCESS_IDENTIFIER_P(NODE) \
TREE_LANG_FLAG_6 (IDENTIFIER_NODE_CHECK (NODE))
Index: jcf-write.c
===================================================================
*** jcf-write.c 2005-05-26 09:59:32.000000000 +0530
--- jcf-write.c 2005-05-26 11:18:46.000000000 +0530
*************** generate_classfile (tree clas, struct jc
*** 3088,3092 ****
if (DECL_FINIT_P (part)
|| DECL_INSTINIT_P (part)
! || OUTER_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (part))
|| TYPE_DOT_CLASS (clas) == part)
{
--- 3088,3092 ----
if (DECL_FINIT_P (part)
|| DECL_INSTINIT_P (part)
! || NESTED_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (part))
|| TYPE_DOT_CLASS (clas) == part)
{
Index: parse.y
===================================================================
*** parse.y 2005-05-26 09:59:33.000000000 +0530
--- parse.y 2005-05-26 11:23:19.000000000 +0530
*************** static tree build_access_to_thisn (tree,
*** 321,337 ****
static tree maybe_build_thisn_access_method (tree);
! static tree build_outer_field_access (tree, tree);
! static tree build_outer_field_access_methods (tree);
! static tree build_outer_field_access_expr (int, tree, tree,
! tree, tree);
static tree build_outer_method_access_method (tree);
static tree build_new_access_id (void);
- static tree build_outer_field_access_method (tree, tree, tree,
- tree, tree);
! static int outer_field_access_p (tree, tree);
! static int outer_field_expanded_access_p (tree, tree *,
! 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);
--- 321,335 ----
static tree maybe_build_thisn_access_method (tree);
! static tree build_nested_field_access (tree, tree);
! static tree build_nested_field_access_methods (tree);
! static tree build_nested_field_access_method (tree, tree, tree, tree, tree);
! static tree build_nested_field_access_expr (int, tree, tree, tree, tree);
static tree build_outer_method_access_method (tree);
static tree build_new_access_id (void);
! static int nested_field_access_p (tree, tree);
! static int nested_field_expanded_access_p (tree, tree *, tree *, tree *);
! static tree nested_field_access_fix (tree, tree, tree);
!
static tree build_incomplete_class_ref (int, tree);
static tree patch_incomplete_class_ref (tree);
*************** java_expand_method_bodies (tree class)
*** 8290,8312 ****
by invoking an access method crafted for that purpose. */
! /* Build the necessary access from an inner class to an outer
! class. This routine could be optimized to cache previous result
(decl, current_class and returned access). When an access method
! needs to be generated, it always takes the form of a read. It might
! be later turned into a write by calling outer_field_access_fix. */
static tree
! build_outer_field_access (tree id, tree decl)
{
tree access = NULL_TREE;
! tree ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
tree decl_ctx = DECL_CONTEXT (decl);
! /* If the immediate enclosing context of the current class is the
! field decl's class or inherits from it; build the access as
! `this$<n>.<field>'. Note that we will break the `private' barrier
! if we're not emitting bytecodes. */
! if ((ctx == decl_ctx || inherits_from_p (ctx, decl_ctx))
! && (!FIELD_PRIVATE (decl) || !flag_emit_class_files ))
{
tree thisn = build_current_thisn (current_class);
--- 8288,8316 ----
by invoking an access method crafted for that purpose. */
! /* Build the necessary access across nested class boundaries.
! This routine could be optimized to cache previous result
(decl, current_class and returned access). When an access method
! needs to be generated, it always takes the form of a read. It might
! be later turned into a write by calling nested_field_access_fix. */
static tree
! build_nested_field_access (tree id, tree decl)
{
tree access = NULL_TREE;
! tree ctx = NULL_TREE;
tree decl_ctx = DECL_CONTEXT (decl);
+ bool is_static = FIELD_STATIC (decl);
+
+ if (DECL_CONTEXT (TYPE_NAME (current_class)))
+ ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
! /* For non-static fields, if the immediate enclosing context of the
! current class is the field decl's class or inherits from it,
! build the access as `this$<n>.<field>'. Note that we will break
! the `private' barrier if we're not emitting bytecodes. */
! if (!is_static
! && ctx
! && (ctx == decl_ctx || inherits_from_p (ctx, decl_ctx))
! && (!FIELD_PRIVATE (decl) || !flag_emit_class_files))
{
tree thisn = build_current_thisn (current_class);
*************** build_outer_field_access (tree id, tree
*** 8314,8319 ****
id, EXPR_WFL_LINECOL (id));
}
! /* Otherwise, generate access methods to outer this and access the
! field (either using an access method or by direct access.) */
else
{
--- 8318,8323 ----
id, EXPR_WFL_LINECOL (id));
}
! /* Otherwise, generate and use accessor methods for the field as
! needed. */
else
{
*************** build_outer_field_access (tree id, tree
*** 8321,8389 ****
/* Now we chain the required number of calls to the access$0 to
! get a hold to the enclosing instance we need, and then we
! build the field access. */
! access = build_access_to_thisn (current_class, decl_ctx, lc);
/* If the field is private and we're generating bytecode, then
! we generate an access method */
! if (FIELD_PRIVATE (decl) && flag_emit_class_files )
{
! tree name = build_outer_field_access_methods (decl);
! access = build_outer_field_access_expr (lc, decl_ctx,
! name, access, NULL_TREE);
}
! /* Otherwise we use `access$(this$<j>). ... access$(this$<i>).<field>'.
Once again we break the `private' access rule from a foreign
! class. */
else
! access = make_qualified_primary (access, id, lc);
}
return resolve_expression_name (access, NULL);
}
! /* Return a nonzero value if NODE describes an outer field inner
! access. */
static int
! outer_field_access_p (tree type, tree decl)
{
if (!INNER_CLASS_TYPE_P (type)
! || TREE_CODE (decl) != FIELD_DECL
! || DECL_CONTEXT (decl) == type)
return 0;
! /* If the inner class extends the declaration context of the field
! we're trying to access, then this isn't an outer field access */
! if (inherits_from_p (type, DECL_CONTEXT (decl)))
! return 0;
! for (type = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))); ;
! type = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))))
! {
! if (type == DECL_CONTEXT (decl))
! return 1;
! if (!DECL_CONTEXT (TYPE_NAME (type)))
! {
! /* Before we give up, see whether the field is inherited from
! the enclosing context we're considering. */
! if (inherits_from_p (type, DECL_CONTEXT (decl)))
! return 1;
! break;
! }
}
return 0;
}
! /* Return a nonzero value if NODE represents an outer field inner
! access that was been already expanded. As a side effect, it returns
the name of the field being accessed and the argument passed to the
access function, suitable for a regeneration of the access method
! call if necessary. */
static int
! outer_field_expanded_access_p (tree node, tree *name, tree *arg_type,
! tree *arg)
{
int identified = 0;
--- 8325,8432 ----
/* Now we chain the required number of calls to the access$0 to
! get a hold to the enclosing instance we need for a non-static
! field, and then we build the field access. */
! if (!is_static)
! access = build_access_to_thisn (current_class, decl_ctx, lc);
/* If the field is private and we're generating bytecode, then
! we generate an access method. */
! if (FIELD_PRIVATE (decl) && flag_emit_class_files)
{
! tree name = build_nested_field_access_methods (decl);
! access = build_nested_field_access_expr (lc, decl_ctx,
! name, access, NULL_TREE);
}
! /* Otherwise we use `access$(this$<j>). ... access$(this$<i>).<field>'
! for non-static fields.
Once again we break the `private' access rule from a foreign
! class. */
! else if (is_static)
! {
! tree class_name = DECL_NAME (TYPE_NAME (decl_ctx));
! access
! = make_qualified_primary (build_wfl_node (class_name), id, lc);
! }
else
! access = make_qualified_primary (access, id, lc);
}
+
return resolve_expression_name (access, NULL);
}
! /* Return a nonzero value if DECL describes a field access across nested
! class boundaries. That is, DECL is in a class that either encloses,
! is enclosed by or shares a common enclosing class with, the class
! TYPE. */
static int
! nested_field_access_p (tree type, tree decl)
{
+ bool is_static = false;
+ tree decl_type = DECL_CONTEXT (decl);
+ tree type_root, decl_type_root;
+
+ if (decl_type == type
+ || (TREE_CODE (decl) != FIELD_DECL && TREE_CODE (decl) != VAR_DECL))
+ return 0;
+
if (!INNER_CLASS_TYPE_P (type)
! && !(TREE_CODE (decl_type) == RECORD_TYPE
! && INNER_CLASS_TYPE_P (decl_type)))
return 0;
! is_static = FIELD_STATIC (decl);
! /* If TYPE extends the declaration context of the non-static
! field we're trying to access, then this isn't a nested field
! access we need to worry about. */
! if (!is_static && inherits_from_p (type, decl_type))
! return 0;
! for (type_root = type;
! DECL_CONTEXT (TYPE_NAME (type_root));
! type_root = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type_root))))
! {
! if (type_root == decl_type)
! return 1;
!
! /* Before we give up, see whether it is a non-static field
! inherited from the enclosing context we are considering. */
! if (!DECL_CONTEXT (TYPE_NAME (type_root))
! && !is_static
! && inherits_from_p (type_root, decl_type))
! return 1;
! }
!
! if (TREE_CODE (decl_type) == RECORD_TYPE
! && INNER_CLASS_TYPE_P (decl_type))
! {
! for (decl_type_root = decl_type;
! DECL_CONTEXT (TYPE_NAME (decl_type_root));
! decl_type_root
! = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (decl_type_root))))
! {
! if (decl_type_root == type)
! return 1;
! }
}
+ else
+ decl_type_root = decl_type;
+
+ if (type_root == decl_type_root)
+ return 1;
return 0;
}
! /* Return a nonzero value if NODE represents a cross-nested-class
! access that has already been expanded. As a side effect, it returns
the name of the field being accessed and the argument passed to the
access function, suitable for a regeneration of the access method
! call if necessary. */
static int
! nested_field_expanded_access_p (tree node, tree *name, tree *arg_type,
! tree *arg)
{
int identified = 0;
*************** outer_field_expanded_access_p (tree node
*** 8392,8401 ****
return 0;
! /* Well, gcj generates slightly different tree nodes when compiling
! to native or bytecodes. It's the case for function calls. */
if (flag_emit_class_files
&& TREE_CODE (node) == CALL_EXPR
! && OUTER_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (TREE_OPERAND (node, 0))))
identified = 1;
else if (!flag_emit_class_files)
--- 8435,8444 ----
return 0;
! /* Well, GCJ generates slightly different tree nodes when compiling
! to native or bytecodes. It's the case for function calls. */
if (flag_emit_class_files
&& TREE_CODE (node) == CALL_EXPR
! && NESTED_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (TREE_OPERAND (node, 0))))
identified = 1;
else if (!flag_emit_class_files)
*************** outer_field_expanded_access_p (tree node
*** 8409,8413 ****
if (TREE_OPERAND (node, 0)
&& TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
! && (OUTER_FIELD_ACCESS_IDENTIFIER_P
(DECL_NAME (TREE_OPERAND (node, 0)))))
identified = 1;
--- 8452,8456 ----
if (TREE_OPERAND (node, 0)
&& TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
! && (NESTED_FIELD_ACCESS_IDENTIFIER_P
(DECL_NAME (TREE_OPERAND (node, 0)))))
identified = 1;
*************** outer_field_expanded_access_p (tree node
*** 8419,8442 ****
tree argument = TREE_OPERAND (node, 1);
*name = DECL_NAME (TREE_OPERAND (node, 0));
! *arg_type = TREE_TYPE (TREE_TYPE (TREE_VALUE (argument)));
! *arg = TREE_VALUE (argument);
}
return identified;
}
! /* Detect in NODE an outer field read access from an inner class and
! transform it into a write with RHS as an argument. This function is
! called from the java_complete_lhs when an assignment to a LHS can
! be identified. */
static tree
! outer_field_access_fix (tree wfl, tree node, tree rhs)
{
tree name, arg_type, arg;
! if (outer_field_expanded_access_p (node, &name, &arg_type, &arg))
{
! node = build_outer_field_access_expr (EXPR_WFL_LINECOL (wfl),
! arg_type, name, arg, rhs);
return java_complete_tree (node);
}
--- 8462,8496 ----
tree argument = TREE_OPERAND (node, 1);
*name = DECL_NAME (TREE_OPERAND (node, 0));
!
! /* The accessors for static fields do not take in a this$<n> argument,
! so we take the class name from the accessor's context instead. */
! if (argument)
! {
! *arg_type = TREE_TYPE (TREE_TYPE (TREE_VALUE (argument)));
! *arg = TREE_VALUE (argument);
! }
! else
! {
! *arg_type = DECL_CONTEXT (TREE_OPERAND (node, 0));
! *arg = NULL_TREE;
! }
}
return identified;
}
! /* Detect in NODE cross-nested-class field read access and
! transform it into a write with RHS as an argument. This function
! is called from the java_complete_lhs when an assignment to a LHS can
! be identified. */
static tree
! nested_field_access_fix (tree wfl, tree node, tree rhs)
{
tree name, arg_type, arg;
! if (nested_field_expanded_access_p (node, &name, &arg_type, &arg))
{
! node = build_nested_field_access_expr (EXPR_WFL_LINECOL (wfl),
! arg_type, name, arg, rhs);
return java_complete_tree (node);
}
*************** outer_field_access_fix (tree wfl, tree n
*** 8451,8471 ****
static tree
! build_outer_field_access_expr (int lc, tree type, tree access_method_name,
! tree arg1, tree arg2)
{
tree args, cn, access;
! args = arg1 ? arg1 :
! build_wfl_node (build_current_thisn (current_class));
! args = build_tree_list (NULL_TREE, args);
if (arg2)
! args = tree_cons (NULL_TREE, arg2, args);
! access = build_method_invocation (build_wfl_node (access_method_name), args);
cn = build_wfl_node (DECL_NAME (TYPE_NAME (type)));
return make_qualified_primary (cn, access, lc);
}
static tree
build_new_access_id (void)
--- 8505,8536 ----
static tree
! build_nested_field_access_expr (int lc, tree type, tree access_method_name,
! tree arg1, tree arg2)
{
tree args, cn, access;
! if (arg1)
! args = build_tree_list (NULL_TREE, arg1);
! else
! args = NULL_TREE;
if (arg2)
! {
! if (args)
! args = tree_cons (NULL_TREE, arg2, args);
! else
! args = build_tree_list (NULL_TREE, arg2);
! }
! access
! = build_method_invocation (build_wfl_node (access_method_name), args);
cn = build_wfl_node (DECL_NAME (TYPE_NAME (type)));
+
return make_qualified_primary (cn, access, lc);
}
+ /* Build the name of a synthetic accessor used to access class members
+ across nested class boundaries. */
+
static tree
build_new_access_id (void)
*************** build_new_access_id (void)
*** 8478,8483 ****
}
! /* Create the static access functions for the outer field DECL. We define a
! read:
TREE_TYPE (<field>) access$<n> (DECL_CONTEXT (<field>) inst$) {
return inst$.field;
--- 8543,8548 ----
}
! /* Create the static access functions for the cross-nested-class field DECL.
! We define a read:
TREE_TYPE (<field>) access$<n> (DECL_CONTEXT (<field>) inst$) {
return inst$.field;
*************** build_new_access_id (void)
*** 8488,8548 ****
return inst$.field = value$;
}
! We should have a usage flags on the DECL so we can lazily turn the ones
! we're using for code generation. FIXME.
*/
static tree
! build_outer_field_access_methods (tree decl)
{
! tree id, args, stmt, mdecl;
! if (FIELD_INNER_ACCESS_P (decl))
! return FIELD_INNER_ACCESS (decl);
MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
! /* Create the identifier and a function named after it. */
id = build_new_access_id ();
/* The identifier is marked as bearing the name of a generated write
! access function for outer field accessed from inner classes. */
! OUTER_FIELD_ACCESS_IDENTIFIER_P (id) = 1;
! /* Create the read access */
! args = build_tree_list (inst_id, build_pointer_type (DECL_CONTEXT (decl)));
! TREE_CHAIN (args) = end_params_node;
! stmt = make_qualified_primary (build_wfl_node (inst_id),
! build_wfl_node (DECL_NAME (decl)), 0);
stmt = build_return (0, stmt);
! mdecl = build_outer_field_access_method (DECL_CONTEXT (decl),
! TREE_TYPE (decl), id, args, stmt);
DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
! /* Create the write access method. No write access for final variable */
if (!FIELD_FINAL (decl))
{
! args = build_tree_list (inst_id,
! build_pointer_type (DECL_CONTEXT (decl)));
! TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
! TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
! stmt = make_qualified_primary (build_wfl_node (inst_id),
! build_wfl_node (DECL_NAME (decl)), 0);
stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
build_wfl_node (wpv_id)));
! mdecl = build_outer_field_access_method (DECL_CONTEXT (decl),
! TREE_TYPE (decl), id,
! args, stmt);
}
DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
/* Return the access name */
! return FIELD_INNER_ACCESS (decl) = id;
}
! /* Build an field access method NAME. */
static tree
! build_outer_field_access_method (tree class, tree type, tree name,
! tree args, tree body)
{
tree saved_current_function_decl, mdecl;
--- 8553,8639 ----
return inst$.field = value$;
}
! For static fields, these methods are generated without the instance
! parameter.
! We should have a usage flag on the DECL so we can lazily turn the ones
! we're using for code generation. FIXME.
*/
static tree
! build_nested_field_access_methods (tree decl)
{
! tree id, args, stmt, mdecl, class_name = NULL_TREE;
! bool is_static = FIELD_STATIC (decl);
! if (FIELD_NESTED_ACCESS_P (decl))
! return FIELD_NESTED_ACCESS (decl);
MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
! /* Create the identifier and a function named after it. */
id = build_new_access_id ();
/* The identifier is marked as bearing the name of a generated write
! access function for outer field accessed from inner classes. */
! NESTED_FIELD_ACCESS_IDENTIFIER_P (id) = 1;
! /* Create the read access. */
! if (!is_static)
! {
! args = build_tree_list (inst_id,
! build_pointer_type (DECL_CONTEXT (decl)));
! TREE_CHAIN (args) = end_params_node;
! stmt = make_qualified_primary (build_wfl_node (inst_id),
! build_wfl_node (DECL_NAME (decl)), 0);
! }
! else
! {
! args = end_params_node;
! class_name = DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl)));
! stmt = make_qualified_primary (build_wfl_node (class_name),
! build_wfl_node (DECL_NAME (decl)), 0);
! }
stmt = build_return (0, stmt);
! mdecl = build_nested_field_access_method (DECL_CONTEXT (decl),
! TREE_TYPE (decl), id, args, stmt);
DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
! /* Create the write access method. No write access for final variable */
if (!FIELD_FINAL (decl))
{
! if (!is_static)
! {
! args = build_tree_list (inst_id,
! build_pointer_type (DECL_CONTEXT (decl)));
! TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
! TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
! stmt = make_qualified_primary (build_wfl_node (inst_id),
! build_wfl_node (DECL_NAME (decl)),
! 0);
! }
! else
! {
! args = build_tree_list (wpv_id, TREE_TYPE (decl));
! TREE_CHAIN (args) = end_params_node;
! stmt = make_qualified_primary (build_wfl_node (class_name),
! build_wfl_node (DECL_NAME (decl)),
! 0);
! }
stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
build_wfl_node (wpv_id)));
! mdecl = build_nested_field_access_method (DECL_CONTEXT (decl),
! TREE_TYPE (decl), id,
! args, stmt);
}
DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
/* Return the access name */
! return FIELD_NESTED_ACCESS (decl) = id;
}
! /* Build a field access method NAME. */
static tree
! build_nested_field_access_method (tree class, tree type, tree name,
! tree args, tree body)
{
tree saved_current_function_decl, mdecl;
*************** build_outer_method_access_method (tree d
*** 8588,8592 ****
/* Obtain an access identifier and mark it */
id = build_new_access_id ();
! OUTER_FIELD_ACCESS_IDENTIFIER_P (id) = 1;
carg = TYPE_ARG_TYPES (TREE_TYPE (decl));
--- 8679,8683 ----
/* Obtain an access identifier and mark it */
id = build_new_access_id ();
! NESTED_FIELD_ACCESS_IDENTIFIER_P (id) = 1;
carg = TYPE_ARG_TYPES (TREE_TYPE (decl));
*************** build_outer_method_access_method (tree d
*** 8654,8658 ****
necessary. This CAN'T be used to solely access this$<n-1> from
this$<n> (which alway yield to special cases and optimization, see
! for example build_outer_field_access). */
static tree
--- 8745,8749 ----
necessary. This CAN'T be used to solely access this$<n-1> from
this$<n> (which alway yield to special cases and optimization, see
! for example build_nested_field_access). */
static tree
*************** resolve_expression_name (tree id, tree *
*** 9457,9469 ****
/* If we're processing an inner class and we're trying
to access a field belonging to an outer class, build
! the access to the field */
! if (!fs && outer_field_access_p (current_class, decl))
{
! if (CLASS_STATIC (TYPE_NAME (current_class)))
{
static_ref_err (id, DECL_NAME (decl), current_class);
return error_mark_node;
}
! access = build_outer_field_access (id, decl);
if (orig)
*orig = access;
--- 9548,9560 ----
/* If we're processing an inner class and we're trying
to access a field belonging to an outer class, build
! the access to the field. */
! if (nested_field_access_p (current_class, decl))
{
! if (!fs && CLASS_STATIC (TYPE_NAME (current_class)))
{
static_ref_err (id, DECL_NAME (decl), current_class);
return error_mark_node;
}
! access = build_nested_field_access (id, decl);
if (orig)
*orig = access;
*************** resolve_qualified_expression_name (tree
*** 9994,10009 ****
if (!type)
{
! if (TREE_CODE (decl) == FIELD_DECL && !FIELD_STATIC (decl))
{
! if (current_this)
! *where_found = current_this;
! else
! {
! static_ref_err (qual_wfl, DECL_NAME (decl),
! current_class);
! return 1;
! }
! if (outer_field_access_p (current_class, decl))
! decl = build_outer_field_access (qual_wfl, decl);
}
else
--- 10085,10111 ----
if (!type)
{
! if (TREE_CODE (decl) == FIELD_DECL
! || TREE_CODE (decl) == VAR_DECL)
{
! if (TREE_CODE (decl) == FIELD_DECL
! && !FIELD_STATIC (decl))
! {
! if (current_this)
! *where_found = current_this;
! else
! {
! static_ref_err (qual_wfl, DECL_NAME (decl),
! current_class);
! return 1;
! }
! }
! else
! {
! *where_found = TREE_TYPE (decl);
! if (TREE_CODE (*where_found) == POINTER_TYPE)
! *where_found = TREE_TYPE (*where_found);
! }
! if (nested_field_access_p (current_class, decl))
! decl = build_nested_field_access (qual_wfl, decl);
}
else
*************** resolve_qualified_expression_name (tree
*** 10114,10118 ****
from_cast = from_super = 0;
! /* It's an access from a type but it isn't static, we
make it relative to `this'. */
if (!is_static && from_type)
--- 10216,10220 ----
from_cast = from_super = 0;
! /* If it's an access from a type but isn't static, we
make it relative to `this'. */
if (!is_static && from_type)
*************** resolve_qualified_expression_name (tree
*** 10129,10134 ****
}
! /* We want to keep the location were found it, and the type
! we found. */
*where_found = decl;
*type_found = type;
--- 10231,10236 ----
}
! /* We want to keep the location where we found it, and the
! type we found. */
*where_found = decl;
*type_found = type;
*************** resolve_qualified_expression_name (tree
*** 10138,10145 ****
if (from_qualified_this)
{
! field_decl = build_outer_field_access (qual_wfl, field_decl);
from_qualified_this = 0;
}
/* This is the decl found and eventually the next one to
search from */
--- 10240,10255 ----
if (from_qualified_this)
{
! field_decl
! = build_nested_field_access (qual_wfl, field_decl);
from_qualified_this = 0;
}
+ /* If needed, generate accessors for static field access. */
+ if (is_static
+ && FIELD_PRIVATE (field_decl)
+ && flag_emit_class_files
+ && nested_field_access_p (current_class, field_decl))
+ field_decl = build_nested_field_access (qual_wfl, field_decl);
+
/* This is the decl found and eventually the next one to
search from */
*************** java_complete_lhs (tree node)
*** 12121,12128 ****
TREE_OPERAND (node, 1) = nn;
! if ((nn = outer_field_access_fix (wfl_op1, TREE_OPERAND (node, 0),
! TREE_OPERAND (node, 1))))
{
! /* We return error_mark_node if outer_field_access_fix
detects we write into a final. */
if (nn == error_mark_node)
--- 12231,12238 ----
TREE_OPERAND (node, 1) = nn;
! if ((nn = nested_field_access_fix (wfl_op1, TREE_OPERAND (node, 0),
! TREE_OPERAND (node, 1))))
{
! /* We return error_mark_node if nested_field_access_fix
detects we write into a final. */
if (nn == error_mark_node)
*************** patch_unaryop (tree node, tree wfl_op)
*** 14144,14148 ****
tree op_type = TREE_TYPE (op);
tree prom_type = NULL_TREE, value, decl;
! int outer_field_flag = 0;
int code = TREE_CODE (node);
int error_found = 0;
--- 14254,14258 ----
tree op_type = TREE_TYPE (op);
tree prom_type = NULL_TREE, value, decl;
! int nested_field_flag = 0;
int code = TREE_CODE (node);
int error_found = 0;
*************** patch_unaryop (tree node, tree wfl_op)
*** 14161,14168 ****
case PREDECREMENT_EXPR:
op = decl = extract_field_decl (op);
! outer_field_flag = outer_field_expanded_access_p (op, NULL, NULL, NULL);
/* We might be trying to change an outer field accessed using
access method. */
! if (outer_field_flag)
{
/* Retrieve the decl of the field we're trying to access. We
--- 14271,14279 ----
case PREDECREMENT_EXPR:
op = decl = extract_field_decl (op);
! nested_field_flag
! = nested_field_expanded_access_p (op, NULL, NULL, NULL);
/* We might be trying to change an outer field accessed using
access method. */
! if (nested_field_flag)
{
/* Retrieve the decl of the field we're trying to access. We
*************** patch_unaryop (tree node, tree wfl_op)
*** 14218,14230 ****
/* We remember we might be accessing an outer field */
! if (outer_field_flag)
{
/* We re-generate an access to the field */
value = build2 (PLUS_EXPR, TREE_TYPE (op),
! build_outer_field_access (wfl_op, decl), value);
/* And we patch the original access$() into a write
with plus_op as a rhs */
! return outer_field_access_fix (node, op, value);
}
--- 14329,14341 ----
/* We remember we might be accessing an outer field */
! if (nested_field_flag)
{
/* We re-generate an access to the field */
value = build2 (PLUS_EXPR, TREE_TYPE (op),
! build_nested_field_access (wfl_op, decl), value);
/* And we patch the original access$() into a write
with plus_op as a rhs */
! return nested_field_access_fix (node, op, value);
}
*************** check_thrown_exceptions (
*** 15810,15814 ****
/* Skip check within generated methods, such as access$<n>. */
! if (OUTER_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (current_function_decl)))
return;
--- 15921,15925 ----
/* Skip check within generated methods, such as access$<n>. */
! if (NESTED_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (current_function_decl)))
return;
Index: ChangeLog
from Ranjit Mathew <rmathew@hotmail.com>
Testsuite adjustments for PR java/19870.
* testsuite/libjava.lang/PR19870.java: New testcase.
* testsuite/libjava.lang/PR19870.out: Expected output for the
testcase.
* testsuite/libjava.jacks/jacks.xfail: Add
8.5.2-accessible-static-member-usage-3 and 15.8.4-static-2
Index: testsuite/libjava.lang/PR19870.java
===================================================================
*** testsuite/libjava.lang/PR19870.java 2005-05-26 11:30:44.000000000 +0530
--- testsuite/libjava.lang/PR19870.java 2005-05-26 11:30:43.000000000 +0530
***************
*** 0 ****
--- 1,44 ----
+ // PR19870: Test static field access across nested class boundaries.
+ //
+ public class PR19870
+ {
+ private static int x = 123;
+
+ static class Foo
+ {
+ private static int junk = 1000;
+
+ static void snafu( )
+ {
+ System.out.println( x);
+ x = 456;
+ System.out.println( PR19870.x);
+ PR19870.x = 789;
+ System.out.println( PR19870.x);
+
+ System.out.println( Bar.junk);
+ }
+ }
+
+ static class Bar
+ {
+ private static int junk = 1984;
+
+ static void snafu( )
+ {
+ System.out.println( Foo.junk);
+ Foo.junk = 2000;
+ System.out.println( Foo.junk);
+ }
+ }
+
+ public static void main( String[] args)
+ {
+ Foo.snafu( );
+ Bar.snafu( );
+
+ System.out.println( Foo.junk);
+ Foo.junk = 3000;
+ System.out.println( Foo.junk);
+ }
+ }
Index: testsuite/libjava.lang/PR19870.out
===================================================================
*** testsuite/libjava.lang/PR19870.out 2005-05-26 11:30:44.000000000 +0530
--- testsuite/libjava.lang/PR19870.out 2005-05-26 11:30:44.000000000 +0530
***************
*** 0 ****
--- 1,8 ----
+ 123
+ 456
+ 789
+ 1984
+ 1000
+ 2000
+ 2000
+ 3000
Index: testsuite/libjava.jacks/jacks.xfail
===================================================================
*** testsuite/libjava.jacks/jacks.xfail 2005-05-26 11:30:58.000000000 +0530
--- testsuite/libjava.jacks/jacks.xfail 2005-05-26 12:28:51.000000000 +0530
***************
*** 307,310 ****
--- 307,311 ----
15.8.2-type-13
15.8.2-type-14
+ 15.8.4-static-2
15.8.5-field-expression-6
15.8.5-method-expression-8
***************
*** 634,637 ****
--- 635,639 ----
8.5-inheritance-3
8.5-inheritance-6
+ 8.5.2-accessible-static-member-usage-3
8.5.2-non-static-member-usage-2
8.5.2-non-static-member-usage-4