mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-05 02:56:50 +08:00
re PR java/19870 (gcj -C doesn't generate accessors for private members across nested class boundaries)
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. From-SVN: r100246
This commit is contained in:
parent
27358466f9
commit
38c9d142c8
@ -1,3 +1,45 @@
|
||||
2005-05-26 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.
|
||||
|
||||
2005-05-26 Bryce McKinlay <mckinlay@redhat.com>
|
||||
|
||||
* decl.c (GCJ_BINARYCOMPAT_ADDITION,
|
||||
@ -10461,7 +10503,7 @@
|
||||
properly initialize `finished_label'. Don't emit gotos for empty
|
||||
try statements.
|
||||
|
||||
2000-03-19 Martin v. Löwis <loewis@informatik.hu-berlin.de>
|
||||
2000-03-19 Martin v. L<EFBFBD>is <loewis@informatik.hu-berlin.de>
|
||||
|
||||
* except.c (emit_handlers): Clear catch_clauses_last.
|
||||
|
||||
|
@ -71,7 +71,7 @@ struct JCF;
|
||||
IS_CRAFTED_STRING_BUFFER_P (in CALL_EXPR)
|
||||
IS_INIT_CHECKED (in SAVE_EXPR)
|
||||
6: CAN_COMPLETE_NORMALLY (in statement nodes)
|
||||
OUTER_FIELD_ACCESS_IDENTIFIER_P (in IDENTIFIER_NODE)
|
||||
NESTED_FIELD_ACCESS_IDENTIFIER_P (in IDENTIFIER_NODE)
|
||||
|
||||
Usage of TYPE_LANG_FLAG_?:
|
||||
0: CLASS_ACCESS0_GENERATED_P (in RECORD_TYPE)
|
||||
@ -896,16 +896,16 @@ union lang_tree_node
|
||||
#define DECL_LOCAL_START_PC(NODE) (DECL_LANG_SPECIFIC (NODE)->u.v.start_pc)
|
||||
/* 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
|
||||
/* 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 from an inner class. */
|
||||
#define FIELD_INNER_ACCESS(DECL) \
|
||||
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_INNER_ACCESS exists or not. */
|
||||
#define FIELD_INNER_ACCESS_P(DECL) \
|
||||
DECL_LANG_SPECIFIC (DECL) && FIELD_INNER_ACCESS (DECL)
|
||||
/* 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. */
|
||||
#define DECL_FIELD_FINAL_IUD(NODE) (DECL_LANG_SPECIFIC (NODE)->u.v.final_iud)
|
||||
@ -1689,9 +1689,9 @@ extern tree *type_map;
|
||||
/* True if NODE (a statement) can complete normally. */
|
||||
#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) \
|
||||
/* 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))
|
||||
|
||||
/* True if NODE belongs to an inner class TYPE_DECL node.
|
||||
|
@ -3087,7 +3087,7 @@ generate_classfile (tree clas, struct jcf_partial *state)
|
||||
/* Make room for the Synthetic attribute (of zero length.) */
|
||||
if (DECL_FINIT_P (part)
|
||||
|| DECL_INSTINIT_P (part)
|
||||
|| OUTER_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (part))
|
||||
|| NESTED_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (part))
|
||||
|| TYPE_DOT_CLASS (clas) == part)
|
||||
{
|
||||
i++;
|
||||
|
401
gcc/java/parse.y
401
gcc/java/parse.y
@ -320,19 +320,17 @@ static tree build_current_thisn (tree);
|
||||
static tree build_access_to_thisn (tree, tree, int);
|
||||
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_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 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 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);
|
||||
static tree create_anonymous_class (tree);
|
||||
@ -8289,114 +8287,159 @@ java_expand_method_bodies (tree class)
|
||||
fields either directly by using the relevant access to this$<n> or
|
||||
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
|
||||
/* 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 outer_field_access_fix. */
|
||||
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_outer_field_access (tree id, tree decl)
|
||||
build_nested_field_access (tree id, tree decl)
|
||||
{
|
||||
tree access = NULL_TREE;
|
||||
tree ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
|
||||
tree ctx = NULL_TREE;
|
||||
tree decl_ctx = DECL_CONTEXT (decl);
|
||||
bool is_static = FIELD_STATIC (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 ))
|
||||
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);
|
||||
access = make_qualified_primary (build_wfl_node (thisn),
|
||||
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.) */
|
||||
/* Otherwise, generate and use accessor methods for the field as
|
||||
needed. */
|
||||
else
|
||||
{
|
||||
int lc = EXPR_WFL_LINECOL (id);
|
||||
|
||||
/* 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);
|
||||
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 )
|
||||
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);
|
||||
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>'.
|
||||
/* 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. */
|
||||
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);
|
||||
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. */
|
||||
/* 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
|
||||
outer_field_access_p (tree type, tree decl)
|
||||
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) != FIELD_DECL
|
||||
|| DECL_CONTEXT (decl) == type)
|
||||
&& !(TREE_CODE (decl_type) == RECORD_TYPE
|
||||
&& INNER_CLASS_TYPE_P (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)))
|
||||
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 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))); ;
|
||||
type = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))))
|
||||
for (type_root = type;
|
||||
DECL_CONTEXT (TYPE_NAME (type_root));
|
||||
type_root = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type_root))))
|
||||
{
|
||||
if (type == DECL_CONTEXT (decl))
|
||||
return 1;
|
||||
if (type_root == decl_type)
|
||||
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;
|
||||
}
|
||||
/* 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 an outer field inner
|
||||
access that was been already expanded. As a side effect, it returns
|
||||
/* 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. */
|
||||
call if necessary. */
|
||||
|
||||
static int
|
||||
outer_field_expanded_access_p (tree node, tree *name, tree *arg_type,
|
||||
tree *arg)
|
||||
nested_field_expanded_access_p (tree node, tree *name, tree *arg_type,
|
||||
tree *arg)
|
||||
{
|
||||
int identified = 0;
|
||||
|
||||
if (TREE_CODE (node) != CALL_EXPR)
|
||||
return 0;
|
||||
|
||||
/* Well, gcj generates slightly different tree nodes when compiling
|
||||
to native or bytecodes. It's the case for function calls. */
|
||||
/* 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))))
|
||||
&& NESTED_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (TREE_OPERAND (node, 0))))
|
||||
identified = 1;
|
||||
else if (!flag_emit_class_files)
|
||||
{
|
||||
@ -8408,7 +8451,7 @@ outer_field_expanded_access_p (tree node, tree *name, tree *arg_type,
|
||||
node = TREE_OPERAND (node, 0);
|
||||
if (TREE_OPERAND (node, 0)
|
||||
&& TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
|
||||
&& (OUTER_FIELD_ACCESS_IDENTIFIER_P
|
||||
&& (NESTED_FIELD_ACCESS_IDENTIFIER_P
|
||||
(DECL_NAME (TREE_OPERAND (node, 0)))))
|
||||
identified = 1;
|
||||
}
|
||||
@ -8418,26 +8461,37 @@ outer_field_expanded_access_p (tree node, tree *name, tree *arg_type,
|
||||
{
|
||||
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);
|
||||
|
||||
/* 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 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. */
|
||||
/* 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
|
||||
outer_field_access_fix (tree wfl, tree node, tree rhs)
|
||||
nested_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))
|
||||
if (nested_field_expanded_access_p (node, &name, &arg_type, &arg))
|
||||
{
|
||||
node = build_outer_field_access_expr (EXPR_WFL_LINECOL (wfl),
|
||||
arg_type, name, arg, rhs);
|
||||
node = build_nested_field_access_expr (EXPR_WFL_LINECOL (wfl),
|
||||
arg_type, name, arg, rhs);
|
||||
return java_complete_tree (node);
|
||||
}
|
||||
return NULL_TREE;
|
||||
@ -8450,23 +8504,34 @@ outer_field_access_fix (tree wfl, tree node, tree rhs)
|
||||
read access. */
|
||||
|
||||
static tree
|
||||
build_outer_field_access_expr (int lc, tree type, tree access_method_name,
|
||||
tree arg1, tree arg2)
|
||||
build_nested_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 (arg1)
|
||||
args = build_tree_list (NULL_TREE, arg1);
|
||||
else
|
||||
args = NULL_TREE;
|
||||
|
||||
if (arg2)
|
||||
args = tree_cons (NULL_TREE, arg2, args);
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
@ -8477,8 +8542,8 @@ build_new_access_id (void)
|
||||
return get_identifier (buffer);
|
||||
}
|
||||
|
||||
/* Create the static access functions for the outer field DECL. We define a
|
||||
read:
|
||||
/* 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;
|
||||
}
|
||||
@ -8487,63 +8552,89 @@ build_new_access_id (void)
|
||||
TREE_TYPE (<field>) value$) {
|
||||
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.
|
||||
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_outer_field_access_methods (tree decl)
|
||||
build_nested_field_access_methods (tree decl)
|
||||
{
|
||||
tree id, args, stmt, mdecl;
|
||||
tree id, args, stmt, mdecl, class_name = NULL_TREE;
|
||||
bool is_static = FIELD_STATIC (decl);
|
||||
|
||||
if (FIELD_INNER_ACCESS_P (decl))
|
||||
return FIELD_INNER_ACCESS (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. */
|
||||
/* 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;
|
||||
access function for outer field accessed from inner classes. */
|
||||
NESTED_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))
|
||||
/* Create the read access. */
|
||||
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;
|
||||
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_outer_field_access_method (DECL_CONTEXT (decl),
|
||||
TREE_TYPE (decl), id,
|
||||
args, stmt);
|
||||
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_INNER_ACCESS (decl) = id;
|
||||
return FIELD_NESTED_ACCESS (decl) = id;
|
||||
}
|
||||
|
||||
/* Build an field access method NAME. */
|
||||
/* Build a field access method NAME. */
|
||||
|
||||
static tree
|
||||
build_outer_field_access_method (tree class, tree type, tree name,
|
||||
tree args, tree body)
|
||||
build_nested_field_access_method (tree class, tree type, tree name,
|
||||
tree args, tree body)
|
||||
{
|
||||
tree saved_current_function_decl, mdecl;
|
||||
|
||||
@ -8587,7 +8678,7 @@ build_outer_method_access_method (tree decl)
|
||||
|
||||
/* Obtain an access identifier and mark it */
|
||||
id = build_new_access_id ();
|
||||
OUTER_FIELD_ACCESS_IDENTIFIER_P (id) = 1;
|
||||
NESTED_FIELD_ACCESS_IDENTIFIER_P (id) = 1;
|
||||
|
||||
carg = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
||||
/* Create the arguments, as much as the original */
|
||||
@ -8653,7 +8744,7 @@ build_outer_method_access_method (tree decl)
|
||||
others. Access methods to this$<n> are build on the fly if
|
||||
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). */
|
||||
for example build_nested_field_access). */
|
||||
|
||||
static tree
|
||||
build_access_to_thisn (tree from, tree to, int lc)
|
||||
@ -9456,15 +9547,15 @@ resolve_expression_name (tree id, tree *orig)
|
||||
|
||||
/* 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))
|
||||
the access to the field. */
|
||||
if (nested_field_access_p (current_class, decl))
|
||||
{
|
||||
if (CLASS_STATIC (TYPE_NAME (current_class)))
|
||||
if (!fs && 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);
|
||||
access = build_nested_field_access (id, decl);
|
||||
if (orig)
|
||||
*orig = access;
|
||||
return access;
|
||||
@ -9993,18 +10084,29 @@ resolve_qualified_expression_name (tree wfl, tree *found_decl,
|
||||
decl = QUAL_RESOLUTION (q);
|
||||
if (!type)
|
||||
{
|
||||
if (TREE_CODE (decl) == FIELD_DECL && !FIELD_STATIC (decl))
|
||||
if (TREE_CODE (decl) == FIELD_DECL
|
||||
|| TREE_CODE (decl) == VAR_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);
|
||||
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
|
||||
{
|
||||
@ -10113,7 +10215,7 @@ resolve_qualified_expression_name (tree wfl, tree *found_decl,
|
||||
}
|
||||
from_cast = from_super = 0;
|
||||
|
||||
/* It's an access from a type but it isn't static, we
|
||||
/* If it's an access from a type but isn't static, we
|
||||
make it relative to `this'. */
|
||||
if (!is_static && from_type)
|
||||
decl = current_this;
|
||||
@ -10128,8 +10230,8 @@ resolve_qualified_expression_name (tree wfl, tree *found_decl,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We want to keep the location were found it, and the type
|
||||
we found. */
|
||||
/* We want to keep the location where we found it, and the
|
||||
type we found. */
|
||||
*where_found = decl;
|
||||
*type_found = type;
|
||||
|
||||
@ -10137,10 +10239,18 @@ resolve_qualified_expression_name (tree wfl, tree *found_decl,
|
||||
qualified this */
|
||||
if (from_qualified_this)
|
||||
{
|
||||
field_decl = build_outer_field_access (qual_wfl, field_decl);
|
||||
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 */
|
||||
decl = field_decl;
|
||||
@ -12120,10 +12230,10 @@ java_complete_lhs (tree node)
|
||||
if ((nn = patch_string (TREE_OPERAND (node, 1))))
|
||||
TREE_OPERAND (node, 1) = nn;
|
||||
|
||||
if ((nn = outer_field_access_fix (wfl_op1, TREE_OPERAND (node, 0),
|
||||
TREE_OPERAND (node, 1))))
|
||||
if ((nn = nested_field_access_fix (wfl_op1, TREE_OPERAND (node, 0),
|
||||
TREE_OPERAND (node, 1))))
|
||||
{
|
||||
/* We return error_mark_node if outer_field_access_fix
|
||||
/* We return error_mark_node if nested_field_access_fix
|
||||
detects we write into a final. */
|
||||
if (nn == error_mark_node)
|
||||
return error_mark_node;
|
||||
@ -14143,7 +14253,7 @@ patch_unaryop (tree node, tree wfl_op)
|
||||
tree op = TREE_OPERAND (node, 0);
|
||||
tree op_type = TREE_TYPE (op);
|
||||
tree prom_type = NULL_TREE, value, decl;
|
||||
int outer_field_flag = 0;
|
||||
int nested_field_flag = 0;
|
||||
int code = TREE_CODE (node);
|
||||
int error_found = 0;
|
||||
|
||||
@ -14160,10 +14270,11 @@ patch_unaryop (tree node, tree wfl_op)
|
||||
/* 15.14.2 Prefix Decrement Operator -- */
|
||||
case PREDECREMENT_EXPR:
|
||||
op = decl = extract_field_decl (op);
|
||||
outer_field_flag = outer_field_expanded_access_p (op, NULL, NULL, NULL);
|
||||
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 (outer_field_flag)
|
||||
if (nested_field_flag)
|
||||
{
|
||||
/* Retrieve the decl of the field we're trying to access. We
|
||||
do that by first retrieving the function we would call to
|
||||
@ -14217,15 +14328,15 @@ patch_unaryop (tree node, tree wfl_op)
|
||||
}
|
||||
|
||||
/* We remember we might be accessing an outer field */
|
||||
if (outer_field_flag)
|
||||
if (nested_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);
|
||||
build_nested_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);
|
||||
return nested_field_access_fix (node, op, value);
|
||||
}
|
||||
|
||||
/* And write back into the node. */
|
||||
@ -15809,7 +15920,7 @@ check_thrown_exceptions (
|
||||
int is_array_call = 0;
|
||||
|
||||
/* Skip check within generated methods, such as access$<n>. */
|
||||
if (OUTER_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (current_function_decl)))
|
||||
if (NESTED_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (current_function_decl)))
|
||||
return;
|
||||
|
||||
if (this_expr != NULL_TREE
|
||||
|
Loading…
Reference in New Issue
Block a user