static tree method_header PROTO ((int, tree, tree, tree));
static void fix_method_argument_names PROTO ((tree ,tree));
static tree method_declarator PROTO ((tree, tree));
-static void parse_warning_context VPROTO ((tree cl, char *msg, ...));
-static void issue_warning_error_from_context PROTO ((tree, char *msg, va_list));
+static void parse_warning_context PVPROTO ((tree cl, const char *msg, ...))
+ ATTRIBUTE_PRINTF_2;
+static void issue_warning_error_from_context PROTO ((tree, const char *msg, va_list));
static tree parse_jdk1_1_error PROTO ((char *));
static void complete_class_report_errors PROTO ((jdep *));
static int process_imports PROTO ((void));
static tree resolve_package PROTO ((tree, tree *));
static tree lookup_package_type PROTO ((char *, int));
static tree resolve_class PROTO ((tree, tree, tree));
-static tree do_resolve_class PROTO ((tree, tree, tree));
static void declare_local_variables PROTO ((int, tree, tree));
static void source_start_java_method PROTO ((tree));
static void source_end_java_method PROTO ((void));
static tree build_string_concatenation PROTO ((tree, tree));
static tree patch_string_cst PROTO ((tree));
static tree patch_string PROTO ((tree));
-static tree build_jump_to_finally PROTO ((tree, tree, tree, tree));
-static tree build_try_statement PROTO ((int, tree, tree, tree));
+static tree build_try_statement PROTO ((int, tree, tree));
+static tree build_try_finally_statement PROTO ((int, tree, tree));
static tree patch_try_statement PROTO ((tree));
static tree patch_synchronized_statement PROTO ((tree, tree));
static tree patch_throw_statement PROTO ((tree, tree));
static char *purify_type_name PROTO ((char *));
static tree patch_initialized_static_field PROTO ((tree));
static tree fold_constant_for_init PROTO ((tree, tree));
+static tree strip_out_static_field_access_decl PROTO ((tree));
+static jdeplist *reverse_jdep_list PROTO ((struct parser_ctxt *));
/* Number of error found so far. */
int java_error_count;
/* The "toString" identifier used for String `+' operator. */
static tree wfl_to_string = NULL_TREE;
+
+/* The "java.lang" import qualified name. */
+static tree java_lang_id = NULL_TREE;
+
+/* The "java.lang.Cloneable" qualified name. */
+static tree java_lang_cloneable = NULL_TREE;
%}
%union {
IMPORT_TK name DOT_TK MULT_TK SC_TK
{
tree name = EXPR_WFL_NODE ($2);
- tree node = build_tree_list ($2, NULL_TREE);
- read_import_dir ($2);
- TREE_CHAIN (node) = ctxp->import_demand_list;
- ctxp->import_demand_list = node;
+ /* Don't import java.lang.* twice. */
+ if (name != java_lang_id)
+ {
+ tree node = build_tree_list ($2, NULL_TREE);
+ read_import_dir ($2);
+ TREE_CHAIN (node) = ctxp->import_demand_list;
+ ctxp->import_demand_list = node;
+ }
}
| IMPORT_TK name DOT_TK error
{yyerror ("'*' expected"); RECOVER;}
| CLASS_TK error
{yyerror ("Missing class name"); RECOVER;}
| CLASS_TK identifier error
- {if (!ctxp->class_err) yyerror ("'{' expected"); DRECOVER(class1);}
+ {
+ if (!ctxp->class_err) yyerror ("'{' expected");
+ DRECOVER(class1);
+ }
| modifiers CLASS_TK identifier error
{if (!ctxp->class_err) yyerror ("'{' expected"); RECOVER;}
;
class_member_declaration:
field_declaration
+| field_declaration SC_TK
+ { $$ = $1; }
| method_declaration
| class_declaration /* Added, JDK1.1 inner classes */
{ $$ = parse_jdk1_1_error ("inner classe declaration"); }
$$ = $6;
}
| INTERFACE_TK identifier error
- {yyerror ("(here)'{' expected"); RECOVER;}
+ {yyerror ("'{' expected"); RECOVER;}
| modifiers INTERFACE_TK identifier error
- {yyerror ("(there)'{' expected"); RECOVER;}
+ {yyerror ("'{' expected"); RECOVER;}
;
extends_interfaces:
if_then_statement:
IF_TK OP_TK expression CP_TK statement
- { $$ = build_if_else_statement ($2.location, $3, $5, NULL_TREE); }
+ {
+ $$ = build_if_else_statement ($2.location, $3,
+ $5, NULL_TREE);
+ }
| IF_TK error
{yyerror ("'(' expected"); RECOVER;}
| IF_TK OP_TK error
if_then_else_statement:
IF_TK OP_TK expression CP_TK statement_nsi ELSE_TK statement
- { $$ = build_if_else_statement ($2.location, $3, $5, $7); }
+ { $$ = build_if_else_statement ($2.location, $3, $5, $7); }
;
if_then_else_statement_nsi:
IF_TK OP_TK expression CP_TK statement_nsi ELSE_TK statement_nsi
- { $$ = build_if_else_statement ($2.location, $3, $5, $7); }
+ { $$ = build_if_else_statement ($2.location, $3, $5, $7); }
;
switch_statement:
for_statement:
for_begin SC_TK expression SC_TK for_update CP_TK statement
- { $$ = complete_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7);}
+ { $$ = complete_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7); }
| for_begin SC_TK SC_TK for_update CP_TK statement
{
$$ = complete_for_loop (0, NULL_TREE, $4, $6);
try_statement:
TRY_TK block catches
- { $$ = build_try_statement ($1.location, $2, $3, NULL_TREE); }
+ { $$ = build_try_statement ($1.location, $2, $3); }
| TRY_TK block finally
- { $$ = build_try_statement ($1.location, $2, NULL_TREE, $3); }
+ { $$ = build_try_finally_statement ($1.location, $2, $3); }
| TRY_TK block catches finally
- { $$ = build_try_statement ($1.location, $2, $3, $4); }
+ { $$ = build_try_finally_statement
+ ($1.location, build_try_statement ($1.location,
+ $2, $3), $4);
+ }
| TRY_TK error
{yyerror ("'{' expected"); DRECOVER (try_statement);}
;
finally:
FINALLY_TK block
- {
- $$ = build (FINALLY_EXPR, NULL_TREE,
- create_label_decl (generate_name ()), $2);
- }
+ { $$ = $2; }
| FINALLY_TK error
{yyerror ("'{' expected"); RECOVER; }
;
| NEW_TK class_or_interface_type dim_exprs
{ $$ = build_newarray_node ($2, $3, 0); }
| NEW_TK primitive_type dim_exprs dims
- { $$ = build_newarray_node ($2, $3, ctxp->osb_number); }
+ { $$ = build_newarray_node ($2, $3, CURRENT_OSB (ctxp));}
| NEW_TK class_or_interface_type dim_exprs dims
- { $$ = build_newarray_node ($2, $3, ctxp->osb_number); }
+ { $$ = build_newarray_node ($2, $3, CURRENT_OSB (ctxp));}
/* Added, JDK1.1 anonymous array. Initial documentation rule
modified */
| NEW_TK class_or_interface_type dims array_initializer
dims:
OSB_TK CSB_TK
- { ctxp->osb_number = 1; }
+ {
+ int allocate = 0;
+ /* If not initialized, allocate memory for the osb
+ numbers stack */
+ if (!ctxp->osb_limit)
+ {
+ allocate = ctxp->osb_limit = 32;
+ ctxp->osb_depth = -1;
+ }
+ /* If capacity overflown, reallocate a bigger chuck */
+ else if (ctxp->osb_depth+1 == ctxp->osb_limit)
+ allocate = ctxp->osb_limit << 1;
+
+ if (allocate)
+ {
+ allocate *= sizeof (int);
+ if (ctxp->osb_number)
+ ctxp->osb_number = (int *)xrealloc (ctxp->osb_number,
+ allocate);
+ else
+ ctxp->osb_number = (int *)xmalloc (allocate);
+ }
+ ctxp->osb_depth++;
+ CURRENT_OSB (ctxp) = 1;
+ }
| dims OSB_TK CSB_TK
- { ctxp->osb_number++; }
+ { CURRENT_OSB (ctxp)++; }
| dims OSB_TK error
{ yyerror ("']' expected"); RECOVER;}
;
OP_TK primitive_type dims CP_TK unary_expression
{
tree type = $2;
- while (ctxp->osb_number--)
+ while (CURRENT_OSB (ctxp)--)
type = build_java_array_type (type, -1);
+ ctxp->osb_depth--;
$$ = build_cast ($1.location, type, $5);
}
| OP_TK primitive_type CP_TK unary_expression
| OP_TK name dims CP_TK unary_expression_not_plus_minus
{
char *ptr;
- while (ctxp->osb_number--)
+ while (CURRENT_OSB (ctxp)--)
obstack_1grow (&temporary_obstack, '[');
+ ctxp->osb_depth--;
obstack_grow0 (&temporary_obstack,
IDENTIFIER_POINTER (EXPR_WFL_NODE ($2)),
IDENTIFIER_LENGTH (EXPR_WFL_NODE ($2)));
static void
issue_warning_error_from_context (cl, msg, ap)
tree cl;
- char *msg;
+ const char *msg;
va_list ap;
{
char *saved, *saved_input_filename;
/* Issue an error message at a current source line CL */
void
-parse_error_context VPROTO ((tree cl, char *msg, ...))
+parse_error_context VPROTO ((tree cl, const char *msg, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
tree cl;
- char *msg;
+ const char *msg;
#endif
va_list ap;
VA_START (ap, msg);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
cl = va_arg (ap, tree);
- msg = va_arg (ap, char *);
+ msg = va_arg (ap, const char *);
#endif
issue_warning_error_from_context (cl, msg, ap);
va_end (ap);
/* Issue a warning at a current source line CL */
static void
-parse_warning_context VPROTO ((tree cl, char *msg, ...))
+parse_warning_context VPROTO ((tree cl, const char *msg, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
tree cl;
- char *msg;
+ const char *msg;
#endif
va_list ap;
VA_START (ap, msg);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
cl = va_arg (ap, tree);
- msg = va_arg (ap, char *);
+ msg = va_arg (ap, const char *);
#endif
force_error = do_warning = 1;
switch (TREE_CODE (node))
{
case BLOCK:
- return find_expr_with_wfl (BLOCK_EXPR_BODY (node));
+ node = BLOCK_EXPR_BODY (node);
+ continue;
case COMPOUND_EXPR:
to_return = find_expr_with_wfl (TREE_OPERAND (node, 0));
if (to_return)
return to_return;
- to_return = find_expr_with_wfl (TREE_OPERAND (node, 1));
- return to_return;
+ node = TREE_OPERAND (node, 1);
+ continue;
case LOOP_EXPR:
- return find_expr_with_wfl (TREE_OPERAND (node, 0));
+ node = TREE_OPERAND (node, 0);
+ continue;
case LABELED_BLOCK_EXPR:
- return find_expr_with_wfl (TREE_OPERAND (node, 1));
+ node = TREE_OPERAND (node, 1);
+ continue;
+
default:
code = TREE_CODE_CLASS (TREE_CODE (node));
if (((code == '1') || (code == '2') || (code == 'e'))
&& EXPR_WFL_LINECOL (node))
return node;
+ return NULL_TREE;
}
}
return NULL_TREE;
/* If we have, then craft a new type for this variable */
if (more_dims)
{
- name = get_identifier (&more_dims [string]);
+ name = get_identifier (&string [more_dims]);
- /* If type already is a reference on an array, get the base type */
- if ((TREE_CODE (type) == POINTER_TYPE) &&
- TYPE_ARRAY_P (TREE_TYPE (type)))
- type = TREE_TYPE (type);
+ /* If we have a pointer, use its type */
+ if (TREE_CODE (type) == POINTER_TYPE)
+ type = TREE_TYPE (type);
/* Building the first dimension of a primitive type uses this
function */
decl = maybe_create_class_interface_decl (decl, q_name, id);
/* Set super info and mark the class a complete */
- set_super_info (ACC_ABSTRACT | ACC_INTERFACE | flags, TREE_TYPE (decl),
+ set_super_info (ACC_INTERFACE | flags, TREE_TYPE (decl),
object_type_node, ctxp->interface_number);
ctxp->interface_number = 0;
CLASS_COMPLETE_P (decl) = 1;
return NULL_TREE;
}
- /* The class is known and exists if there is a decl. Otherwise,
- postpone the operation and do it later. */
- super_decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (super));
- if (super_decl)
- {
- parser_check_super (super_decl, decl, id);
- super_decl_type = TREE_TYPE (super_decl);
- }
- else
- super_decl_type =
- register_incomplete_type (JDEP_SUPER, super, decl, NULL_TREE);
+ super_decl_type =
+ register_incomplete_type (JDEP_SUPER, super, decl, NULL_TREE);
}
else if (TREE_TYPE (decl) != object_type_node)
super_decl_type = object_type_node;
if (must_chain)
register_incomplete_type (JDEP_FIELD, wfl, field_decl, type);
- /* Default value of a static field is 0 and it is considered
- initialized. */
- if (flags & ACC_STATIC)
- INITIALIZED_P (field_decl) = 1;
-
/* If we have an initialization value tied to the field */
if (init)
{
{
/* We include the field and its initialization part into
a list used to generate <clinit>. After <clinit> is
- walked, fields initialization will be processed and
- fields initialized with know constants will be taken
- out of <clinit> and have ther DECL_INITIAL set
+ walked, field initializations will be processed and
+ fields initialized with known constants will be taken
+ out of <clinit> and have their DECL_INITIAL set
appropriately. */
TREE_CHAIN (init) = ctxp->static_initialized;
ctxp->static_initialized = init;
DECL_INITIAL (field_decl) = TREE_OPERAND (init, 1);
if (TREE_CODE (TREE_OPERAND (init, 1)) == NEW_ARRAY_INIT)
- TREE_STATIC (TREE_OPERAND (TREE_OPERAND (init, 1), 0)) = 1;
+ TREE_STATIC (TREE_OPERAND (init, 1)) = 1;
}
/* A non-static field declared with an immediate initialization is
to be initialized in <init>, if any. This field is remembered
TREE_CHAIN (init) = ctxp->non_static_initialized;
ctxp->non_static_initialized = init;
}
- INITIALIZED_P (field_decl) = 1;
MODIFY_EXPR_FROM_INITIALIZATION_P (init) = 1;
}
}
ABSTRACT_CHECK (flags, ACC_FINAL, id, "Final");
ABSTRACT_CHECK (flags, ACC_NATIVE, id, "Native");
ABSTRACT_CHECK (flags, ACC_SYNCHRONIZED,id, "Synchronized");
- if (!CLASS_ABSTRACT (TYPE_NAME (this_class)))
+ if (!CLASS_ABSTRACT (TYPE_NAME (this_class))
+ && !CLASS_INTERFACE (TYPE_NAME (this_class)))
parse_error_context
(id, "Class `%s' must be declared abstract to define abstract "
"method `%s'",
/* Method declared within the scope of an interface are implicitly
abstract and public. Conflicts with other erroneously provided
- modifiers are check right after. */
+ modifiers are checked right after. */
if (CLASS_INTERFACE (TYPE_NAME (this_class)))
{
fatal ("invalid type name - obtain_incomplete_type");
for (ptr = ctxp->incomplete_class; ptr; ptr = TREE_CHAIN (ptr))
- if (TYPE_NAME (TREE_PURPOSE (ptr)) == name)
+ if (TYPE_NAME (ptr) == name)
break;
if (!ptr)
{
- tree core;
push_obstacks (&permanent_obstack, &permanent_obstack);
- BUILD_PTR_FROM_NAME (core, name);
- layout_type (core);
- ptr = build_tree_list (core, NULL_TREE);
+ BUILD_PTR_FROM_NAME (ptr, name);
+ layout_type (ptr);
pop_obstacks ();
TREE_CHAIN (ptr) = ctxp->incomplete_class;
ctxp->incomplete_class = ptr;
{
char *name = IDENTIFIER_POINTER (TYPE_NAME (class_type));
char *base = name;
- tree resolved_type, resolved_type_decl;
+ tree resolved_type = TREE_TYPE (class_type);
+ tree resolved_type_decl;
+ if (resolved_type != NULL_TREE)
+ {
+ tree resolved_type_decl = TYPE_NAME (resolved_type);
+ if (resolved_type_decl == NULL_TREE
+ || TREE_CODE (resolved_type_decl) == IDENTIFIER_NODE)
+ {
+ resolved_type_decl = build_decl (TYPE_DECL,
+ TYPE_NAME (class_type),
+ resolved_type);
+ }
+ return resolved_type_decl;
+ }
+
/* 1- Check to see if we have an array. If true, find what we really
want to resolve */
while (name[0] == '[')
/* Figure how those two things are important for error report. FIXME */
DECL_SOURCE_LINE (resolved_type_decl) = 0;
DECL_SOURCE_FILE (resolved_type_decl) = input_filename;
+ TYPE_NAME (class_type) = TYPE_NAME (resolved_type);
}
+ TREE_TYPE (class_type) = resolved_type;
return resolved_type_decl;
}
/* Effectively perform the resolution of class CLASS_TYPE. DECL or CL
are used to report error messages. */
-static tree
+tree
do_resolve_class (class_type, decl, cl)
tree class_type;
tree decl;
tree cl;
{
tree new_class_decl;
- tree new_name;
tree original_name = NULL_TREE;
/* Do not try to replace TYPE_NAME (class_type) by a variable, since
tree redef, name;
tree cl = DECL_NAME (method);
tree sig = TYPE_ARGUMENT_SIGNATURE (TREE_TYPE (method));
- /* decl name of artificial <clinit> and $finit$ doesn't need to be fixed and
- checked */
+ /* decl name of artificial <clinit> and $finit$ doesn't need to be
+ fixed and checked */
/* Reset the method name before running the check. If it returns 1,
the method doesn't need to be verified with respect to method
/* If we previously found something and its name was saved,
reinstall it now */
if (found && saved_found_wfl)
- DECL_NAME (found) = saved_found_wfl;
+ {
+ DECL_NAME (found) = saved_found_wfl;
+ saved_found_wfl = NULL_TREE;
+ }
/* Check for redefinitions */
if (check_method_redefinition (class, method))
found = lookup_argument_method (super_class, DECL_NAME (method), sig);
/* Nothing overrides or it's a private method. */
- if (!found || (found && METHOD_PRIVATE (found)))
+ if (!found)
continue;
+ if (METHOD_PRIVATE (found))
+ {
+ found = NULL_TREE;
+ continue;
+ }
/* If found wasn't verified, it's DECL_NAME won't be set properly.
We set it temporarily for the sake of the error report. */
char *package_name = IDENTIFIER_POINTER (package_id);
int package_length = IDENTIFIER_LENGTH (package_id);
DIR *dirp = NULL;
- JCF jcfr, *jcf, *saved_jcf = current_jcf;
+ JCF *saved_jcf = current_jcf;
int found = 0;
int k;
}
*filename->ptr++ = '/';
- for (; k < zipf->count; k++, zipd = ZIPDIR_NEXT (zipd))
+ for (k = 0; k < zipf->count; k++, zipd = ZIPDIR_NEXT (zipd))
{
char *current_entry = ZIPDIR_FILENAME (zipd);
int current_entry_len = zipd->filename_length;
- if (strncmp (filename->data, current_entry,
- BUFFER_LENGTH (filename)) != 0)
+ if (current_entry_len >= BUFFER_LENGTH (filename)
+ && strncmp (filename->data, current_entry,
+ BUFFER_LENGTH (filename)) != 0)
continue;
- found += note_possible_classname (current_entry,
+ found |= note_possible_classname (current_entry,
current_entry_len);
}
}
*filename->ptr++ = '/';
for (;;)
{
- int java_or_class = 0;
int len;
char *d_name;
struct dirent *direntp = readdir (dirp);
len = strlen (direntp->d_name);
buffer_grow (filename, len+1);
strcpy (filename->ptr, d_name);
- found += note_possible_classname (filename->data + entry_length,
+ found |= note_possible_classname (filename->data + entry_length,
package_length+len+1);
}
if (dirp)
if (!CLASS_PUBLIC (TYPE_NAME (type)))
{
+ /* Access to a private class within the same package is
+ allowed. */
+ tree l, r;
+ breakdown_qualified (&l, &r, class_name);
+ if (l == ctxp->package)
+ return 0;
+
parse_error_context
(cl, "Can't access %s `%s'. Only public classes and interfaces in "
"other packages can be accessed",
tree type_wfl = NULL_TREE;
int must_chain = 0;
- /* Push a new block if statement were seen between the last time we
+ /* Push a new block if statements were seen between the last time we
pushed a block and now. Keep a cound of block to close */
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (current_function_decl)))
{
DECL_ARG_TYPE (tem) = type;
layout_decl (tem, 0);
pushdecl (tem);
- INITIALIZED_P (tem) = 1; /* Parms are initialized */
*ptr = tem;
ptr = &TREE_CHAIN (tem);
tem = next;
*ptr = NULL_TREE;
pushdecl_force_head (DECL_ARGUMENTS (fndecl));
lineno = DECL_SOURCE_LINE_FIRST (fndecl);
- complete_start_java_method (fndecl);
}
/* Terminate a function and expand its body. */
{
if (flag_emit_class_files)
write_classfile (current_class);
- else
+ else if (! flag_syntax_only)
finish_class (current_class);
}
}
tree fbody = DECL_FUNCTION_BODY (mdecl);
tree block_body = BLOCK_EXPR_BODY (fbody);
expand_start_java_method (mdecl);
+ build_result_decl (mdecl);
current_this
= (!METHOD_STATIC (mdecl) ?
&& TREE_CODE (TREE_TYPE (TREE_TYPE (mdecl))) != VOID_TYPE)
missing_return_error (current_function_decl);
+ complete_start_java_method (mdecl);
+
/* Don't go any further if we've found error(s) during the
expansion */
if (!java_error_count)
}
/* We might have been trying to resolve field.method(). In which
case, the resolution is over and decl is the answer */
- else if (DECL_P (decl) && IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) == decl)
+ else if (JDECL_P (decl) && IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) == decl)
field_ref = decl;
- else if (DECL_P (decl))
+ else if (JDECL_P (decl))
{
int static_final_found = 0;
if (!type_found)
type_found = DECL_CONTEXT (decl);
- is_static = DECL_P (decl) && FIELD_STATIC (decl);
+ is_static = JDECL_P (decl) && FIELD_STATIC (decl);
if (FIELD_FINAL (decl)
&& JPRIMITIVE_TYPE_P (TREE_TYPE (decl))
&& DECL_LANG_SPECIFIC (decl)
return field_ref;
}
+/* If NODE is an access to f static field, strip out the class
+ initialization part and return the field decl, otherwise, return
+ NODE. */
+
+static tree
+strip_out_static_field_access_decl (node)
+ tree node;
+{
+ if (TREE_CODE (node) == COMPOUND_EXPR)
+ {
+ tree op1 = TREE_OPERAND (node, 1);
+ if (TREE_CODE (op1) == COMPOUND_EXPR)
+ {
+ tree call = TREE_OPERAND (op1, 0);
+ if (TREE_CODE (call) == CALL_EXPR
+ && TREE_CODE (TREE_OPERAND (call, 0)) == ADDR_EXPR
+ && TREE_OPERAND (TREE_OPERAND (call, 0), 0)
+ == soft_initclass_node)
+ return TREE_OPERAND (op1, 1);
+ }
+ }
+ return node;
+}
+
/* 6.5.5.2: Qualified Expression Names */
static int
case NEW_CLASS_EXPR:
/* If the access to the function call is a non static field,
build the code to access it. */
- if (DECL_P (decl) && !FIELD_STATIC (decl))
+ if (JDECL_P (decl) && !FIELD_STATIC (decl))
{
decl = maybe_access_field (decl, *where_found,
DECL_CONTEXT (decl));
}
continue;
+ case NEW_ARRAY_EXPR:
+ *where_found = decl = java_complete_tree (qual_wfl);
+ if (decl == error_mark_node)
+ return 1;
+ *type_found = type = QUAL_DECL_TYPE (decl);
+ CLASS_LOADED_P (type) = 1;
+ continue;
+
case CONVERT_EXPR:
*where_found = decl = java_complete_tree (qual_wfl);
if (decl == error_mark_node)
case ARRAY_REF:
/* If the access to the function call is a non static field,
build the code to access it. */
- if (DECL_P (decl) && !FIELD_STATIC (decl))
+ if (JDECL_P (decl) && !FIELD_STATIC (decl))
{
decl = maybe_access_field (decl, *where_found, type);
if (decl == error_mark_node)
parse_error_context
(qual_wfl, "Can't access %s field `%s.%s' from `%s'",
java_accstring_lookup (get_access_flags_from_decl (decl)),
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
+ GET_TYPE_NAME (type),
IDENTIFIER_POINTER (DECL_NAME (decl)),
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))));
return 1;
return 1;
}
- if (!(field_decl =
- lookup_field_wrapper (type, EXPR_WFL_NODE (qual_wfl))))
+ field_decl = lookup_field_wrapper (type,
+ EXPR_WFL_NODE (qual_wfl));
+ if (field_decl == NULL_TREE)
{
parse_error_context
- (qual_wfl, "No variable `%s' defined in class `%s'",
+ (qual_wfl, "No variable `%s' defined in type `%s'",
IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)),
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
+ GET_TYPE_NAME (type));
return 1;
}
+ if (field_decl == error_mark_node)
+ return 1;
/* Layout the type of field_decl, since we may need
it. Don't do primitive types or loaded classes. The
"Can't access %s field `%s.%s' from `%s'",
java_accstring_lookup
(get_access_flags_from_decl (field_decl)),
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
+ GET_TYPE_NAME (type),
IDENTIFIER_POINTER (DECL_NAME (field_decl)),
IDENTIFIER_POINTER
(DECL_NAME (TYPE_NAME (current_class))));
tree list;
int is_static_flag = 0;
int is_super_init = 0;
+ tree this_arg = NULL_TREE;
/* Should be overriden if everything goes well. Otherwise, if
something fails, it should keep this value. It stop the
identifier, args);
/* 4- Add the field as an argument */
- args = tree_cons (NULL_TREE, field, nreverse (args));
+ args = nreverse (args);
+ this_arg = field;
}
/* IDENTIFIER_WFL will be used to report any problem further */
returned by the object allocator. If method is resolved as a
primary, use the primary otherwise use the current THIS. */
args = nreverse (args);
- if (!METHOD_STATIC (list) && TREE_CODE (patch) != NEW_CLASS_EXPR)
- args = tree_cons (NULL_TREE, primary ? primary : current_this, args);
+ if (TREE_CODE (patch) != NEW_CLASS_EXPR)
+ this_arg = primary ? primary : current_this;
}
/* Merge point of all resolution schemes. If we have nothing, this
check_deprecation (wfl, list);
is_static_flag = METHOD_STATIC (list);
+ if (! METHOD_STATIC (list) && this_arg != NULL_TREE)
+ args = tree_cons (NULL_TREE, this_arg, args);
/* In the context of an explicit constructor invocation, we can't
invoke any method relying on `this'. Exceptions are: we're
/* Fix the arguments */
for (node = arg_list; node; node = TREE_CHAIN (node))
{
- tree current_arg = TREE_VALUE (node);
- /* Integer constant 0 passed as itself, not as a type */
- if (current_arg != integer_zero_node)
- current_arg = TREE_TYPE (TREE_VALUE (node));
+ tree current_arg = TREE_TYPE (TREE_VALUE (node));
/* Non primitive type may have to be resolved */
- if (current_arg != integer_zero_node
- && !JPRIMITIVE_TYPE_P (current_arg))
+ if (!JPRIMITIVE_TYPE_P (current_arg))
resolve_and_layout (current_arg, NULL_TREE);
/* And promoted */
if (TREE_CODE (current_arg) == RECORD_TYPE)
candidates = obstack_finish (&temporary_obstack);
}
/* Issue the error message */
- for (node = atl; node; node = TREE_CHAIN (node))
- if (TREE_VALUE (node) == integer_zero_node)
- TREE_VALUE (node) = long_type_node;
method = make_node (FUNCTION_TYPE);
TYPE_ARG_TYPES (method) = atl;
signature = build_java_argument_signature (method);
tree id;
{
tree qual, qual_wfl, name, decl, ptr_type, saved_current_class;
- int again, super_found = 0, this_found = 0;
+ int again, super_found = 0, this_found = 0, new_array_found = 0;
/* We first qualify the first element, then derive qualification of
others based on the first one. If the first element is qualified
qual_wfl = QUAL_WFL (qual);
}
break;
+ case NEW_ARRAY_EXPR:
+ qual = TREE_CHAIN (qual);
+ new_array_found = again = 1;
+ continue;
case NEW_CLASS_EXPR:
case CONVERT_EXPR:
qual_wfl = TREE_OPERAND (qual_wfl, 0);
/* Do one more interation to set things up */
super_found = again = 1;
}
- /* Loop one more time if we're dealing with ?: or a string constant */
+ /* Loop one more time if we're dealing with ?: or a string
+ constant, or a convert expression */
if (TREE_CODE (qual_wfl) == CONDITIONAL_EXPR
- || TREE_CODE (qual_wfl) == STRING_CST)
+ || TREE_CODE (qual_wfl) == STRING_CST
+ || TREE_CODE (qual_wfl) == CONVERT_EXPR)
{
qual = TREE_CHAIN (qual);
qual_wfl = QUAL_WFL (qual);
declaration or parameter declaration, then it is an expression
name. We don't carry this test out if we're in the context of the
use of SUPER or THIS */
-
if (!this_found && !super_found && (decl = IDENTIFIER_LOCAL_VALUE (name)))
{
RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
/* If within the class/interface NAME was found to be used there
exists a (possibly inherited) field named NAME, then this is an
- expression name. */
- else if ((decl = lookup_field_wrapper (ptr_type, name)))
+ expression name. If we saw a NEW_ARRAY_EXPR before and want to
+ address length, it is OK. */
+ else if ((decl = lookup_field_wrapper (ptr_type, name))
+ || (new_array_found && name == length_identifier_node))
{
RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
- QUAL_RESOLUTION (qual) = decl;
+ QUAL_RESOLUTION (qual) = (new_array_found ? NULL_TREE : decl);
}
/* We reclassify NAME as a type name if:
return node;
}
+static tree
+java_stabilize_reference (node)
+ tree node;
+{
+ if (TREE_CODE (node) == COMPOUND_EXPR)
+ {
+ tree op0 = TREE_OPERAND (node, 0);
+ tree op1 = TREE_OPERAND (node, 1);
+ TREE_OPERAND (node, 0) = build1 (SAVE_EXPR, TREE_TYPE (op0), op0);
+ TREE_OPERAND (node, 1) = java_stabilize_reference (op1);
+ return node;
+ }
+ else
+ return stabilize_reference (node);
+}
+
/* Patch tree nodes in a function body. When a BLOCK is found, push
local variable decls if present.
Same as java_complete_tree, but does not resolve static finals to values. */
{
DECL_CONTEXT (cn) = current_function_decl;
IDENTIFIER_LOCAL_VALUE (DECL_NAME (cn)) = cn;
- INITIALIZED_P (cn) = 0;
}
if (BLOCK_EXPR_BODY (node) == NULL_TREE)
CAN_COMPLETE_NORMALLY (node) = 1;
/* Now do the actual complete, without deep recursion for
long blocks. */
ptr = &BLOCK_EXPR_BODY (node);
- while (TREE_CODE (*ptr) == COMPOUND_EXPR)
+ while (TREE_CODE (*ptr) == COMPOUND_EXPR
+ && TREE_OPERAND (*ptr, 1) != empty_stmt_node)
{
tree cur = java_complete_tree (TREE_OPERAND (*ptr, 0));
tree *next = &TREE_OPERAND (*ptr, 1);
break;
}
if (TREE_CODE (wfl_op2) != CASE_EXPR
- && TREE_CODE (wfl_op2) != DEFAULT_EXPR
- && wfl_op2 != empty_stmt_node)
+ && TREE_CODE (wfl_op2) != DEFAULT_EXPR)
unreachable_stmt_error (*ptr);
}
ptr = next;
case TRY_EXPR:
return patch_try_statement (node);
+ case TRY_FINALLY_EXPR:
+ COMPLETE_CHECK_OP_0 (node);
+ COMPLETE_CHECK_OP_1 (node);
+ CAN_COMPLETE_NORMALLY (node)
+ = (CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0))
+ && CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1)));
+ TREE_TYPE (node) = TREE_TYPE (TREE_OPERAND (node, 0));
+ return node;
+
case CLEANUP_POINT_EXPR:
COMPLETE_CHECK_OP_0 (node);
TREE_TYPE (node) = void_type_node;
- CAN_COMPLETE_NORMALLY (node) = CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0));
+ CAN_COMPLETE_NORMALLY (node) =
+ CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0));
return node;
case WITH_CLEANUP_EXPR:
COMPLETE_CHECK_OP_0 (node);
COMPLETE_CHECK_OP_2 (node);
- CAN_COMPLETE_NORMALLY (node) = CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0));
+ CAN_COMPLETE_NORMALLY (node) =
+ CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0));
TREE_TYPE (node) = void_type_node;
return node;
wfl_op2 = TREE_OPERAND (node, 1);
TREE_OPERAND (node, 0) = nn =
java_complete_tree (TREE_OPERAND (node, 0));
- if (! CAN_COMPLETE_NORMALLY (nn) && TREE_CODE (nn) != ERROR_MARK
- && TREE_OPERAND (node, 1) != empty_stmt_node)
+ if (wfl_op2 == empty_stmt_node)
+ CAN_COMPLETE_NORMALLY (node) = CAN_COMPLETE_NORMALLY (nn);
+ else
{
- SET_WFL_OPERATOR (wfl_operator, node, wfl_op2);
- parse_error_context (wfl_operator, "Unreachable statement");
+ if (! CAN_COMPLETE_NORMALLY (nn) && TREE_CODE (nn) != ERROR_MARK)
+ {
+ /* An unreachable condition in a do-while statement
+ is *not* (technically) an unreachable statement. */
+ nn = wfl_op2;
+ if (TREE_CODE (nn) == EXPR_WITH_FILE_LOCATION)
+ nn = EXPR_WFL_NODE (nn);
+ if (TREE_CODE (nn) != EXIT_EXPR)
+ {
+ SET_WFL_OPERATOR (wfl_operator, node, wfl_op2);
+ parse_error_context (wfl_operator, "Unreachable statement");
+ }
+ }
+ TREE_OPERAND (node, 1) = java_complete_tree (TREE_OPERAND (node, 1));
+ if (TREE_OPERAND (node, 1) == error_mark_node)
+ return error_mark_node;
+ CAN_COMPLETE_NORMALLY (node)
+ = CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1));
}
- TREE_OPERAND (node, 1) = java_complete_tree (TREE_OPERAND (node, 1));
- if (TREE_OPERAND (node, 1) == error_mark_node)
- return error_mark_node;
TREE_TYPE (node) = TREE_TYPE (TREE_OPERAND (node, 1));
- CAN_COMPLETE_NORMALLY (node)
- = CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1));
break;
case RETURN_EXPR:
|| TREE_CODE (EXPR_WFL_NODE (node)) == IDENTIFIER_NODE)
{
node = resolve_expression_name (node, NULL);
+ if (node == error_mark_node)
+ return node;
CAN_COMPLETE_NORMALLY (node) = 1;
}
else
body = java_complete_tree (EXPR_WFL_NODE (node));
lineno = save_lineno;
EXPR_WFL_NODE (node) = body;
- TREE_SIDE_EFFECTS (node) = 1;
+ TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (body);
CAN_COMPLETE_NORMALLY (node) = CAN_COMPLETE_NORMALLY (body);
- if (EXPR_WFL_NODE (node) == error_mark_node)
+ if (body == error_mark_node)
{
/* Its important for the evaluation of assignment that
this mark on the TREE_TYPE is propagated. */
tree_cons (wfl, decl,
DECL_CONSTRUCTOR_CALLS (current_function_decl));
CAN_COMPLETE_NORMALLY (node) = 1;
- return node;
+ return force_evaluation_order (node);
}
case MODIFY_EXPR:
if (COMPOUND_ASSIGN_P (wfl_op2))
{
- tree lvalue;
- tree other =
- java_complete_tree (TREE_OPERAND (wfl_op2, 0));
+ tree lvalue = java_stabilize_reference (TREE_OPERAND (node, 0));
/* Hand stablize the lhs on both places */
- lvalue = stabilize_reference (other);
TREE_OPERAND (node, 0) = lvalue;
TREE_OPERAND (TREE_OPERAND (node, 1), 0) = lvalue;
+
+ /* Now complete the RHS. We write it back later on. */
+ nn = java_complete_tree (TREE_OPERAND (node, 1));
+
+ /* The last part of the rewrite for E1 op= E2 is to have
+ E1 = (T)(E1 op E2), with T being the type of E1. */
+ nn = build_cast (EXPR_WFL_LINECOL (wfl_op2), TREE_TYPE (lvalue), nn);
}
/* If we're about to patch a NEW_ARRAY_INIT, we call a special
function to complete this RHS */
- if (TREE_CODE (wfl_op2) == NEW_ARRAY_INIT)
+ else if (TREE_CODE (wfl_op2) == NEW_ARRAY_INIT)
nn = patch_new_array_init (TREE_TYPE (TREE_OPERAND (node, 0)),
TREE_OPERAND (node, 1));
+ /* Otherwise we simply complete the RHS */
else
nn = java_complete_tree (TREE_OPERAND (node, 1));
- /* There are cases where the type of RHS is fixed. In those
- cases, if the evaluation of the RHS fails, we further the
- evaluation of the assignment to detect more errors. */
if (nn == error_mark_node)
- {
- /* It's hopeless, but we can further things on to discover
- an error during the assignment. In any cases, the
- assignment operation fails. */
- if (TREE_CODE (TREE_OPERAND (node, 1)) != EXPR_WITH_FILE_LOCATION
- && TREE_CODE (TREE_OPERAND (node, 1)) != NEW_ARRAY_INIT
- && TREE_TYPE (TREE_OPERAND (node, 1)) != error_mark_node)
- patch_assignment (node, wfl_op1, wfl_op2);
-
- /* Now, we still mark the lhs as initialized */
- if (DECL_P (TREE_OPERAND (node, 0)))
- INITIALIZED_P (TREE_OPERAND (node, 0)) = 1;
+ return error_mark_node;
- return error_mark_node;
- }
+ /* Write back the RHS as we evaluated it. */
TREE_OPERAND (node, 1) = nn;
/* In case we're handling = with a String as a RHS, we need to
CAN_COMPLETE_NORMALLY (node) = 1;
/* Don't complete string nodes if dealing with the PLUS operand. */
if (TREE_CODE (node) != PLUS_EXPR || !JSTRING_P (wfl_op1))
- {
- TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1);
- if (TREE_OPERAND (node, 0) == error_mark_node)
- return error_mark_node;
- }
+ {
+ nn = java_complete_tree (wfl_op1);
+ if (nn == error_mark_node)
+ return error_mark_node;
+ if ((cn = patch_string (nn)))
+ nn = cn;
+ TREE_OPERAND (node, 0) = nn;
+ }
if (TREE_CODE (node) != PLUS_EXPR || !JSTRING_P (wfl_op2))
- {
- TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2);
- if (TREE_OPERAND (node, 1) == error_mark_node)
- return error_mark_node;
- }
- return patch_binop (node, wfl_op1, wfl_op2);
+ {
+ nn = java_complete_tree (wfl_op2);
+ if (nn == error_mark_node)
+ return error_mark_node;
+ if ((cn = patch_string (nn)))
+ nn = cn;
+ TREE_OPERAND (node, 1) = nn;
+ }
+ return force_evaluation_order (patch_binop (node, wfl_op1, wfl_op2));
case INSTANCEOF_EXPR:
wfl_op1 = TREE_OPERAND (node, 0);
check_final_assignment (lvalue, wfl)
tree lvalue, wfl;
{
- if (DECL_P (lvalue) && FIELD_FINAL (lvalue) &&
+ if (JDECL_P (lvalue) && FIELD_FINAL (lvalue) &&
DECL_NAME (current_function_decl) != clinit_identifier_node)
{
parse_error_context
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
/* Lhs can be a named variable */
- if (DECL_P (lvalue))
+ if (JDECL_P (lvalue))
{
- INITIALIZED_P (lvalue) = 1;
lhs_type = TREE_TYPE (lvalue);
}
/* Or Lhs can be a array acccess. Should that be lvalue ? FIXME +
valid_builtin_assignconv_identity_widening_p (lhs_type, rhs_type)
tree lhs_type, rhs_type;
{
- int all_primitive;
-
+ /* 5.1.1: This is the identity conversion part. */
if (lhs_type == rhs_type)
return 1;
- /* Sometimes, instead of passing a type, we pass integer_zero_node
- so we know that an integral type can accomodate it */
- if (JINTEGRAL_TYPE_P (lhs_type) && (rhs_type == integer_zero_node))
- return 1;
-
- all_primitive =
- JPRIMITIVE_TYPE_P (lhs_type) && JPRIMITIVE_TYPE_P (rhs_type);
-
- if (!all_primitive)
+ /* Reject non primitive types */
+ if (!JPRIMITIVE_TYPE_P (lhs_type) || !JPRIMITIVE_TYPE_P (rhs_type))
return 0;
- /* byte, even if it's smaller than a char can't be converted into a
- char. Short can't too, but the < test below takes care of that */
+ /* 5.1.2: widening primitive conversion. byte, even if it's smaller
+ than a char can't be converted into a char. Short can't too, but
+ the < test below takes care of that */
if (lhs_type == char_type_node && rhs_type == byte_type_node)
return 0;
|| rhs_type == promoted_boolean_type_node))
return 1;
- if (JINTEGRAL_TYPE_P (rhs_type)
- && ((TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type))
- || (JFLOAT_TYPE_P (lhs_type) &&
- TYPE_PRECISION (rhs_type) == TYPE_PRECISION (lhs_type))))
- return 1;
- else if (JFLOAT_TYPE_P (rhs_type)
- && (TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type)))
+ /* From here, an integral is widened if its precision is smaller
+ than the precision of the LHS or if the LHS is a floating point
+ type, or the RHS is a float and the RHS a double. */
+ if ((JINTEGRAL_TYPE_P (rhs_type) && JINTEGRAL_TYPE_P (lhs_type)
+ && (TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type)))
+ || (JINTEGRAL_TYPE_P (rhs_type) && JFLOAT_TYPE_P (lhs_type))
+ || (rhs_type == float_type_node && lhs_type == double_type_node))
return 1;
return 0;
tree dest;
int cast;
{
+ /* SOURCE or DEST might be null if not from a declared entity. */
+ if (!source || !dest)
+ return 0;
if (JNULLP_TYPE_P (source))
return 1;
if (TREE_CODE (source) == POINTER_TYPE)
{
if (TYPE_CLASS_P (dest))
return dest == object_type_node;
+ /* Can't cast an array to an interface unless the interface is
+ java.lang.Cloneable */
if (TYPE_INTERFACE_P (dest))
- return 0; /* Install test on Clonable. FIXME */
+ return (DECL_NAME (TYPE_NAME (dest)) == java_lang_cloneable ? 1 : 0);
else /* Arrays */
{
tree source_element_type = TYPE_ARRAY_ELEMENT (source);
return arg;
}
+/* Return a non zero value if SOURCE can be converted into DEST using
+ the method invocation conversion rule (5.3). */
static int
valid_method_invocation_conversion_p (dest, source)
tree dest, source;
{
- return (((JPRIMITIVE_TYPE_P (source) || (source == integer_zero_node))
- && JPRIMITIVE_TYPE_P (dest)
- && valid_builtin_assignconv_identity_widening_p (dest, source))
- || ((JREFERENCE_TYPE_P (source) || JNULLP_TYPE_P (source))
- && (JREFERENCE_TYPE_P (dest) || JNULLP_TYPE_P (dest))
- && valid_ref_assignconv_cast_p (source, dest, 0)));
+ return ((JPRIMITIVE_TYPE_P (source) && JPRIMITIVE_TYPE_P (dest)
+ && valid_builtin_assignconv_identity_widening_p (dest, source))
+ || ((JREFERENCE_TYPE_P (source) || JNULLP_TYPE_P (source))
+ && (JREFERENCE_TYPE_P (dest) || JNULLP_TYPE_P (dest))
+ && valid_ref_assignconv_cast_p (source, dest, 0)));
}
/* Build an incomplete binop expression. */
/* Change the division operator if necessary */
if (code == RDIV_EXPR && TREE_CODE (prom_type) == INTEGER_TYPE)
TREE_SET_CODE (node, TRUNC_DIV_EXPR);
- /* This one is more complicated. FLOATs are processed by a function
- call to soft_fmod. */
+
+ /* This one is more complicated. FLOATs are processed by a
+ function call to soft_fmod. Duplicate the value of the
+ COMPOUND_ASSIGN_P flag. */
if (code == TRUNC_MOD_EXPR)
- return build_java_binop (TRUNC_MOD_EXPR, prom_type, op1, op2);
+ {
+ tree mod = build_java_binop (TRUNC_MOD_EXPR, prom_type, op1, op2);
+ COMPOUND_ASSIGN_P (mod) = COMPOUND_ASSIGN_P (node);
+ TREE_SIDE_EFFECTS (mod)
+ = TREE_SIDE_EFFECTS (op1) | TREE_SIDE_EFFECTS (op2);
+ return mod;
+ }
break;
/* 15.17 Additive Operators */
/* The >>> operator is a >> operating on unsigned quantities */
if (code == URSHIFT_EXPR && ! flag_emit_class_files)
{
- op1 = convert (unsigned_type (prom_type), op1);
+ tree to_return;
+ tree utype = unsigned_type (prom_type);
+ op1 = convert (utype, op1);
TREE_SET_CODE (node, RSHIFT_EXPR);
+ TREE_OPERAND (node, 0) = op1;
+ TREE_OPERAND (node, 1) = op2;
+ TREE_TYPE (node) = utype;
+ to_return = convert (prom_type, node);
+ /* Copy the original value of the COMPOUND_ASSIGN_P flag */
+ COMPOUND_ASSIGN_P (to_return) = COMPOUND_ASSIGN_P (node);
+ TREE_SIDE_EFFECTS (to_return)
+ = TREE_SIDE_EFFECTS (op1) | TREE_SIDE_EFFECTS (op2);
+ return to_return;
}
break;
else if (flag_emit_class_files)
{
TREE_OPERAND (node, 1) = op2_type;
+ TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (op1);
return node;
}
/* Otherwise we have to invoke instance of to figure it out */
build_tree_list (NULL_TREE,
build_class_ref (op2_type))),
NULL_TREE);
- TREE_SIDE_EFFECTS (call) = 1;
+ TREE_SIDE_EFFECTS (call) = TREE_SIDE_EFFECTS (op1);
return call;
}
}
TREE_OPERAND (node, 0) = op1;
TREE_OPERAND (node, 1) = op2;
TREE_TYPE (node) = prom_type;
+ TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (op1) | TREE_SIDE_EFFECTS (op2);
+
return fold (node);
}
tree op1, op2;
{
tree result;
+ int side_effects = TREE_SIDE_EFFECTS (op1) | TREE_SIDE_EFFECTS (op2);
+
/* Try to do some static optimization */
if ((result = string_constant_concatenation (op1, op2)))
return result;
- /* If operands are string constant, turn then into object references */
+ /* Discard empty strings on either side of the expression */
+ if (TREE_CODE (op1) == STRING_CST && TREE_STRING_LENGTH (op1) == 0)
+ {
+ op1 = op2;
+ op2 = NULL_TREE;
+ }
+ else if (TREE_CODE (op2) == STRING_CST && TREE_STRING_LENGTH (op2) == 0)
+ op2 = NULL_TREE;
+ /* If operands are string constant, turn then into object references */
if (TREE_CODE (op1) == STRING_CST)
op1 = patch_string_cst (op1);
- if (TREE_CODE (op2) == STRING_CST)
+ if (op2 && TREE_CODE (op2) == STRING_CST)
op2 = patch_string_cst (op2);
+ /* If either one of the constant is null and the other non null
+ operand is a String object, return it. */
+ if (JSTRING_TYPE_P (TREE_TYPE (op1)) && !op2)
+ return op1;
+
/* If OP1 isn't already a StringBuffer, create and
initialize a new one */
if (!IS_CRAFTED_STRING_BUFFER_P (op1))
{
/* Two solutions here:
1) OP1 is a string reference, we call new StringBuffer(OP1)
- 2) Op2 is something else, we call new StringBuffer().append(OP1). */
+ 2) OP1 is something else, we call new StringBuffer().append(OP1). */
if (JSTRING_TYPE_P (TREE_TYPE (op1)))
op1 = BUILD_STRING_BUFFER (op1);
else
}
}
- /* No longer the last node holding a crafted StringBuffer */
- IS_CRAFTED_STRING_BUFFER_P (op1) = 0;
- /* Create a node for `{new...,xxx}.append (op2)' */
- op1 = make_qualified_primary (op1, BUILD_APPEND (op2), 0);
+ if (op2)
+ {
+ /* OP1 is no longer the last node holding a crafted StringBuffer */
+ IS_CRAFTED_STRING_BUFFER_P (op1) = 0;
+ /* Create a node for `{new...,xxx}.append (op2)' */
+ if (op2)
+ op1 = make_qualified_primary (op1, BUILD_APPEND (op2), 0);
+ }
+
/* Mark the last node holding a crafted StringBuffer */
IS_CRAFTED_STRING_BUFFER_P (op1) = 1;
-
+
+ TREE_SIDE_EFFECTS (op1) = side_effects;
return op1;
}
{
tree op = TREE_OPERAND (node, 0);
tree op_type = TREE_TYPE (op);
- tree prom_type, value;
+ tree prom_type, value, decl;
int code = TREE_CODE (node);
int error_found = 0;
case PREINCREMENT_EXPR:
/* 15.14.2 Prefix Decrement Operator -- */
case PREDECREMENT_EXPR:
- if (!DECL_P (op) && !((TREE_CODE (op) == INDIRECT_REF
- || TREE_CODE (op) == COMPONENT_REF)
- && JPRIMITIVE_TYPE_P (TREE_TYPE (op))))
+ decl = strip_out_static_field_access_decl (op);
+ if (!JDECL_P (decl)
+ && !((TREE_CODE (decl) == INDIRECT_REF
+ || TREE_CODE (decl) == COMPONENT_REF)
+ && JPRIMITIVE_TYPE_P (TREE_TYPE (decl))))
{
tree lvalue;
/* Before screaming, check that we're not in fact trying to
error_found = 1;
}
else
- return fold (value);
+ {
+ value = fold (value);
+ TREE_SIDE_EFFECTS (value) = TREE_SIDE_EFFECTS (op);
+ return value;
+ }
break;
}
CONVERT_EXPR, {POST,PRE}{INCR,DECR}EMENT_EXPR. */
TREE_OPERAND (node, 0) = fold (op);
TREE_TYPE (node) = prom_type;
+ TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (op);
return fold (node);
}
if (cast_type == op_type)
return node;
+ /* float and double type are converted to the original type main
+ variant and then to the target type. */
+ if (JFLOAT_TYPE_P (op_type) && TREE_CODE (cast_type) == CHAR_TYPE)
+ op = convert (integer_type_node, op);
+
/* Try widening/narowwing convertion. Potentially, things need
to be worked out in gcc so we implement the extreme cases
correctly. fold_convert() needs to be fixed. */
return convert (cast_type, op);
}
+ /* It's also valid to cast a boolean into a boolean */
+ if (op_type == boolean_type_node && cast_type == boolean_type_node)
+ return node;
+
/* null can be casted to references */
if (op == null_pointer_node && JREFERENCE_TYPE_P (cast_type))
return build_null_of_type (cast_type);
/* The remaining legal casts involve conversion between reference
types. Check for their compile time correctness. */
if (JREFERENCE_TYPE_P (op_type) && JREFERENCE_TYPE_P (cast_type)
- && valid_ref_assignconv_cast_p (cast_type, op_type, 1))
+ && valid_ref_assignconv_cast_p (op_type, cast_type, 1))
{
TREE_TYPE (node) = promote_type (cast_type);
/* Now, the case can be determined correct at compile time if
TREE_OPERAND (node, 1) = index;
}
else
- node = build_java_arrayaccess (array, array_type, index);
+ {
+ /* The save_expr is for correct evaluation order. It would be cleaner
+ to use force_evaluation_order (see comment there), but that is
+ difficult when we also have to deal with bounds checking. */
+ if (TREE_SIDE_EFFECTS (index))
+ array = save_expr (array);
+ node = build_java_arrayaccess (array, array_type, index);
+ if (TREE_SIDE_EFFECTS (index))
+ node = build (COMPOUND_EXPR, array_type, array, node);
+ }
TREE_TYPE (node) = array_type;
return node;
}
{
tree constructor = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, values);
tree to_return = build1 (NEW_ARRAY_INIT, NULL_TREE, constructor);
- EXPR_WFL_LINECOL (to_return) = EXPR_WFL_LINECOL (constructor) = location;
+ EXPR_WFL_LINECOL (to_return) = location;
return to_return;
}
if (elt == NULL_TREE || TREE_CODE (elt) != NEW_ARRAY_INIT)
{
error_seen |= array_constructor_check_entry (element_type, current);
- if (! TREE_CONSTANT (TREE_VALUE (current)))
+ elt = TREE_VALUE (current);
+ /* When compiling to native code, STRING_CST is converted to
+ INDIRECT_REF, but still with a TREE_CONSTANT flag. */
+ if (! TREE_CONSTANT (elt) || TREE_CODE (elt) == INDIRECT_REF)
all_constant = 0;
}
else
COMPOUND_EXPR (loop main body)
EXIT_EXPR (this order is for while/for loops.
LABELED_BLOCK_EXPR the order is reversed for do loops)
- LABEL_DECL (continue occurding here branche at the
+ LABEL_DECL (a continue occuring here branches at the
BODY end of this labeled block)
INCREMENT (if any)
/* Find the statement we're targeting. */
target_stmt = LABELED_BLOCK_BODY (bc_label);
+ /* Target loop is slightly burrowed in the case of a for loop, it
+ appears at the first sight to be a block. */
+ if (TREE_CODE (target_stmt) == BLOCK)
+ {
+ tree sub = BLOCK_SUBBLOCKS (target_stmt);
+ if (sub && TREE_CODE (sub) == COMPOUND_EXPR && TREE_OPERAND (sub, 1)
+ && TREE_CODE (TREE_OPERAND (sub, 1)) == LOOP_EXPR)
+ target_stmt = TREE_OPERAND (sub, 1);
+ }
+
/* 14.13 The break Statement */
if (IS_BREAK_STMT_P (node))
{
while/do/for/switch */
if (is_unlabeled &&
!(TREE_CODE (target_stmt) == LOOP_EXPR /* do/while/for */
- || TREE_CODE (target_stmt) == SWITCH_EXPR)) /* switch FIXME */
+ || TREE_CODE (target_stmt) == SWITCH_EXPR)) /* switch */
{
parse_error_context (wfl_operator,
"`break' must be in loop or switch");
EXIT_BLOCK_LABELED_BLOCK (node) = bc_label;
}
/* 14.14 The continue Statement */
- /* The continue statement must always target a loop */
+ /* The continue statement must always target a loop, unnamed or not. */
else
- {
+ {
if (TREE_CODE (target_stmt) != LOOP_EXPR) /* do/while/for */
{
parse_error_context (wfl_operator, "`continue' must be in loop");
return error_mark_node;
}
/* Everything looks good. We can fix the `continue' jump to go
- at the place in the loop were the continue is. The continue
- is the current labeled block, by construction. */
- EXIT_BLOCK_LABELED_BLOCK (node) = bc_label = ctxp->current_labeled_block;
+ at the place in the loop were the continue is. For unlabeled
+ continue, the continuation point is the current labeled
+ block, by construction. */
+ if (is_unlabeled)
+ EXIT_BLOCK_LABELED_BLOCK (node) =
+ bc_label = ctxp->current_labeled_block;
}
CAN_COMPLETE_NORMALLY (bc_label) = 1;
/* 14.18 The try statement */
-/* Wrap BLOCK around a LABELED_BLOCK, set DECL to the newly generated
- exit labeld and issue a jump to FINALLY_LABEL:
-
- LABELED_BLOCK
- BLOCK
- <orignal_statments>
- DECL = &LABEL_DECL
- GOTO_EXPR
- FINALLY_LABEL
- LABEL_DECL */
-
static tree
-build_jump_to_finally (block, decl, finally_label, type)
- tree block, decl, finally_label, type;
+build_try_statement (location, try_block, catches)
+ int location;
+ tree try_block, catches;
{
- tree stmt;
- tree new_block = build (LABELED_BLOCK_EXPR, type,
- create_label_decl (generate_name ()), block);
-
- stmt = build (MODIFY_EXPR, void_type_node, decl,
- build_address_of (LABELED_BLOCK_LABEL (new_block)));
- TREE_SIDE_EFFECTS (stmt) = 1;
- CAN_COMPLETE_NORMALLY (stmt) = 1;
- add_stmt_to_block (block, type, stmt);
- stmt = build (GOTO_EXPR, void_type_node, finally_label);
- TREE_SIDE_EFFECTS (stmt) = 1;
- add_stmt_to_block (block, type, stmt);
- return new_block;
+ tree node = build (TRY_EXPR, NULL_TREE, try_block, catches);
+ EXPR_WFL_LINECOL (node) = location;
+ return node;
}
static tree
-build_try_statement (location, try_block, catches, finally)
+build_try_finally_statement (location, try_block, finally)
int location;
- tree try_block, catches, finally;
-{
- tree node, rff;
-
- if (finally && ! flag_emit_class_files)
- {
- /* This block defines a scope for the entire try[-catch]-finally
- sequence. It hold a local variable used to return from the
- finally using a computed goto. We call it
- return_from_finally (RFF). */
- rff = build_decl (VAR_DECL, generate_name (), return_address_type_node);
-
- /* Modification of the try block. */
- try_block = build_jump_to_finally (try_block, rff,
- FINALLY_EXPR_LABEL (finally),
- NULL_TREE);
-
- /* To the finally block: add the computed goto */
- add_stmt_to_block (FINALLY_EXPR_BLOCK (finally), NULL_TREE,
- build (GOTO_EXPR, void_type_node, rff));
-
- /* Modification of each catch blocks, if any */
- if (catches)
- {
- tree catch, catch_decl, catch_block, stmt;
-
- for (catch = catches; catch; catch = TREE_CHAIN (catch))
- TREE_OPERAND (catch, 0) =
- build_jump_to_finally (TREE_OPERAND (catch, 0), rff,
- FINALLY_EXPR_LABEL (finally),
- NULL_TREE);
-
- /* Plus, at the end of the list, we add the catch clause that
- will catch an uncaught exception, call finally and rethrow it:
- BLOCK
- void *exception_parameter; (catch_decl)
- LABELED_BLOCK
- BLOCK
- exception_parameter = _Jv_exception_info ();
- RFF = &LABEL_DECL;
- goto finally;
- LABEL_DECL;
- CALL_EXPR
- Jv_ReThrow
- exception_parameter */
- catch_decl = build_decl (VAR_DECL, generate_name (), ptr_type_node);
- BUILD_ASSIGN_EXCEPTION_INFO (stmt, catch_decl);
- catch_block = build_expr_block (stmt, NULL_TREE);
- catch_block = build_jump_to_finally (catch_block, rff,
- FINALLY_EXPR_LABEL (finally),
- void_type_node);
- BUILD_THROW (stmt, catch_decl);
- catch_block = build_expr_block (catch_block, catch_decl);
- add_stmt_to_block (catch_block, void_type_node, stmt);
-
- /* Link the new handler to the existing list as the first
- entry. It will be the last one to be generated. */
- catch = build1 (CATCH_EXPR, void_type_node, catch_block);
- TREE_CHAIN (catch) = catches;
- catches = catch;
- }
- }
-
- node = build (TRY_EXPR, NULL_TREE, try_block, catches, finally);
- EXPR_WFL_LINECOL (node) = location;
-
- /* If we have a finally, surround this whole thing by a block where
- the RFF local variable is defined. */
-
- return (finally && ! flag_emit_class_files ? build_expr_block (node, rff)
- : node);
-}
-
-/* Get the catch clause block from an element of the catch clause
- list. If depends on whether a finally clause exists or node (in
- which case the original catch clause was surrounded by a
- LABELED_BLOCK_EXPR. */
-
-tree
-java_get_catch_block (node, finally_present_p)
- tree node;
- int finally_present_p;
+ tree try_block, finally;
{
- return (CATCH_EXPR_GET_EXPR (TREE_OPERAND (node, 0), finally_present_p));
+ tree node = build (TRY_FINALLY_EXPR, NULL_TREE, try_block, finally);
+ EXPR_WFL_LINECOL (node) = location;
+ return node;
}
static tree
tree try = TREE_OPERAND (node, 0);
/* Exception handlers are considered in left to right order */
tree catch = nreverse (TREE_OPERAND (node, 1));
- tree finally = TREE_OPERAND (node, 2);
- int finally_p = (finally ? 1 : 0);
tree current, caught_type_list = NULL_TREE;
/* Check catch clauses, if any. Every time we find an error, we try
tree sub_current, catch_block, catch_clause;
int unreachable;
- /* Always detect the last catch clause if a finally is
- present. This is the catch-all handler and it just needs to
- be walked. */
- if (!TREE_CHAIN (current) && finally)
- {
- TREE_OPERAND (current, 0) =
- java_complete_tree (TREE_OPERAND (current, 0));
- continue;
- }
-
/* At this point, the structure of the catch clause is
- LABELED_BLOCK_EXPR (if we have a finally)
CATCH_EXPR (catch node)
BLOCK (with the decl of the parameter)
COMPOUND_EXPR
MODIFY_EXPR (assignment of the catch parameter)
BLOCK (catch clause block)
- LABEL_DECL (where to return after finally (if any))
-
- Since the structure of the catch clause depends on the
- presence of a finally, we use a function call to get to the
- cath clause */
- catch_clause = java_get_catch_block (current, finally_p);
+ */
+ catch_clause = TREE_OPERAND (current, 0);
carg_decl = BLOCK_EXPR_DECLS (catch_clause);
carg_type = TREE_TYPE (TREE_TYPE (carg_decl));
sub_current != current; sub_current = TREE_CHAIN (sub_current))
{
tree sub_catch_clause, decl;
- sub_catch_clause = java_get_catch_block (sub_current, finally_p);
+ sub_catch_clause = TREE_OPERAND (sub_current, 0);
decl = BLOCK_EXPR_DECLS (sub_catch_clause);
if (inherits_from_p (carg_type, TREE_TYPE (TREE_TYPE (decl))))
CAN_COMPLETE_NORMALLY (node) = 1;
POP_EXCEPTIONS ();
- /* Process finally */
- if (finally)
- {
- current = java_complete_tree (FINALLY_EXPR_BLOCK (finally));
- FINALLY_EXPR_BLOCK (finally) = current;
- if (current == error_mark_node)
- error_found = 1;
- if (! CAN_COMPLETE_NORMALLY (current))
- CAN_COMPLETE_NORMALLY (node) = 0;
- }
-
/* Verification ends here */
if (error_found)
return error_mark_node;
TREE_OPERAND (node, 0) = try;
TREE_OPERAND (node, 1) = catch;
- TREE_OPERAND (node, 2) = finally;
TREE_TYPE (node) = void_type_node;
return node;
}
tree expr = java_complete_tree (TREE_OPERAND (node, 0));
tree block = TREE_OPERAND (node, 1);
- tree enter, exit, finally, expr_decl;
+ tree enter, exit, expr_decl, assignment;
if (expr == error_mark_node)
{
BUILD_MONITOR_EXIT (exit, expr_decl);
CAN_COMPLETE_NORMALLY (enter) = 1;
CAN_COMPLETE_NORMALLY (exit) = 1;
+ assignment = build (MODIFY_EXPR, NULL_TREE, expr_decl, expr);
+ TREE_SIDE_EFFECTS (assignment) = 1;
node = build1 (CLEANUP_POINT_EXPR, NULL_TREE,
build (COMPOUND_EXPR, NULL_TREE,
build (WITH_CLEANUP_EXPR, NULL_TREE,
build (COMPOUND_EXPR, NULL_TREE,
- build (MODIFY_EXPR, NULL_TREE,
- expr_decl, expr),
- enter),
+ assignment, enter),
NULL_TREE, exit),
block));
node = build_expr_block (node, expr_decl);