/* Source code parsing and tree node generation for the GNU compiler
for the Java(TM) language.
- Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
This file is part of GNU CC.
static tree lookup_package_type PARAMS ((const char *, int));
static tree resolve_class PARAMS ((tree, tree, tree, tree));
static void declare_local_variables PARAMS ((int, tree, tree));
+static void dump_java_tree PARAMS ((enum tree_dump_index, tree));
static void source_start_java_method PARAMS ((tree));
static void source_end_java_method PARAMS ((void));
static tree find_name_in_single_imports PARAMS ((tree));
static void fix_constructors PARAMS ((tree));
static tree build_alias_initializer_parameter_list PARAMS ((int, tree,
tree, int *));
-static void craft_constructor PARAMS ((tree, tree));
+static tree craft_constructor PARAMS ((tree, tree));
static int verify_constructor_super PARAMS ((tree));
static tree create_artificial_method PARAMS ((tree, int, tree, tree, tree));
static void start_artificial_method_body PARAMS ((tree));
covers both integral/floating point division. The code is changed
once the type of both operator is worked out. */
-static enum tree_code binop_lookup[19] =
+static const enum tree_code binop_lookup[19] =
{
PLUS_EXPR, MINUS_EXPR, MULT_EXPR, RDIV_EXPR, TRUNC_MOD_EXPR,
LSHIFT_EXPR, RSHIFT_EXPR, URSHIFT_EXPR,
`ctxp->current_loop'. */
static tree case_label_list;
-static tree src_parse_roots[1] = { NULL_TREE };
+static tree src_parse_roots[1];
/* All classes seen from source code */
#define gclass_list src_parse_roots[0]
%token PUBLIC_TK PRIVATE_TK PROTECTED_TK
%token STATIC_TK FINAL_TK SYNCHRONIZED_TK
%token VOLATILE_TK TRANSIENT_TK NATIVE_TK
-%token PAD_TK ABSTRACT_TK MODIFIER_TK
-%token STRICT_TK
+%token PAD_TK ABSTRACT_TK STRICT_TK
+%token MODIFIER_TK
/* Keep those two in order, too */
%token DECR_TK INCR_TK
popped by a resume. */
int no_error_occurred = ctxp->next && GET_CPC () != error_mark_node;
+ if (GET_CPC () != error_mark_node)
+ dump_java_tree (TDI_class, GET_CPC ());
+
java_parser_context_pop_initialized_field ();
POP_CPC ();
if (resume && no_error_occurred)
ABSTRACT_CHECK (flags, ACC_STATIC, id, "Static");
ABSTRACT_CHECK (flags, ACC_FINAL, id, "Final");
ABSTRACT_CHECK (flags, ACC_NATIVE, id, "Native");
- ABSTRACT_CHECK (flags, ACC_SYNCHRONIZED,id, "Synchronized");
+ ABSTRACT_CHECK (flags, ACC_SYNCHRONIZED, id, "Synchronized");
+ ABSTRACT_CHECK (flags, ACC_STRICT, id, "Strictfp");
if (!CLASS_ABSTRACT (TYPE_NAME (this_class))
&& !CLASS_INTERFACE (TYPE_NAME (this_class)))
parse_error_context
JCONSTRUCTOR_CHECK (flags, ACC_FINAL, id, "final");
JCONSTRUCTOR_CHECK (flags, ACC_NATIVE, id, "native");
JCONSTRUCTOR_CHECK (flags, ACC_SYNCHRONIZED, id, "synchronized");
+ JCONSTRUCTOR_CHECK (flags, ACC_STRICT, id, "strictfp");
}
/* If we found error here, we don't consider it's OK to tread
the method definition as a constructor, for the rest of this
if (!CLASS_INTERFACE (super_decl))
{
parse_error_context
- (this_wfl, "Can't use %s `%s' to implement/extend %s `%s'",
- (TYPE_ARRAY_P (super_type) ? "array" : "class"),
- IDENTIFIER_POINTER (DECL_NAME (super_decl)),
+ (this_wfl, "%s `%s' can't implement/extend %s `%s'",
(CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (this_decl))) ?
- "interface" : "class"),
- IDENTIFIER_POINTER (DECL_NAME (this_decl)));
+ "Interface" : "Class"),
+ IDENTIFIER_POINTER (DECL_NAME (this_decl)),
+ (TYPE_ARRAY_P (super_type) ? "array" : "class"),
+ IDENTIFIER_POINTER (DECL_NAME (super_decl)));
return 1;
}
where found. ARGS is non NULL when a special signature must be
enforced. This is the case for anonymous classes. */
-static void
+static tree
craft_constructor (class_decl, args)
tree class_decl, args;
{
/* Now, mark the artificial parameters. */
DECL_FUNCTION_NAP (decl) = artificial;
DECL_FUNCTION_SYNTHETIC_CTOR (decl) = DECL_CONSTRUCTOR_P (decl) = 1;
+ return decl;
}
{
tree new_class_decl = NULL_TREE, super = NULL_TREE;
tree saved_enclosing_type = enclosing ? TREE_TYPE (enclosing) : NULL_TREE;
+ tree decl_result;
struct hash_table _ht, *circularity_hash = &_ht;
/* This hash table is used to register the classes we're going
if (check_pkg_class_access (TYPE_NAME (class_type), cl, true))
return NULL_TREE;
}
-
+
/* 6- Last call for a resolution */
- return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
+ decl_result = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
+
+ /* The final lookup might have registered a.b.c into a.b$c If we
+ failed at the first lookup, progressively change the name if
+ applicable and use the matching DECL instead. */
+ if (!decl_result && QUALIFIED_P (TYPE_NAME (class_type)))
+ {
+ tree name = TYPE_NAME (class_type);
+ char *separator;
+ do {
+
+ /* Reach the last '.', and if applicable, replace it by a `$' and
+ see if this exists as a type. */
+ if ((separator = strrchr (IDENTIFIER_POINTER (name), '.')))
+ {
+ int c = *separator;
+ *separator = '$';
+ name = get_identifier (IDENTIFIER_POINTER (name));
+ *separator = c;
+ decl_result = IDENTIFIER_CLASS_VALUE (name);
+ }
+ } while (!decl_result && separator);
+ }
+ return decl_result;
}
static tree
exit_block ();
}
+/* Dump a tree of some kind. This is a convenience wrapper for the
+ dump_* functions in tree-dump.c. */
+static void
+dump_java_tree (phase, t)
+ enum tree_dump_index phase;
+ tree t;
+{
+ FILE *stream;
+ int flags;
+
+ stream = dump_begin (phase, &flags);
+ if (stream)
+ {
+ dump_node (t, flags, stream);
+ dump_end (phase, stream);
+ }
+}
+
/* Terminate a function and expand its body. */
static void
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) == empty_stmt_node)
BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) = NULL_TREE;
+ /* We've generated all the trees for this function, and it has been
+ patched. Dump it to a file if the user requested it. */
+ dump_java_tree (TDI_original, fndecl);
+
/* Generate function's code */
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl))
&& ! flag_emit_class_files
if (METHOD_NATIVE (decl))
{
- tree body = build_jni_stub (decl);
+ tree body;
+ current_function_decl = decl;
+ body = build_jni_stub (decl);
BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (decl)) = body;
}
{
tree access = NULL_TREE;
- while (from != to)
+ while (from != to && PURE_INNER_CLASS_TYPE_P (from))
{
if (!access)
{
access = make_qualified_primary (cn, access, lc);
}
- /* if FROM isn't an inter class, that's fine, we've done
- enough. What we're looking for can be accessed from there. */
+ /* If FROM isn't an inner class, that's fine, we've done enough.
+ What we're looking for can be accessed from there. */
from = DECL_CONTEXT (TYPE_NAME (from));
if (!from)
break;
java_layout_classes ();
java_parse_abort_on_error ();
- cur_ctxp = ctxp_for_generation;
- for (; cur_ctxp; cur_ctxp = cur_ctxp->next)
+ for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
{
ctxp = cur_ctxp;
input_filename = ctxp->filename;
}
input_filename = main_input_filename;
- /* Find anonymous classes and expand their constructor, now they
- have been fixed. */
- for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
+
+ /* Find anonymous classes and expand their constructor. This extra pass is
+ neccessary because the constructor itself is only generated when the
+ method in which it is defined is expanded. */
+ for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
{
tree current;
ctxp = cur_ctxp;
restore_line_number_status (1);
java_complete_expand_method (d);
restore_line_number_status (0);
- break; /* We now there are no other ones */
+ break; /* There is only one constructor. */
}
}
}
return;
/* Now things are stable, go for generation of the class data. */
- for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
+
+ /* We pessimistically marked all fields external until we knew
+ what set of classes we were planning to compile. Now mark
+ those that will be generated locally as not external. */
+ for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
+ {
+ tree current;
+ ctxp = cur_ctxp;
+ for (current = ctxp->class_list; current; current = TREE_CHAIN (current))
+ {
+ tree class = TREE_TYPE (current);
+ tree field;
+ for (field = TYPE_FIELDS (class); field ; field = TREE_CHAIN (field))
+ if (FIELD_STATIC (field))
+ DECL_EXTERNAL (field) = 0;
+ }
+ }
+
+ /* Compile the classes. */
+ for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
{
tree current;
ctxp = cur_ctxp;
/* Generate the code used to initialize fields declared with an
initialization statement and build a compound statement along
with the super constructor invocation. */
+ CAN_COMPLETE_NORMALLY (patch) = 1;
patch = build (COMPOUND_EXPR, void_type_node, patch,
java_complete_tree (finit_call));
- CAN_COMPLETE_NORMALLY (patch) = 1;
}
return patch;
}
func = method;
else
{
- tree signature = build_java_signature (TREE_TYPE (method));
switch (invocation_mode (method, CALL_USING_SUPER (patch)))
{
case INVOKE_VIRTUAL:
case INVOKE_SUPER:
case INVOKE_STATIC:
- func = build_known_method_ref (method, TREE_TYPE (method),
- DECL_CONTEXT (method),
- signature, args);
+ {
+ tree signature = build_java_signature (TREE_TYPE (method));
+ func = build_known_method_ref (method, TREE_TYPE (method),
+ DECL_CONTEXT (method),
+ signature, args);
+ }
break;
case INVOKE_INTERFACE:
TREE_TYPE (patch) = TREE_TYPE (TREE_TYPE (method));
TREE_OPERAND (patch, 0) = func;
TREE_OPERAND (patch, 1) = args;
+ patch = check_for_builtin (method, patch);
original_call = patch;
/* We're processing a `new TYPE ()' form. New is called and its
know the arguments' types. */
if (lc && ANONYMOUS_CLASS_P (class))
- craft_constructor (TYPE_NAME (class), atl);
+ {
+ tree saved_current_class;
+ tree mdecl = craft_constructor (TYPE_NAME (class), atl);
+ saved_current_class = current_class;
+ current_class = class;
+ fix_constructors (mdecl);
+ current_class = saved_current_class;
+ }
/* Find all candidates and then refine the list, searching for the
most specific method. */
else if (code == INTEGER_CST)
name = qual_wfl;
-
+
else if (code == CONVERT_EXPR &&
TREE_CODE (TREE_OPERAND (qual_wfl, 0)) == EXPR_WITH_FILE_LOCATION)
name = TREE_OPERAND (qual_wfl, 0);
-
+
+ else if (code == CONVERT_EXPR
+ && TREE_CODE (TREE_OPERAND (qual_wfl, 0)) == CALL_EXPR
+ && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (qual_wfl, 0), 0))
+ == EXPR_WITH_FILE_LOCATION))
+ name = TREE_OPERAND (TREE_OPERAND (qual_wfl, 0), 0);
+
else if ((code == ARRAY_REF || code == CALL_EXPR || code == MODIFY_EXPR) &&
TREE_CODE (TREE_OPERAND (qual_wfl, 0)) == EXPR_WITH_FILE_LOCATION)
name = EXPR_WFL_NODE (TREE_OPERAND (qual_wfl, 0));
else
{
node = patch_assignment (node, wfl_op1);
+ if (node == error_mark_node)
+ return error_mark_node;
/* Reorganize the tree if necessary. */
if (flag && (!JREFERENCE_TYPE_P (TREE_TYPE (node))
|| JSTRING_P (TREE_TYPE (node))))
{
lhs_type = TREE_TYPE (lvalue);
}
- /* Or Lhs can be a array access. Should that be lvalue ? FIXME +
- comment on reason why */
- else if (TREE_CODE (wfl_op1) == ARRAY_REF)
+ /* Or Lhs can be an array access. */
+ else if (TREE_CODE (lvalue) == ARRAY_REF)
{
lhs_type = TREE_TYPE (lvalue);
lvalue_from_array = 1;
&& lvalue_from_array
&& JREFERENCE_TYPE_P (TYPE_ARRAY_ELEMENT (lhs_type)))
{
- tree check;
- tree base = lvalue;
+ tree array, store_check, base, index_expr;
+
+ /* Save RHS so that it doesn't get re-evaluated by the store check. */
+ new_rhs = save_expr (new_rhs);
- /* We need to retrieve the right argument for
- _Jv_CheckArrayStore. This is somewhat complicated by bounds
- and null pointer checks, both of which wrap the operand in
- one layer of COMPOUND_EXPR. */
- if (TREE_CODE (lvalue) == COMPOUND_EXPR)
- base = TREE_OPERAND (lvalue, 0);
- else
+ /* Get the INDIRECT_REF. */
+ array = TREE_OPERAND (TREE_OPERAND (lvalue, 0), 0);
+ /* Get the array pointer expr. */
+ array = TREE_OPERAND (array, 0);
+ store_check = build_java_arraystore_check (array, new_rhs);
+
+ index_expr = TREE_OPERAND (lvalue, 1);
+
+ if (TREE_CODE (index_expr) == COMPOUND_EXPR)
{
- tree op = TREE_OPERAND (base, 0);
-
- /* We can have a SAVE_EXPR here when doing String +=. */
- if (TREE_CODE (op) == SAVE_EXPR)
- op = TREE_OPERAND (op, 0);
- /* We can have a COMPOUND_EXPR here when doing bounds check. */
- if (TREE_CODE (op) == COMPOUND_EXPR)
- op = TREE_OPERAND (op, 1);
- base = TREE_OPERAND (op, 0);
- /* Strip the last PLUS_EXPR to obtain the base. */
- if (TREE_CODE (base) == PLUS_EXPR)
- base = TREE_OPERAND (base, 0);
- }
-
- /* Build the invocation of _Jv_CheckArrayStore */
- new_rhs = save_expr (new_rhs);
- check = build (CALL_EXPR, void_type_node,
- build_address_of (soft_checkarraystore_node),
- tree_cons (NULL_TREE, base,
- build_tree_list (NULL_TREE, new_rhs)),
- NULL_TREE);
- TREE_SIDE_EFFECTS (check) = 1;
-
- /* We have to decide on an insertion point */
- if (TREE_CODE (lvalue) == COMPOUND_EXPR)
- {
- tree t;
- if (flag_bounds_check)
- {
- t = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (lvalue, 1), 0), 0);
- TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (lvalue, 1), 0), 0) =
- build (COMPOUND_EXPR, void_type_node, t, check);
- }
- else
- TREE_OPERAND (lvalue, 1) = build (COMPOUND_EXPR, lhs_type,
- check, TREE_OPERAND (lvalue, 1));
+ /* A COMPOUND_EXPR here is a bounds check. The bounds check must
+ happen before the store check, so prepare to insert the store
+ check within the second operand of the existing COMPOUND_EXPR. */
+ base = index_expr;
}
- else if (flag_bounds_check)
- {
- tree hook = lvalue;
- tree compound = TREE_OPERAND (lvalue, 0);
- tree bound_check, new_compound;
-
- if (TREE_CODE (compound) == SAVE_EXPR)
- {
- compound = TREE_OPERAND (compound, 0);
- hook = TREE_OPERAND (hook, 0);
- }
-
- /* Find the array bound check, hook the original array access. */
- bound_check = TREE_OPERAND (compound, 0);
- TREE_OPERAND (hook, 0) = TREE_OPERAND (compound, 1);
-
- /* Make sure the bound check will happen before the store check */
- new_compound =
- build (COMPOUND_EXPR, void_type_node, bound_check, check);
-
- /* Re-assemble the augmented array access. */
- lvalue = build (COMPOUND_EXPR, TREE_TYPE (lvalue),
- new_compound, lvalue);
- }
else
- lvalue = build (COMPOUND_EXPR, TREE_TYPE (lvalue), check, lvalue);
+ base = lvalue;
+
+ index_expr = TREE_OPERAND (base, 1);
+ TREE_OPERAND (base, 1) = build (COMPOUND_EXPR, TREE_TYPE (index_expr),
+ store_check, index_expr);
}
/* Final locals can be used as case values in switch
new_rhs = rhs;
}
- /* Zero accepted everywhere */
- else if (TREE_CODE (rhs) == INTEGER_CST
- && TREE_INT_CST_HIGH (rhs) == 0 && TREE_INT_CST_LOW (rhs) == 0
- && JPRIMITIVE_TYPE_P (rhs_type))
- new_rhs = convert (lhs_type, rhs);
-
/* 5.1.1 Try Identity Conversion,
5.1.2 Try Widening Primitive Conversion */
else if (valid_builtin_assignconv_identity_widening_p (lhs_type, rhs_type))
= EXPR_WFL_LINECOL (TREE_PURPOSE (iter));
/* The case_label_list is in reverse order, so print the
outer label first. */
- parse_error_context (wfl_operator, "duplicate case label: `%d'",
- subval);
+ parse_error_context (wfl_operator, "duplicate case label: `"
+ HOST_WIDE_INT_PRINT_DEC "'", subval);
EXPR_WFL_LINECOL (wfl_operator)
= EXPR_WFL_LINECOL (TREE_PURPOSE (subiter));
parse_error_context (wfl_operator, "original label is here");
init_src_parse ()
{
/* Register roots with the garbage collector. */
- ggc_add_tree_root (src_parse_roots, sizeof (src_parse_roots) / sizeof(tree));
+ ggc_add_tree_root (src_parse_roots, ARRAY_SIZE (src_parse_roots));
}
\f