decl.c (runtime_exception_type_node, [...]): New global variables.
Tue Oct 13 03:50:28 1998 Alexandre Petit-Bianco <apbianco@cygnus.com> * decl.c (runtime_exception_type_node, error_exception_type_node): New global variables. (init_decl_processing): Initialized. * expr.c (java_lang_expand_expr): Set caught exception type to null if catch handler argument doesn't exit. * java-tree.def (SYNCHRONIZED_EXPR, THROW_EXPR): New Java specific tree codes. * java-tree.h (runtime_exception_type_node, error_exception_type_node): Global variables declared. (DECL_FUNCTION_THROWS): New macro. (DECL_FUNCTION_BODY): Modified comment. (DECL_SPECIFIC_COUNT): Likewise. (struct lang_decl): New field throws_list. (IS_UNCHECKED_EXPRESSION_P): New macro. * lex.c (java_lex): Generate location information for THROW_TK. * parse.h (PUSH_EXCEPTIONS, POP_EXCEPTIONS, IN_TRY_BLOCK_P, EXCEPTIONS_P): New macros. (enum jdep_code): New value JDEP_EXCEPTION. (BUILD_MONITOR_ENTER, BUILD_MONITOR_EXIT, BUILD_ASSIGN_EXCEPTION_INFO, BUILD_THROW, SET_WFL_OPERATOR, PATCH_METHOD_RETURN_ERROR): New macros. (patch_method_invocation_stmt): Added new argument to prototype. (patch_synchronized_statement, patch_throw_statement, check_thrown_exceptions, check_thrown_exceptions_do, purge_unchecked_exceptions, check_throws_clauses): New function prototypes. * parse.y Fixed typo in keyword section. (throw:): Rule tagged <node>. (THROW_TK): Keyword tagged <operator>. (method_header:): Last argument to call to method_header passed from throws: rule. (throws:, class_type_list:, throw_statement:, synchronized_statement:, synchronized:): Defined actions. (method_header): New local variable current. Register exceptions from throws clause. (java_complete_tree): Complete and verify exceptions from throws clause. (complete_class_report_errors): Error message on exceptions not found (java_check_regular_methods): Fixed typo. Shortcut on private overriding methods. Changed error message on method redefinition. Check for throws clause compatibility. (check_throws_clauses): New function. (java_check_abstract_methods): Use DECL_NAME for wfl or current method. Changed error message on method redefinition. (currently_caught_type_list): New static variable. (java_complete_expand_methods): Purge unchecked exceptions from throws clause list. Call PUSH_EXCEPTIONS before walk and POP_EXCEPTIONS after. (resolve_qualified_expression_name): Pass new argument as NULL to patch_method_invocation_stmt. (patch_method_invocation_stmt): New argument ref_decl. Invoke PATCH_METHOD_RETURN_ERROR when returning with error. Reverse argument list when appropriate. Use new argument if non null to store selected method decl. (patch_invoke): Convert if necessary args of builtin types before forming CALL_EXPR. Argument list no longer reversed here. (invocation_mode): Treat final methods as static methods. (java_complete_tree): New cases for THROW_EXPR: and SYNCHRONIZED_EXPR:. Check thrown exceptions when completing function call. (complete_function_arguments): No more RECORD_TYPE conversion. Function parameter nodes no longer saved. (valid_ref_assignconv_cast_p): Avoid handling null type. (patch_binop): Fixed null constant reference handling. (build_try_statement): Use BUILD_ASSIGN_EXCEPTION_INFO and BUILD_THROW macros. (patch_try_statement): Fixed comments. Record caught types in list, push the list, expand try block and pop the list. (patch_synchronized_statement, patch_throw_statement, check_thrown_exceptions, check_thrown_exceptions_do, purge_unchecked_exceptions): New functions. * typeck.c (lookup_argument_method): Allow WFL in place of method DECL_NAME during method definition check Implements the `synchronized' statement, the `throw' statements and the `throws' clause. Fixes method invocation bugs. From-SVN: r23087
This commit is contained in:
parent
8e30605ec7
commit
b9f7e36ca1
@ -47,6 +47,83 @@ Tue Oct 13 23:34:12 1998 Jeffrey A Law (law@cygnus.com)
|
|||||||
(disassemble_method): Undefine RET to avoid clash with
|
(disassemble_method): Undefine RET to avoid clash with
|
||||||
config/i386/i386.h.
|
config/i386/i386.h.
|
||||||
|
|
||||||
|
Tue Oct 13 03:50:28 1998 Alexandre Petit-Bianco <apbianco@cygnus.com>
|
||||||
|
|
||||||
|
* decl.c (runtime_exception_type_node, error_exception_type_node):
|
||||||
|
New global variables.
|
||||||
|
(init_decl_processing): Initialized.
|
||||||
|
* expr.c (java_lang_expand_expr): Set caught exception type to
|
||||||
|
null if catch handler argument doesn't exit.
|
||||||
|
* java-tree.def (SYNCHRONIZED_EXPR, THROW_EXPR): New Java specific
|
||||||
|
tree codes.
|
||||||
|
* java-tree.h (runtime_exception_type_node,
|
||||||
|
error_exception_type_node): Global variables declared.
|
||||||
|
(DECL_FUNCTION_THROWS): New macro.
|
||||||
|
(DECL_FUNCTION_BODY): Modified comment.
|
||||||
|
(DECL_SPECIFIC_COUNT): Likewise.
|
||||||
|
(struct lang_decl): New field throws_list.
|
||||||
|
(IS_UNCHECKED_EXPRESSION_P): New macro.
|
||||||
|
* lex.c (java_lex): Generate location information for THROW_TK.
|
||||||
|
* parse.h (PUSH_EXCEPTIONS, POP_EXCEPTIONS, IN_TRY_BLOCK_P,
|
||||||
|
EXCEPTIONS_P): New macros.
|
||||||
|
(enum jdep_code): New value JDEP_EXCEPTION.
|
||||||
|
(BUILD_MONITOR_ENTER, BUILD_MONITOR_EXIT,
|
||||||
|
BUILD_ASSIGN_EXCEPTION_INFO, BUILD_THROW, SET_WFL_OPERATOR,
|
||||||
|
PATCH_METHOD_RETURN_ERROR): New macros.
|
||||||
|
(patch_method_invocation_stmt): Added new argument to prototype.
|
||||||
|
(patch_synchronized_statement, patch_throw_statement,
|
||||||
|
check_thrown_exceptions, check_thrown_exceptions_do,
|
||||||
|
purge_unchecked_exceptions, check_throws_clauses): New function
|
||||||
|
prototypes.
|
||||||
|
* parse.y Fixed typo in keyword section.
|
||||||
|
(throw:): Rule tagged <node>.
|
||||||
|
(THROW_TK): Keyword tagged <operator>.
|
||||||
|
(method_header:): Last argument to call to method_header passed
|
||||||
|
from throws: rule.
|
||||||
|
(throws:, class_type_list:, throw_statement:,
|
||||||
|
synchronized_statement:, synchronized:): Defined actions.
|
||||||
|
(method_header): New local variable current. Register exceptions
|
||||||
|
from throws clause.
|
||||||
|
(java_complete_tree): Complete and verify exceptions from throws
|
||||||
|
clause.
|
||||||
|
(complete_class_report_errors): Error message on exceptions not
|
||||||
|
found
|
||||||
|
(java_check_regular_methods): Fixed typo. Shortcut on private
|
||||||
|
overriding methods. Changed error message on method
|
||||||
|
redefinition. Check for throws clause compatibility.
|
||||||
|
(check_throws_clauses): New function.
|
||||||
|
(java_check_abstract_methods): Use DECL_NAME for wfl or current
|
||||||
|
method. Changed error message on method redefinition.
|
||||||
|
(currently_caught_type_list): New static variable.
|
||||||
|
(java_complete_expand_methods): Purge unchecked exceptions from
|
||||||
|
throws clause list. Call PUSH_EXCEPTIONS before walk and
|
||||||
|
POP_EXCEPTIONS after.
|
||||||
|
(resolve_qualified_expression_name): Pass new argument as NULL to
|
||||||
|
patch_method_invocation_stmt.
|
||||||
|
(patch_method_invocation_stmt): New argument ref_decl. Invoke
|
||||||
|
PATCH_METHOD_RETURN_ERROR when returning with error. Reverse
|
||||||
|
argument list when appropriate. Use new argument if non null to
|
||||||
|
store selected method decl.
|
||||||
|
(patch_invoke): Convert if necessary args of builtin types before
|
||||||
|
forming CALL_EXPR. Argument list no longer reversed here.
|
||||||
|
(invocation_mode): Treat final methods as static methods.
|
||||||
|
(java_complete_tree): New cases for THROW_EXPR: and
|
||||||
|
SYNCHRONIZED_EXPR:. Check thrown exceptions when completing
|
||||||
|
function call.
|
||||||
|
(complete_function_arguments): No more RECORD_TYPE
|
||||||
|
conversion. Function parameter nodes no longer saved.
|
||||||
|
(valid_ref_assignconv_cast_p): Avoid handling null type.
|
||||||
|
(patch_binop): Fixed null constant reference handling.
|
||||||
|
(build_try_statement): Use BUILD_ASSIGN_EXCEPTION_INFO and
|
||||||
|
BUILD_THROW macros.
|
||||||
|
(patch_try_statement): Fixed comments. Record caught types in
|
||||||
|
list, push the list, expand try block and pop the list.
|
||||||
|
(patch_synchronized_statement, patch_throw_statement,
|
||||||
|
check_thrown_exceptions, check_thrown_exceptions_do,
|
||||||
|
purge_unchecked_exceptions): New functions.
|
||||||
|
* typeck.c (lookup_argument_method): Allow WFL in place of method
|
||||||
|
DECL_NAME during method definition check
|
||||||
|
|
||||||
1998-10-09 Tom Tromey <tromey@cygnus.com>
|
1998-10-09 Tom Tromey <tromey@cygnus.com>
|
||||||
|
|
||||||
* gjavah.c (decode_signature_piece): New function.
|
* gjavah.c (decode_signature_piece): New function.
|
||||||
|
@ -250,6 +250,8 @@ tree object_type_node;
|
|||||||
tree object_ptr_type_node;
|
tree object_ptr_type_node;
|
||||||
tree string_type_node;
|
tree string_type_node;
|
||||||
tree throwable_type_node;
|
tree throwable_type_node;
|
||||||
|
tree runtime_exception_type_node;
|
||||||
|
tree error_exception_type_node;
|
||||||
|
|
||||||
tree boolean_type_node;
|
tree boolean_type_node;
|
||||||
|
|
||||||
@ -518,6 +520,10 @@ init_decl_processing ()
|
|||||||
string_type_node = lookup_class (get_identifier ("java.lang.String"));
|
string_type_node = lookup_class (get_identifier ("java.lang.String"));
|
||||||
class_type_node = lookup_class (get_identifier ("java.lang.Class"));
|
class_type_node = lookup_class (get_identifier ("java.lang.Class"));
|
||||||
throwable_type_node = lookup_class (get_identifier ("java.lang.Throwable"));
|
throwable_type_node = lookup_class (get_identifier ("java.lang.Throwable"));
|
||||||
|
runtime_exception_type_node =
|
||||||
|
lookup_class (get_identifier ("java.lang.RuntimeException"));
|
||||||
|
error_exception_type_node =
|
||||||
|
lookup_class (get_identifier ("java.lang.Error"));
|
||||||
|
|
||||||
methodtable_type = make_node (RECORD_TYPE);
|
methodtable_type = make_node (RECORD_TYPE);
|
||||||
layout_type (methodtable_type);
|
layout_type (methodtable_type);
|
||||||
|
@ -1750,7 +1750,7 @@ java_lang_expand_expr (exp, target, tmode, modifier)
|
|||||||
{
|
{
|
||||||
tree catch = java_get_catch_block (current, has_finally_p);
|
tree catch = java_get_catch_block (current, has_finally_p);
|
||||||
tree decl = BLOCK_EXPR_DECLS (catch);
|
tree decl = BLOCK_EXPR_DECLS (catch);
|
||||||
type = TREE_TYPE (TREE_TYPE (decl));
|
type = (decl ? TREE_TYPE (TREE_TYPE (decl)) : NULL_TREE);
|
||||||
}
|
}
|
||||||
start_catch_handler (prepare_eh_table_type (type));
|
start_catch_handler (prepare_eh_table_type (type));
|
||||||
expand_expr_stmt (TREE_OPERAND (current, 0));
|
expand_expr_stmt (TREE_OPERAND (current, 0));
|
||||||
@ -1772,7 +1772,8 @@ java_lang_expand_expr (exp, target, tmode, modifier)
|
|||||||
if (has_finally_p)
|
if (has_finally_p)
|
||||||
{
|
{
|
||||||
tree finally = TREE_OPERAND (exp, 2);
|
tree finally = TREE_OPERAND (exp, 2);
|
||||||
emit_label (label_rtx (FINALLY_EXPR_LABEL (finally)));
|
if (FINALLY_EXPR_LABEL (finally))
|
||||||
|
emit_label (label_rtx (FINALLY_EXPR_LABEL (finally)));
|
||||||
expand_expr_stmt (FINALLY_EXPR_BLOCK (finally));
|
expand_expr_stmt (FINALLY_EXPR_BLOCK (finally));
|
||||||
}
|
}
|
||||||
expand_end_all_catch ();
|
expand_end_all_catch ();
|
||||||
|
@ -55,3 +55,12 @@ DEFTREECODE (CATCH_EXPR, "catch", '1', 1)
|
|||||||
Operand 0 is the finally label.
|
Operand 0 is the finally label.
|
||||||
Operand 1 is the finally block. */
|
Operand 1 is the finally block. */
|
||||||
DEFTREECODE (FINALLY_EXPR, "finally", 'e', 2)
|
DEFTREECODE (FINALLY_EXPR, "finally", 'e', 2)
|
||||||
|
|
||||||
|
/* Synchronized statement.
|
||||||
|
Operand 0 is the expression on which we whish to synchronize,
|
||||||
|
Operand 1 is the synchronized expression block. */
|
||||||
|
DEFTREECODE (SYNCHRONIZED_EXPR, "synchronized", 'e', 2)
|
||||||
|
|
||||||
|
/* Throw statement.
|
||||||
|
Operand 0 is the throw expresion. */
|
||||||
|
DEFTREECODE (THROW_EXPR, "throw", '1', 1)
|
||||||
|
@ -175,6 +175,8 @@ extern tree object_type_node;
|
|||||||
extern tree object_ptr_type_node;
|
extern tree object_ptr_type_node;
|
||||||
extern tree string_type_node;
|
extern tree string_type_node;
|
||||||
extern tree throwable_type_node;
|
extern tree throwable_type_node;
|
||||||
|
extern tree runtime_exception_type_node;
|
||||||
|
extern tree error_exception_type_node;
|
||||||
|
|
||||||
extern tree byte_array_type_node;
|
extern tree byte_array_type_node;
|
||||||
extern tree short_array_type_node;
|
extern tree short_array_type_node;
|
||||||
@ -317,8 +319,14 @@ struct lang_identifier
|
|||||||
#define DECL_MAX_STACK(DECL) (DECL_LANG_SPECIFIC(DECL)->max_stack)
|
#define DECL_MAX_STACK(DECL) (DECL_LANG_SPECIFIC(DECL)->max_stack)
|
||||||
/* Number of local variable slots needed for the arguments of this function. */
|
/* Number of local variable slots needed for the arguments of this function. */
|
||||||
#define DECL_ARG_SLOT_COUNT(DECL) (DECL_LANG_SPECIFIC(DECL)->arg_slot_count)
|
#define DECL_ARG_SLOT_COUNT(DECL) (DECL_LANG_SPECIFIC(DECL)->arg_slot_count)
|
||||||
/* Pointer to the function's COMPOUND_EXPR tree */
|
/* List of checked thrown exceptions, as specified with the `throws'
|
||||||
|
keyword */
|
||||||
|
#define DECL_FUNCTION_THROWS(DECL) (DECL_LANG_SPECIFIC(DECL)->throws_list)
|
||||||
|
/* Pointer to the function's current's COMPOUND_EXPR tree (while
|
||||||
|
completing its body) or the function's block */
|
||||||
#define DECL_FUNCTION_BODY(DECL) (DECL_LANG_SPECIFIC(DECL)->function_decl_body)
|
#define DECL_FUNCTION_BODY(DECL) (DECL_LANG_SPECIFIC(DECL)->function_decl_body)
|
||||||
|
/* How specific the function is (for method selection - Java source
|
||||||
|
code front-end */
|
||||||
#define DECL_SPECIFIC_COUNT(DECL) DECL_ARG_SLOT_COUNT(DECL)
|
#define DECL_SPECIFIC_COUNT(DECL) DECL_ARG_SLOT_COUNT(DECL)
|
||||||
|
|
||||||
/* In a LABEL_DECL, a TREE_VEC that saves the type_map at that point. */
|
/* In a LABEL_DECL, a TREE_VEC that saves the type_map at that point. */
|
||||||
@ -391,6 +399,7 @@ struct lang_decl
|
|||||||
long localvariables_offset;
|
long localvariables_offset;
|
||||||
int arg_slots;
|
int arg_slots;
|
||||||
int max_locals, max_stack, arg_slot_count;
|
int max_locals, max_stack, arg_slot_count;
|
||||||
|
tree throws_list; /* Exception specified by `throws' */
|
||||||
tree function_decl_body; /* Hold all function's statements */
|
tree function_decl_body; /* Hold all function's statements */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -726,3 +735,8 @@ extern tree *type_map;
|
|||||||
|
|
||||||
/* Using a CATCH_EXPR node */
|
/* Using a CATCH_EXPR node */
|
||||||
#define CATCH_EXPR_GET_EXPR(NODE, V) (V ? LABELED_BLOCK_BODY (NODE) : (NODE))
|
#define CATCH_EXPR_GET_EXPR(NODE, V) (V ? LABELED_BLOCK_BODY (NODE) : (NODE))
|
||||||
|
|
||||||
|
/* Non zero if TYPE is an unchecked expression */
|
||||||
|
#define IS_UNCHECKED_EXPRESSION_P(TYPE) \
|
||||||
|
(inherits_from_p ((TYPE), runtime_exception_type_node) \
|
||||||
|
|| inherits_from_p ((TYPE), error_exception_type_node))
|
||||||
|
@ -1209,6 +1209,7 @@ java_lex (java_lval)
|
|||||||
case CONTINUE_TK:
|
case CONTINUE_TK:
|
||||||
case TRY_TK:
|
case TRY_TK:
|
||||||
case CATCH_TK:
|
case CATCH_TK:
|
||||||
|
case THROW_TK:
|
||||||
BUILD_OPERATOR (kw->token);
|
BUILD_OPERATOR (kw->token);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -262,6 +262,24 @@ extern tree stabilize_reference PROTO ((tree));
|
|||||||
}
|
}
|
||||||
#define POP_LOOP() ctxp->current_loop = TREE_CHAIN (ctxp->current_loop)
|
#define POP_LOOP() ctxp->current_loop = TREE_CHAIN (ctxp->current_loop)
|
||||||
|
|
||||||
|
#define PUSH_EXCEPTIONS(E) \
|
||||||
|
currently_caught_type_list = \
|
||||||
|
tree_cons (NULL_TREE, (E), currently_caught_type_list);
|
||||||
|
|
||||||
|
#define POP_EXCEPTIONS() \
|
||||||
|
currently_caught_type_list = TREE_CHAIN (currently_caught_type_list)
|
||||||
|
|
||||||
|
/* Check that we're inside a try block */
|
||||||
|
#define IN_TRY_BLOCK_P() \
|
||||||
|
(currently_caught_type_list \
|
||||||
|
&& ((TREE_VALUE (currently_caught_type_list) != \
|
||||||
|
DECL_FUNCTION_THROWS (current_function_decl)) \
|
||||||
|
|| TREE_CHAIN (currently_caught_type_list)))
|
||||||
|
|
||||||
|
/* Check that we have exceptions in E */
|
||||||
|
#define EXCEPTIONS_P(E) ((E) ? TREE_VALUE (E) : NULL_TREE)
|
||||||
|
|
||||||
|
|
||||||
/* Invocation modes, as returned by invocation_mode (). */
|
/* Invocation modes, as returned by invocation_mode (). */
|
||||||
enum {
|
enum {
|
||||||
INVOKE_STATIC,
|
INVOKE_STATIC,
|
||||||
@ -317,6 +335,7 @@ enum jdep_code {
|
|||||||
JDEP_TYPE, /* Patch a random tree node type,
|
JDEP_TYPE, /* Patch a random tree node type,
|
||||||
without the need for any specific
|
without the need for any specific
|
||||||
actions */
|
actions */
|
||||||
|
JDEP_EXCEPTION, /* Patch exceptions specified by `throws' */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _jdep {
|
typedef struct _jdep {
|
||||||
@ -431,6 +450,51 @@ static jdeplist *reverse_jdep_list ();
|
|||||||
build_new_invocation (wfl_string_buffer, \
|
build_new_invocation (wfl_string_buffer, \
|
||||||
(ARG ? build_tree_list (NULL, (ARG)) : NULL_TREE))
|
(ARG ? build_tree_list (NULL, (ARG)) : NULL_TREE))
|
||||||
|
|
||||||
|
/* For exception handling, build diverse function calls */
|
||||||
|
#define BUILD_MONITOR_ENTER(WHERE, ARG) \
|
||||||
|
{ \
|
||||||
|
(WHERE) = build (CALL_EXPR, int_type_node, \
|
||||||
|
build_address_of (soft_monitorenter_node), \
|
||||||
|
build_tree_list (NULL_TREE, (ARG))); \
|
||||||
|
TREE_SIDE_EFFECTS (WHERE) = 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BUILD_MONITOR_EXIT(WHERE, ARG) \
|
||||||
|
{ \
|
||||||
|
(WHERE) = build (CALL_EXPR, int_type_node, \
|
||||||
|
build_address_of (soft_monitorexit_node), \
|
||||||
|
build_tree_list (NULL_TREE, (ARG))); \
|
||||||
|
TREE_SIDE_EFFECTS (WHERE) = 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BUILD_ASSIGN_EXCEPTION_INFO(WHERE, TO) \
|
||||||
|
{ \
|
||||||
|
(WHERE) = build (MODIFY_EXPR, void_type_node, (TO), \
|
||||||
|
soft_exceptioninfo_call_node); \
|
||||||
|
TREE_SIDE_EFFECTS (WHERE) = 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BUILD_THROW(WHERE, WHAT) \
|
||||||
|
{ \
|
||||||
|
(WHERE) = build (CALL_EXPR, void_type_node, \
|
||||||
|
build_address_of (throw_node), \
|
||||||
|
build_tree_list (NULL_TREE, (WHAT)), NULL_TREE); \
|
||||||
|
TREE_SIDE_EFFECTS ((WHERE)) = 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set wfl_operator for the most accurate error location */
|
||||||
|
#define SET_WFL_OPERATOR(WHICH, NODE, WFL) \
|
||||||
|
EXPR_WFL_LINECOL (WHICH) = \
|
||||||
|
(TREE_CODE (WFL) == EXPR_WITH_FILE_LOCATION ? \
|
||||||
|
EXPR_WFL_LINECOL (WFL) : EXPR_WFL_LINECOL (NODE))
|
||||||
|
|
||||||
|
#define PATCH_METHOD_RETURN_ERROR() \
|
||||||
|
{ \
|
||||||
|
if (ret_decl) \
|
||||||
|
*ret_decl = NULL_TREE; \
|
||||||
|
return error_mark_node; \
|
||||||
|
}
|
||||||
|
|
||||||
/* Parser context data structure. */
|
/* Parser context data structure. */
|
||||||
struct parser_ctxt {
|
struct parser_ctxt {
|
||||||
|
|
||||||
@ -527,7 +591,7 @@ static tree lookup_java_interface_method2 PROTO ((tree, tree));
|
|||||||
static tree resolve_expression_name PROTO ((tree));
|
static tree resolve_expression_name PROTO ((tree));
|
||||||
static tree maybe_create_class_interface_decl PROTO ((tree, tree, tree));
|
static tree maybe_create_class_interface_decl PROTO ((tree, tree, tree));
|
||||||
static int check_class_interface_creation PROTO ((int, int, tree, tree, tree, tree));
|
static int check_class_interface_creation PROTO ((int, int, tree, tree, tree, tree));
|
||||||
static tree patch_method_invocation_stmt PROTO ((tree, tree, tree, int *));
|
static tree patch_method_invocation_stmt PROTO ((tree, tree, tree, int *, tree *));
|
||||||
static int breakdown_qualified PROTO ((tree *, tree *, tree));
|
static int breakdown_qualified PROTO ((tree *, tree *, tree));
|
||||||
static tree resolve_and_layout PROTO ((tree, tree));
|
static tree resolve_and_layout PROTO ((tree, tree));
|
||||||
static tree resolve_no_layout PROTO ((tree, tree));
|
static tree resolve_no_layout PROTO ((tree, tree));
|
||||||
@ -613,6 +677,12 @@ static tree patch_string PROTO ((tree));
|
|||||||
static tree build_jump_to_finally PROTO ((tree, tree, tree, 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, tree));
|
||||||
static tree patch_try_statement PROTO ((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 void check_thrown_exceptions PROTO ((int, tree));
|
||||||
|
static int check_thrown_exceptions_do PROTO ((int, tree));
|
||||||
|
static void purge_unchecked_exceptions PROTO ((tree));
|
||||||
|
static void check_throws_clauses PROTO ((tree, tree, tree));
|
||||||
|
|
||||||
void safe_layout_class PROTO ((tree));
|
void safe_layout_class PROTO ((tree));
|
||||||
void java_complete_class PROTO ((void));
|
void java_complete_class PROTO ((void));
|
||||||
|
507
gcc/java/parse.y
507
gcc/java/parse.y
@ -195,7 +195,7 @@ static tree wfl_to_string = NULL_TREE;
|
|||||||
%type <node> class_body_declarations
|
%type <node> class_body_declarations
|
||||||
%type <node> class_or_interface_type class_type class_type_list
|
%type <node> class_or_interface_type class_type class_type_list
|
||||||
constructor_declarator explicit_constructor_invocation
|
constructor_declarator explicit_constructor_invocation
|
||||||
%type <node> dim_expr dim_exprs this_or_super
|
%type <node> dim_expr dim_exprs this_or_super throws
|
||||||
|
|
||||||
%type <node> variable_declarator_id variable_declarator
|
%type <node> variable_declarator_id variable_declarator
|
||||||
variable_declarators variable_initializer
|
variable_declarators variable_initializer
|
||||||
@ -245,8 +245,9 @@ static tree wfl_to_string = NULL_TREE;
|
|||||||
%token <operator> BOOL_AND_TK AND_TK BOOL_OR_TK OR_TK INCR_TK PLUS_TK
|
%token <operator> BOOL_AND_TK AND_TK BOOL_OR_TK OR_TK INCR_TK PLUS_TK
|
||||||
%token <operator> DECR_TK MINUS_TK MULT_TK DIV_TK XOR_TK REM_TK NEQ_TK
|
%token <operator> DECR_TK MINUS_TK MULT_TK DIV_TK XOR_TK REM_TK NEQ_TK
|
||||||
%token <operator> NEG_TK REL_QM_TK REL_CL_TK NOT_TK LT_TK
|
%token <operator> NEG_TK REL_QM_TK REL_CL_TK NOT_TK LT_TK
|
||||||
%token <operator> OP_TK OSB_TK DOT_TK
|
%token <operator> OP_TK OSB_TK DOT_TK THROW_TK
|
||||||
%type <operator> THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK CASE_TK%type <operator> DEFAULT_TK TRY_TK CATCH_TK
|
%type <operator> THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK
|
||||||
|
%type <operator> CASE_TK DEFAULT_TK TRY_TK CATCH_TK SYNCHRONIZED_TK
|
||||||
|
|
||||||
%type <node> method_body
|
%type <node> method_body
|
||||||
|
|
||||||
@ -661,13 +662,13 @@ method_declaration:
|
|||||||
|
|
||||||
method_header:
|
method_header:
|
||||||
type method_declarator throws
|
type method_declarator throws
|
||||||
{ $$ = method_header (0, $1, $2, NULL); }
|
{ $$ = method_header (0, $1, $2, $3); }
|
||||||
| VOID_TK method_declarator throws
|
| VOID_TK method_declarator throws
|
||||||
{ $$ = method_header (0, void_type_node, $2, NULL); }
|
{ $$ = method_header (0, void_type_node, $2, $3); }
|
||||||
| modifiers type method_declarator throws
|
| modifiers type method_declarator throws
|
||||||
{ $$ = method_header ($1, $2, $3, NULL); }
|
{ $$ = method_header ($1, $2, $3, $4); }
|
||||||
| modifiers VOID_TK method_declarator throws
|
| modifiers VOID_TK method_declarator throws
|
||||||
{ $$ = method_header ($1, void_type_node, $3, NULL); }
|
{ $$ = method_header ($1, void_type_node, $3, $4); }
|
||||||
| type error
|
| type error
|
||||||
{RECOVER;}
|
{RECOVER;}
|
||||||
| modifiers type error
|
| modifiers type error
|
||||||
@ -730,14 +731,18 @@ formal_parameter:
|
|||||||
;
|
;
|
||||||
|
|
||||||
throws:
|
throws:
|
||||||
|
{ $$ = NULL_TREE; }
|
||||||
| THROWS_TK class_type_list
|
| THROWS_TK class_type_list
|
||||||
|
{ $$ = $2; }
|
||||||
| THROWS_TK error
|
| THROWS_TK error
|
||||||
{yyerror ("Missing class type term"); RECOVER;}
|
{yyerror ("Missing class type term"); RECOVER;}
|
||||||
;
|
;
|
||||||
|
|
||||||
class_type_list:
|
class_type_list:
|
||||||
class_type
|
class_type
|
||||||
|
{ $$ = build_tree_list (NULL_TREE, $1); }
|
||||||
| class_type_list C_TK class_type
|
| class_type_list C_TK class_type
|
||||||
|
{ $$ = tree_cons (NULL_TREE, $3, $1); }
|
||||||
| class_type_list C_TK error
|
| class_type_list C_TK error
|
||||||
{yyerror ("Missing class type term"); RECOVER;}
|
{yyerror ("Missing class type term"); RECOVER;}
|
||||||
;
|
;
|
||||||
@ -1395,7 +1400,10 @@ return_statement:
|
|||||||
|
|
||||||
throw_statement:
|
throw_statement:
|
||||||
THROW_TK expression SC_TK
|
THROW_TK expression SC_TK
|
||||||
{ $$ = NULL_TREE; /* FIXME */ }
|
{
|
||||||
|
$$ = build1 (THROW_EXPR, NULL_TREE, $2);
|
||||||
|
EXPR_WFL_LINECOL ($$) = $1.location;
|
||||||
|
}
|
||||||
| THROW_TK error
|
| THROW_TK error
|
||||||
{yyerror ("Missing term"); RECOVER;}
|
{yyerror ("Missing term"); RECOVER;}
|
||||||
| THROW_TK expression error
|
| THROW_TK expression error
|
||||||
@ -1404,7 +1412,11 @@ throw_statement:
|
|||||||
|
|
||||||
synchronized_statement:
|
synchronized_statement:
|
||||||
synchronized OP_TK expression CP_TK block
|
synchronized OP_TK expression CP_TK block
|
||||||
{ $$ = NULL_TREE; /* FIXME */ }
|
{
|
||||||
|
$$ = build (SYNCHRONIZED_EXPR, NULL_TREE, $3, $5);
|
||||||
|
EXPR_WFL_LINECOL ($$) =
|
||||||
|
EXPR_WFL_LINECOL (MODIFIER_WFL (SYNCHRONIZED_TK));
|
||||||
|
}
|
||||||
| synchronized OP_TK expression CP_TK error
|
| synchronized OP_TK expression CP_TK error
|
||||||
{yyerror ("'{' expected"); RECOVER;}
|
{yyerror ("'{' expected"); RECOVER;}
|
||||||
| synchronized error
|
| synchronized error
|
||||||
@ -1415,10 +1427,11 @@ synchronized_statement:
|
|||||||
{yyerror ("Missing term"); RECOVER;}
|
{yyerror ("Missing term"); RECOVER;}
|
||||||
;
|
;
|
||||||
|
|
||||||
synchronized: /* Test lval.sub_token here */
|
synchronized:
|
||||||
MODIFIER_TK
|
MODIFIER_TK
|
||||||
{
|
{
|
||||||
SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1));
|
if ((1 << $1) != ACC_SYNCHRONIZED)
|
||||||
|
fatal ("synchronized was '%d' - yyparse", (1 << $1));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -2852,7 +2865,7 @@ method_header (flags, type, mdecl, throws)
|
|||||||
tree id = TREE_PURPOSE (mdecl);
|
tree id = TREE_PURPOSE (mdecl);
|
||||||
tree this_class = TREE_TYPE (ctxp->current_parsed_class);
|
tree this_class = TREE_TYPE (ctxp->current_parsed_class);
|
||||||
tree handle_class = CLASS_TO_HANDLE_TYPE (this_class);
|
tree handle_class = CLASS_TO_HANDLE_TYPE (this_class);
|
||||||
tree meth_name, returned_type;
|
tree meth_name, returned_type, current;
|
||||||
int saved_lineno;
|
int saved_lineno;
|
||||||
|
|
||||||
check_modifiers_consistency (flags);
|
check_modifiers_consistency (flags);
|
||||||
@ -2957,6 +2970,24 @@ method_header (flags, type, mdecl, throws)
|
|||||||
}
|
}
|
||||||
DECL_MAX_LOCALS (meth) = ctxp->formal_parameter_number+1;
|
DECL_MAX_LOCALS (meth) = ctxp->formal_parameter_number+1;
|
||||||
lineno = saved_lineno;
|
lineno = saved_lineno;
|
||||||
|
|
||||||
|
/* Register exception specified by the `throws' keyword for
|
||||||
|
resolution and set the method decl appropriate field to the list.
|
||||||
|
Note: the grammar ensures that what we get here are class
|
||||||
|
types. */
|
||||||
|
if (throws)
|
||||||
|
{
|
||||||
|
throws = nreverse (throws);
|
||||||
|
for (current = throws; current; current = TREE_CHAIN (current))
|
||||||
|
{
|
||||||
|
register_incomplete_type (JDEP_EXCEPTION, TREE_VALUE (current),
|
||||||
|
NULL_TREE, NULL_TREE);
|
||||||
|
JDEP_GET_PATCH (CLASSD_LAST (ctxp->classd_list)) =
|
||||||
|
&TREE_VALUE (current);
|
||||||
|
}
|
||||||
|
DECL_FUNCTION_THROWS (meth) = throws;
|
||||||
|
}
|
||||||
|
|
||||||
/* We set the DECL_NAME to ID so we can track the location where
|
/* We set the DECL_NAME to ID so we can track the location where
|
||||||
the function was declared. This allow us to report
|
the function was declared. This allow us to report
|
||||||
redefinition error accurately. When method are verified,
|
redefinition error accurately. When method are verified,
|
||||||
@ -3456,6 +3487,24 @@ java_complete_class ()
|
|||||||
tree_code_name [TREE_CODE (JDEP_DECL (dep))]));
|
tree_code_name [TREE_CODE (JDEP_DECL (dep))]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case JDEP_EXCEPTION:
|
||||||
|
/* Check for righteous inheritance here */
|
||||||
|
if (!inherits_from_p (TREE_TYPE (decl), throwable_type_node))
|
||||||
|
{
|
||||||
|
parse_error_context
|
||||||
|
(JDEP_WFL (dep), "Class `%s' in `throws' clause must be "
|
||||||
|
"a subclass of class `java.lang.Throwable'",
|
||||||
|
IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JDEP_APPLY_PATCH (dep, TREE_TYPE (decl));
|
||||||
|
SOURCE_FRONTEND_DEBUG
|
||||||
|
(("Completing `%s' `throws' argument node",
|
||||||
|
IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep)))));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fatal ("incomplete switch - java_complete_class");
|
fatal ("incomplete switch - java_complete_class");
|
||||||
}
|
}
|
||||||
@ -3664,6 +3713,11 @@ complete_class_report_errors (dep)
|
|||||||
(EXPR_WFL_NODE (JDEP_WFL (dep)))),
|
(EXPR_WFL_NODE (JDEP_WFL (dep)))),
|
||||||
IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep))));
|
IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep))));
|
||||||
break;
|
break;
|
||||||
|
case JDEP_EXCEPTION: /* As specified by `throws' */
|
||||||
|
parse_error_context
|
||||||
|
(JDEP_WFL (dep), "Class `%s' not found in `throws'",
|
||||||
|
IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3731,7 +3785,7 @@ java_check_regular_methods (class_decl)
|
|||||||
tree method_wfl = DECL_NAME (method);
|
tree method_wfl = DECL_NAME (method);
|
||||||
int aflags;
|
int aflags;
|
||||||
|
|
||||||
if (DECL_CONSTRUCTOR_P (method))
|
if (DECL_CONSTRUCTOR_P (method))
|
||||||
seen_constructor = 1;
|
seen_constructor = 1;
|
||||||
|
|
||||||
/* Check for redefinitions */
|
/* Check for redefinitions */
|
||||||
@ -3741,16 +3795,24 @@ java_check_regular_methods (class_decl)
|
|||||||
sig = build_java_argument_signature (TREE_TYPE (method));
|
sig = build_java_argument_signature (TREE_TYPE (method));
|
||||||
|
|
||||||
found = lookup_argument_method (super_class, DECL_NAME (method), sig);
|
found = lookup_argument_method (super_class, DECL_NAME (method), sig);
|
||||||
if (! found)
|
|
||||||
|
/* Nothing overrides or it's a private method */
|
||||||
|
if (!found || (found && METHOD_PRIVATE (found)))
|
||||||
continue;
|
continue;
|
||||||
/* Can't override a method with the same name and different return
|
/* Can't override a method with the same name and different return
|
||||||
types. */
|
types. */
|
||||||
if (TREE_TYPE (TREE_TYPE (found)) != TREE_TYPE (TREE_TYPE (method)))
|
if (TREE_TYPE (TREE_TYPE (found)) != TREE_TYPE (TREE_TYPE (method)))
|
||||||
parse_warning_context
|
{
|
||||||
(method_wfl,
|
char *t = strdup ((char *)lang_printable_name (TREE_TYPE
|
||||||
"Method `%s' redefined with different return type in class `%s'",
|
(TREE_TYPE (found))));
|
||||||
lang_printable_name (found),
|
parse_error_context
|
||||||
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
|
(method_wfl,
|
||||||
|
"Method `%s' was defined with return type `%s' in class `%s'",
|
||||||
|
lang_printable_name (found), t,
|
||||||
|
IDENTIFIER_POINTER
|
||||||
|
(DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
|
||||||
|
free (t);
|
||||||
|
}
|
||||||
|
|
||||||
/* Can't override final. Can't override static. */
|
/* Can't override final. Can't override static. */
|
||||||
if (METHOD_FINAL (found) || METHOD_STATIC (found))
|
if (METHOD_FINAL (found) || METHOD_STATIC (found))
|
||||||
@ -3796,9 +3858,13 @@ java_check_regular_methods (class_decl)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overriding methods must have compatible `throws' clauses on checked
|
||||||
|
exceptions, if any */
|
||||||
|
check_throws_clauses (method, method_wfl, found);
|
||||||
|
|
||||||
/* If the method has default access in an other package, then
|
/* If the method has default access in an other package, then
|
||||||
issue a warning that the current method doesn't override the one
|
issue a warning that the current method doesn't override the
|
||||||
that was found elsewhere */
|
one that was found elsewhere */
|
||||||
aflags = get_access_flags_from_decl (found);
|
aflags = get_access_flags_from_decl (found);
|
||||||
if ((!aflags || (aflags > ACC_PROTECTED))
|
if ((!aflags || (aflags > ACC_PROTECTED))
|
||||||
&& !class_in_current_package (DECL_CONTEXT (found)))
|
&& !class_in_current_package (DECL_CONTEXT (found)))
|
||||||
@ -3832,6 +3898,40 @@ java_check_regular_methods (class_decl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a non zero value if the `throws' clause of METHOD (if any)
|
||||||
|
is incompatible with the `throws' clause of FOUND (if any). */
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_throws_clauses (method, method_wfl, found)
|
||||||
|
tree method, method_wfl, found;
|
||||||
|
{
|
||||||
|
tree mthrows, fthrows;
|
||||||
|
|
||||||
|
for (mthrows = DECL_FUNCTION_THROWS (method);
|
||||||
|
mthrows; mthrows = TREE_CHAIN (mthrows))
|
||||||
|
{
|
||||||
|
/* We don't verify unchecked expressions */
|
||||||
|
if (IS_UNCHECKED_EXPRESSION_P (TREE_VALUE (mthrows)))
|
||||||
|
continue;
|
||||||
|
/* Checked expression must be compatible */
|
||||||
|
for (fthrows = DECL_FUNCTION_THROWS (found);
|
||||||
|
fthrows; fthrows = TREE_CHAIN (fthrows))
|
||||||
|
if (inherits_from_p (TREE_VALUE (mthrows), TREE_VALUE (fthrows)))
|
||||||
|
break;
|
||||||
|
if (!fthrows)
|
||||||
|
{
|
||||||
|
parse_error_context
|
||||||
|
(method_wfl, "Invalid checked exception class `%s' in "
|
||||||
|
"`throws' clause. The exception must be a subclass of an "
|
||||||
|
"exception thrown by `%s' from class `%s'",
|
||||||
|
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (TREE_VALUE (mthrows)))),
|
||||||
|
lang_printable_name (found),
|
||||||
|
IDENTIFIER_POINTER
|
||||||
|
(DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check abstract method of interface INTERFACE */
|
/* Check abstract method of interface INTERFACE */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -3844,24 +3944,26 @@ java_check_abstract_methods (interface)
|
|||||||
for (method = TYPE_METHODS (interface); method; method = TREE_CHAIN (method))
|
for (method = TYPE_METHODS (interface); method; method = TREE_CHAIN (method))
|
||||||
{
|
{
|
||||||
char *csig;
|
char *csig;
|
||||||
tree name = DECL_NAME (method);
|
tree method_wfl = DECL_NAME (method);
|
||||||
|
|
||||||
/* 2- Check for double definition inside the defining interface */
|
/* 2- Check for double definition inside the defining interface */
|
||||||
if (check_method_redefinition (interface, method))
|
if (check_method_redefinition (interface, method))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* 3- Overriding is OK as far as we preserve the return type and
|
/* 3- Overriding is OK as far as we preserve the return type and
|
||||||
the thrown exceptions */
|
the thrown exceptions (FIXME) */
|
||||||
found = lookup_java_interface_method2 (interface, method);
|
found = lookup_java_interface_method2 (interface, method);
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
|
char *t = strdup ((char *)lang_printable_name (TREE_TYPE
|
||||||
|
(TREE_TYPE (found))));
|
||||||
parse_error_context
|
parse_error_context
|
||||||
(lookup_cl (method),
|
(method_wfl,
|
||||||
"Method `%s' previously defined in interface `%s' is "
|
"Method `%s' was defined with return type `%s' in class `%s ",
|
||||||
"redefined with different return type in interface `%s'",
|
lang_printable_name (found), t,
|
||||||
lang_printable_name (found),
|
IDENTIFIER_POINTER
|
||||||
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))),
|
(DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
|
||||||
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (interface))));
|
free (t);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4659,6 +4761,10 @@ java_complete_expand_methods ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hold a list of catch clauses list. The first element of this list is
|
||||||
|
the list of the catch clauses of the currently analysed try block. */
|
||||||
|
static tree currently_caught_type_list;
|
||||||
|
|
||||||
/* Complete and expand a method. */
|
/* Complete and expand a method. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -4720,12 +4826,23 @@ java_complete_expand_method (mdecl)
|
|||||||
= (!METHOD_STATIC (mdecl) ?
|
= (!METHOD_STATIC (mdecl) ?
|
||||||
BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE);
|
BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE);
|
||||||
|
|
||||||
|
/* Purge the `throws' list of unchecked exceptions */
|
||||||
|
purge_unchecked_exceptions (mdecl);
|
||||||
|
|
||||||
|
/* Install exceptions thrown with `throws' */
|
||||||
|
PUSH_EXCEPTIONS (DECL_FUNCTION_THROWS (mdecl));
|
||||||
|
|
||||||
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) && no_ac_found)
|
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) && no_ac_found)
|
||||||
java_complete_tree (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)));
|
java_complete_tree (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)));
|
||||||
/* Don't go any further if we've found error(s) during the
|
/* Don't go any further if we've found error(s) during the
|
||||||
expansion */
|
expansion */
|
||||||
if (!java_error_count)
|
if (!java_error_count)
|
||||||
source_end_java_method ();
|
source_end_java_method ();
|
||||||
|
|
||||||
|
/* Pop the exceptions and sanity check */
|
||||||
|
POP_EXCEPTIONS();
|
||||||
|
if (currently_caught_type_list)
|
||||||
|
fatal ("Exception list non empty - java_complete_expand_method");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5007,7 +5124,8 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
|
|||||||
if (complete_function_arguments (qual_wfl))
|
if (complete_function_arguments (qual_wfl))
|
||||||
return 1;
|
return 1;
|
||||||
*where_found =
|
*where_found =
|
||||||
patch_method_invocation_stmt (qual_wfl, decl, type, &is_static);
|
patch_method_invocation_stmt (qual_wfl, decl, type,
|
||||||
|
&is_static, NULL);
|
||||||
if (*where_found == error_mark_node)
|
if (*where_found == error_mark_node)
|
||||||
return 1;
|
return 1;
|
||||||
*type_found = type = QUAL_DECL_TYPE (*where_found);
|
*type_found = type = QUAL_DECL_TYPE (*where_found);
|
||||||
@ -5352,9 +5470,10 @@ maybe_access_field (decl, where, type)
|
|||||||
used. IS_STATIC is set to 1 if the invoked function is static. */
|
used. IS_STATIC is set to 1 if the invoked function is static. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
patch_method_invocation_stmt (patch, primary, where, is_static)
|
patch_method_invocation_stmt (patch, primary, where, is_static, ret_decl)
|
||||||
tree patch, primary, where;
|
tree patch, primary, where;
|
||||||
int *is_static;
|
int *is_static;
|
||||||
|
tree *ret_decl;
|
||||||
{
|
{
|
||||||
tree wfl = TREE_OPERAND (patch, 0);
|
tree wfl = TREE_OPERAND (patch, 0);
|
||||||
tree args = TREE_OPERAND (patch, 1);
|
tree args = TREE_OPERAND (patch, 1);
|
||||||
@ -5396,7 +5515,7 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
parse_error_context (wfl, "Can't search method `%s' in package "
|
parse_error_context (wfl, "Can't search method `%s' in package "
|
||||||
"`%s'",IDENTIFIER_POINTER (identifier),
|
"`%s'",IDENTIFIER_POINTER (identifier),
|
||||||
IDENTIFIER_POINTER (remainder));
|
IDENTIFIER_POINTER (remainder));
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
}
|
}
|
||||||
/* We're resolving a call from a type */
|
/* We're resolving a call from a type */
|
||||||
else if (RESOLVE_TYPE_NAME_P (wfl))
|
else if (RESOLVE_TYPE_NAME_P (wfl))
|
||||||
@ -5412,7 +5531,7 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
(identifier_wfl, "Can't make static reference to method "
|
(identifier_wfl, "Can't make static reference to method "
|
||||||
"`%s' in interface `%s'", IDENTIFIER_POINTER (identifier),
|
"`%s' in interface `%s'", IDENTIFIER_POINTER (identifier),
|
||||||
IDENTIFIER_POINTER (name));
|
IDENTIFIER_POINTER (name));
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
}
|
}
|
||||||
/* Look the method up in the type selector. The method ought
|
/* Look the method up in the type selector. The method ought
|
||||||
to be static. */
|
to be static. */
|
||||||
@ -5427,7 +5546,7 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
lang_printable_name (TREE_TYPE (TREE_TYPE (list))), fct_name,
|
lang_printable_name (TREE_TYPE (TREE_TYPE (list))), fct_name,
|
||||||
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
|
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
|
||||||
free (fct_name);
|
free (fct_name);
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* We're resolving an expression name */
|
/* We're resolving an expression name */
|
||||||
@ -5438,7 +5557,7 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
/* 1- Find the field to which the call applies */
|
/* 1- Find the field to which the call applies */
|
||||||
field = resolve_field_access (wfl, NULL, &type);
|
field = resolve_field_access (wfl, NULL, &type);
|
||||||
if (field == error_mark_node)
|
if (field == error_mark_node)
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
|
|
||||||
/* 2- Do the layout of the class where the last field
|
/* 2- Do the layout of the class where the last field
|
||||||
was found, so we can search it. */
|
was found, so we can search it. */
|
||||||
@ -5451,7 +5570,7 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
identifier, args);
|
identifier, args);
|
||||||
|
|
||||||
/* 4- Add the field as an argument */
|
/* 4- Add the field as an argument */
|
||||||
args = tree_cons (NULL_TREE, field, args);
|
args = tree_cons (NULL_TREE, field, nreverse (args));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CLASS_TYPE is used during the call to not_accessible_p and
|
/* CLASS_TYPE is used during the call to not_accessible_p and
|
||||||
@ -5475,7 +5594,7 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
parse_error_context
|
parse_error_context
|
||||||
(wfl, "Class `%s' not found in type declaration",
|
(wfl, "Class `%s' not found in type declaration",
|
||||||
IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
|
IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Can't instantiate an abstract class */
|
/* Can't instantiate an abstract class */
|
||||||
@ -5484,7 +5603,7 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
parse_error_context
|
parse_error_context
|
||||||
(wfl, "Class `%s' is an abstract class. It can't be "
|
(wfl, "Class `%s' is an abstract class. It can't be "
|
||||||
"instantiated", IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
|
"instantiated", IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
}
|
}
|
||||||
class_to_search = TREE_TYPE (class_to_search);
|
class_to_search = TREE_TYPE (class_to_search);
|
||||||
lc = 1;
|
lc = 1;
|
||||||
@ -5504,16 +5623,18 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
|
|
||||||
/* Don't continue if no method were found, as the next statement
|
/* Don't continue if no method were found, as the next statement
|
||||||
can't be executed then. */
|
can't be executed then. */
|
||||||
if (!list) return error_mark_node;
|
if (!list)
|
||||||
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
|
|
||||||
/* Check for static reference if non static methods */
|
/* Check for static reference if non static methods */
|
||||||
if (check_for_static_method_reference (wfl, patch, list,
|
if (check_for_static_method_reference (wfl, patch, list,
|
||||||
class_to_search, primary))
|
class_to_search, primary))
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
|
|
||||||
/* Non static/constructor methods are called with the current
|
/* Non static/constructor methods are called with the current
|
||||||
object extra argument. If method is resolved as a primary,
|
object extra argument. If method is resolved as a primary,
|
||||||
use the primary otherwise use the current THIS. */
|
use the primary otherwise use the current THIS. */
|
||||||
|
args = nreverse (args);
|
||||||
if (!CALL_CONSTRUCTOR_P (patch) && !METHOD_STATIC (list))
|
if (!CALL_CONSTRUCTOR_P (patch) && !METHOD_STATIC (list))
|
||||||
args = tree_cons (NULL_TREE, primary ? primary : current_this, args);
|
args = tree_cons (NULL_TREE, primary ? primary : current_this, args);
|
||||||
|
|
||||||
@ -5522,7 +5643,8 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
|
|
||||||
/* Merge point of all resolution schemes. If we have nothing, this
|
/* Merge point of all resolution schemes. If we have nothing, this
|
||||||
is an error, already signaled */
|
is an error, already signaled */
|
||||||
if (!list) return error_mark_node;
|
if (!list)
|
||||||
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
|
|
||||||
/* Check accessibility, position the is_static flag, build and
|
/* Check accessibility, position the is_static flag, build and
|
||||||
return the call */
|
return the call */
|
||||||
@ -5536,12 +5658,16 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
|
|||||||
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class_type))), fct_name,
|
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class_type))), fct_name,
|
||||||
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))));
|
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))));
|
||||||
free (fct_name);
|
free (fct_name);
|
||||||
return error_mark_node;
|
PATCH_METHOD_RETURN_ERROR ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_static)
|
if (is_static)
|
||||||
*is_static = METHOD_STATIC (list);
|
*is_static = METHOD_STATIC (list);
|
||||||
java_parser_context_restore_global ();
|
java_parser_context_restore_global ();
|
||||||
|
/* Sometimes, we want the decl of the selected method. Such as for
|
||||||
|
EH checking */
|
||||||
|
if (ret_decl)
|
||||||
|
*ret_decl = list;
|
||||||
return patch_invoke (patch, list, args, wfl);
|
return patch_invoke (patch, list, args, wfl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5574,21 +5700,28 @@ patch_invoke (patch, method, args, cl)
|
|||||||
tree patch, method, args;
|
tree patch, method, args;
|
||||||
tree cl;
|
tree cl;
|
||||||
{
|
{
|
||||||
|
int im;
|
||||||
tree dtable, func;
|
tree dtable, func;
|
||||||
tree signature = build_java_signature (TREE_TYPE (method));
|
tree signature = build_java_signature (TREE_TYPE (method));
|
||||||
tree original_call;
|
tree original_call, node, t, ta;
|
||||||
|
|
||||||
switch (invocation_mode (method, 0))
|
/* Last step for args: convert build-in types */
|
||||||
|
for (t = TYPE_ARG_TYPES (TREE_TYPE (method)),
|
||||||
|
ta = args; t && ta; t = TREE_CHAIN (t), ta = TREE_CHAIN (ta))
|
||||||
|
if (JPRIMITIVE_TYPE_P (TREE_TYPE (TREE_VALUE (ta))) &&
|
||||||
|
TREE_TYPE (TREE_VALUE (ta)) != TREE_VALUE (t))
|
||||||
|
TREE_VALUE (ta) = convert (TREE_VALUE (t), TREE_VALUE (ta));
|
||||||
|
|
||||||
|
switch ((im = invocation_mode (method, 0)))
|
||||||
{
|
{
|
||||||
case INVOKE_VIRTUAL:
|
case INVOKE_VIRTUAL:
|
||||||
dtable = invoke_build_dtable (0, args);
|
dtable = invoke_build_dtable (0, args);
|
||||||
func = build_invokevirtual (dtable, method);
|
func = build_invokevirtual (dtable, method);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INVOKE_STATIC:
|
case INVOKE_STATIC:
|
||||||
func = build_known_method_ref (method, TREE_TYPE (method),
|
func = build_known_method_ref (method, TREE_TYPE (method),
|
||||||
DECL_CONTEXT (method),
|
DECL_CONTEXT (method), signature, args);
|
||||||
signature, args);
|
|
||||||
args = nreverse (args);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -5596,7 +5729,6 @@ patch_invoke (patch, method, args, cl)
|
|||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Ensure self_type is initialized, (invokestatic). FIXME */
|
/* Ensure self_type is initialized, (invokestatic). FIXME */
|
||||||
func = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (method)), func);
|
func = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (method)), func);
|
||||||
TREE_TYPE (patch) = TREE_TYPE (TREE_TYPE (method));
|
TREE_TYPE (patch) = TREE_TYPE (TREE_TYPE (method));
|
||||||
@ -5638,7 +5770,7 @@ invocation_mode (method, super)
|
|||||||
{
|
{
|
||||||
int access = get_access_flags_from_decl (method);
|
int access = get_access_flags_from_decl (method);
|
||||||
|
|
||||||
if (access & ACC_STATIC)
|
if (access & ACC_STATIC || access & ACC_FINAL)
|
||||||
return INVOKE_STATIC;
|
return INVOKE_STATIC;
|
||||||
|
|
||||||
if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method))))
|
if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method))))
|
||||||
@ -6113,6 +6245,17 @@ java_complete_tree (node)
|
|||||||
|
|
||||||
/* 2- They are expressions but ultimately deal with statements */
|
/* 2- They are expressions but ultimately deal with statements */
|
||||||
|
|
||||||
|
case THROW_EXPR:
|
||||||
|
wfl_op1 = TREE_OPERAND (node, 0);
|
||||||
|
COMPLETE_CHECK_OP_0 (node);
|
||||||
|
return patch_throw_statement (node, wfl_op1);
|
||||||
|
|
||||||
|
case SYNCHRONIZED_EXPR:
|
||||||
|
wfl_op1 = TREE_OPERAND (node, 0);
|
||||||
|
COMPLETE_CHECK_OP_0 (node);
|
||||||
|
COMPLETE_CHECK_OP_1 (node);
|
||||||
|
return patch_synchronized_statement (node, wfl_op1);
|
||||||
|
|
||||||
case TRY_EXPR:
|
case TRY_EXPR:
|
||||||
return patch_try_statement (node);
|
return patch_try_statement (node);
|
||||||
|
|
||||||
@ -6219,7 +6362,7 @@ java_complete_tree (node)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TREE_VALUE (cn) = save_expr (dim);
|
TREE_VALUE (cn) = dim;
|
||||||
/* Setup the location of the current dimension, for
|
/* Setup the location of the current dimension, for
|
||||||
later error report. */
|
later error report. */
|
||||||
TREE_PURPOSE (cn) =
|
TREE_PURPOSE (cn) =
|
||||||
@ -6237,7 +6380,14 @@ java_complete_tree (node)
|
|||||||
if (complete_function_arguments (node))
|
if (complete_function_arguments (node))
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
else
|
else
|
||||||
return patch_method_invocation_stmt (node, NULL_TREE, NULL_TREE, NULL);
|
{
|
||||||
|
tree decl;
|
||||||
|
node = patch_method_invocation_stmt (node, NULL_TREE,
|
||||||
|
NULL_TREE, 0, &decl);
|
||||||
|
if (node != error_mark_node)
|
||||||
|
check_thrown_exceptions (EXPR_WFL_LINECOL (node), decl);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
case MODIFY_EXPR:
|
case MODIFY_EXPR:
|
||||||
/* Save potential wfls */
|
/* Save potential wfls */
|
||||||
@ -6407,12 +6557,9 @@ complete_function_arguments (node)
|
|||||||
crafted string buffer, as a result of use of the the String
|
crafted string buffer, as a result of use of the the String
|
||||||
`+' operator. Build `parm.toString()' and expand it. */
|
`+' operator. Build `parm.toString()' and expand it. */
|
||||||
if ((temp = patch_string (parm)))
|
if ((temp = patch_string (parm)))
|
||||||
parm = TREE_VALUE (cn) = temp;
|
parm = temp;
|
||||||
|
TREE_VALUE (cn) = parm;
|
||||||
if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE)
|
|
||||||
TREE_VALUE (cn) = convert (promote_type (TREE_TYPE (parm)), parm);
|
|
||||||
else
|
|
||||||
TREE_VALUE (cn) = save_expr (parm);
|
|
||||||
if (not_initialized_as_it_should_p (parm))
|
if (not_initialized_as_it_should_p (parm))
|
||||||
{
|
{
|
||||||
ERROR_VARIABLE_NOT_INITIALIZED (wfl, EXPR_WFL_NODE (wfl));
|
ERROR_VARIABLE_NOT_INITIALIZED (wfl, EXPR_WFL_NODE (wfl));
|
||||||
@ -6943,6 +7090,9 @@ valid_ref_assignconv_cast_p (source, dest, cast)
|
|||||||
tree source_element_type = TYPE_ARRAY_ELEMENT (source);
|
tree source_element_type = TYPE_ARRAY_ELEMENT (source);
|
||||||
tree dest_element_type = TYPE_ARRAY_ELEMENT (dest);
|
tree dest_element_type = TYPE_ARRAY_ELEMENT (dest);
|
||||||
|
|
||||||
|
/* In case of severe errors, they turn out null */
|
||||||
|
if (!dest_element_type || !source_element_type)
|
||||||
|
return 0;
|
||||||
if (source_element_type == dest_element_type)
|
if (source_element_type == dest_element_type)
|
||||||
return 1;
|
return 1;
|
||||||
return valid_ref_assignconv_cast_p (source_element_type,
|
return valid_ref_assignconv_cast_p (source_element_type,
|
||||||
@ -7289,12 +7439,9 @@ patch_binop (node, wfl_op1, wfl_op2)
|
|||||||
|
|
||||||
/* 15.20.3 Reference Equality Operators == and != */
|
/* 15.20.3 Reference Equality Operators == and != */
|
||||||
/* Types have to be either references or the null type */
|
/* Types have to be either references or the null type */
|
||||||
else if ((op1 == null_pointer_node || op2 == null_pointer_node
|
else if (op1 == null_pointer_node || op2 == null_pointer_node
|
||||||
|| JREFERENCE_TYPE_P (op1_type)
|
|| (JREFERENCE_TYPE_P (op1_type) && JREFERENCE_TYPE_P (op2_type)
|
||||||
|| JREFERENCE_TYPE_P (op2_type))
|
&& ((op1_type == op2_type))))
|
||||||
&& ((op1_type == op2_type)
|
|
||||||
/* There should use a valid_cast_to_p() */
|
|
||||||
))
|
|
||||||
; /* Nothing to do here */
|
; /* Nothing to do here */
|
||||||
|
|
||||||
/* Else we have an error figure what can't be converted into
|
/* Else we have an error figure what can't be converted into
|
||||||
@ -8768,18 +8915,13 @@ build_try_statement (location, try_block, catches, finally)
|
|||||||
exception_parameter */
|
exception_parameter */
|
||||||
catch_decl = build_decl_no_layout (VAR_DECL, generate_name (),
|
catch_decl = build_decl_no_layout (VAR_DECL, generate_name (),
|
||||||
ptr_type_node);
|
ptr_type_node);
|
||||||
stmt = build (MODIFY_EXPR, void_type_node, catch_decl,
|
BUILD_ASSIGN_EXCEPTION_INFO (stmt, catch_decl);
|
||||||
soft_exceptioninfo_call_node);
|
|
||||||
TREE_SIDE_EFFECTS (stmt) = 1;
|
|
||||||
catch_block = build_expr_block (stmt, NULL_TREE);
|
catch_block = build_expr_block (stmt, NULL_TREE);
|
||||||
catch_block = build_jump_to_finally (catch_block, rff,
|
catch_block = build_jump_to_finally (catch_block, rff,
|
||||||
FINALLY_EXPR_LABEL (finally),
|
FINALLY_EXPR_LABEL (finally),
|
||||||
void_type_node);
|
void_type_node);
|
||||||
stmt = build (CALL_EXPR, void_type_node,
|
BUILD_THROW (stmt, catch_decl);
|
||||||
build_address_of (throw_node),
|
|
||||||
build_tree_list (NULL_TREE, catch_decl), NULL_TREE);
|
|
||||||
catch_block = build_expr_block (catch_block, catch_decl);
|
catch_block = build_expr_block (catch_block, catch_decl);
|
||||||
TREE_SIDE_EFFECTS (stmt) = 1;
|
|
||||||
add_stmt_to_block (catch_block, void_type_node, stmt);
|
add_stmt_to_block (catch_block, void_type_node, stmt);
|
||||||
|
|
||||||
/* Link the new handler to the existing list as the first
|
/* Link the new handler to the existing list as the first
|
||||||
@ -8822,14 +8964,12 @@ patch_try_statement (node)
|
|||||||
tree catch = nreverse (TREE_OPERAND (node, 1));
|
tree catch = nreverse (TREE_OPERAND (node, 1));
|
||||||
tree finally = TREE_OPERAND (node, 2);
|
tree finally = TREE_OPERAND (node, 2);
|
||||||
int finally_p = (finally ? 1 : 0);
|
int finally_p = (finally ? 1 : 0);
|
||||||
tree current;
|
tree current, caught_type_list = NULL_TREE;
|
||||||
|
|
||||||
/* Walk the try block */
|
|
||||||
if ((try = java_complete_tree (try)) == error_mark_node)
|
|
||||||
error_found = 1;
|
|
||||||
|
|
||||||
/* Check catch clauses, if any. Every time we find an error, we try
|
/* Check catch clauses, if any. Every time we find an error, we try
|
||||||
to process the next catch clause. */
|
to process the next catch clause. We process the catch clause before
|
||||||
|
the try block so that when processing the try block we can check thrown
|
||||||
|
exceptions againts the caught type list. */
|
||||||
for (current = catch; current; current = TREE_CHAIN (current))
|
for (current = catch; current; current = TREE_CHAIN (current))
|
||||||
{
|
{
|
||||||
tree carg_decl, carg_type;
|
tree carg_decl, carg_type;
|
||||||
@ -8908,6 +9048,11 @@ patch_try_statement (node)
|
|||||||
if (unreachable)
|
if (unreachable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Things to do here: the exception must be thrown */
|
||||||
|
|
||||||
|
/* Link this type to the caught type list */
|
||||||
|
caught_type_list = tree_cons (NULL_TREE, carg_type, caught_type_list);
|
||||||
|
|
||||||
/* Complete the catch clause block */
|
/* Complete the catch clause block */
|
||||||
catch_block = java_complete_tree (TREE_OPERAND (current, 0));
|
catch_block = java_complete_tree (TREE_OPERAND (current, 0));
|
||||||
if (catch_block == error_mark_node)
|
if (catch_block == error_mark_node)
|
||||||
@ -8918,6 +9063,11 @@ patch_try_statement (node)
|
|||||||
TREE_OPERAND (current, 0) = catch_block;
|
TREE_OPERAND (current, 0) = catch_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUSH_EXCEPTIONS (caught_type_list);
|
||||||
|
if ((try = java_complete_tree (try)) == error_mark_node)
|
||||||
|
error_found = 1;
|
||||||
|
POP_EXCEPTIONS ();
|
||||||
|
|
||||||
/* Process finally */
|
/* Process finally */
|
||||||
if (finally)
|
if (finally)
|
||||||
{
|
{
|
||||||
@ -8937,3 +9087,208 @@ patch_try_statement (node)
|
|||||||
TREE_TYPE (node) = void_type_node;
|
TREE_TYPE (node) = void_type_node;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 14.17 The synchronized Statement */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
patch_synchronized_statement (node, wfl_op1)
|
||||||
|
tree node, wfl_op1;
|
||||||
|
{
|
||||||
|
tree expr = TREE_OPERAND (node, 0);
|
||||||
|
tree block = TREE_OPERAND (node, 1);
|
||||||
|
tree try_block, catch_all, stmt, compound, decl;
|
||||||
|
|
||||||
|
/* The TYPE of expr must be a reference type */
|
||||||
|
if (!JREFERENCE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0))))
|
||||||
|
{
|
||||||
|
SET_WFL_OPERATOR (wfl_operator, node, wfl_op1);
|
||||||
|
parse_error_context (wfl_operator, "Incompatible type for `synchronized'"
|
||||||
|
". Can't convert `%s' to `java.lang.Object'",
|
||||||
|
lang_printable_name (TREE_TYPE (expr)));
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a try-finally for the synchronized statement, except
|
||||||
|
that the handler that catches all throw exception calls
|
||||||
|
_Jv_MonitorExit and then rethrow the exception.
|
||||||
|
The synchronized statement is then implemented as:
|
||||||
|
TRY
|
||||||
|
{
|
||||||
|
_Jv_MonitorEnter (expression)
|
||||||
|
synchronized_block
|
||||||
|
_Jv_MonitorExit (expression)
|
||||||
|
}
|
||||||
|
CATCH_ALL
|
||||||
|
{
|
||||||
|
e = _Jv_exception_info ();
|
||||||
|
_Jv_MonitorExit (expression)
|
||||||
|
Throw (e);
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* TRY block */
|
||||||
|
BUILD_MONITOR_ENTER (stmt, expr);
|
||||||
|
compound = add_stmt_to_compound (NULL_TREE, int_type_node, stmt);
|
||||||
|
compound = add_stmt_to_compound (compound, void_type_node, block);
|
||||||
|
BUILD_MONITOR_EXIT (stmt, expr);
|
||||||
|
compound = add_stmt_to_compound (compound, int_type_node, stmt);
|
||||||
|
try_block = build_expr_block (compound, NULL_TREE);
|
||||||
|
|
||||||
|
/* CATCH_ALL block */
|
||||||
|
decl = build_decl_no_layout (VAR_DECL, generate_name (), ptr_type_node);
|
||||||
|
BUILD_ASSIGN_EXCEPTION_INFO (stmt, decl);
|
||||||
|
compound = add_stmt_to_compound (NULL_TREE, void_type_node, stmt);
|
||||||
|
BUILD_MONITOR_EXIT (stmt, expr);
|
||||||
|
compound = add_stmt_to_compound (compound, int_type_node, stmt);
|
||||||
|
BUILD_THROW (stmt, decl);
|
||||||
|
compound = add_stmt_to_compound (compound, void_type_node, stmt);
|
||||||
|
catch_all = build_expr_block (compound, decl);
|
||||||
|
catch_all = build_expr_block (catch_all, NULL_TREE);
|
||||||
|
catch_all = build1 (CATCH_EXPR, void_type_node, catch_all);
|
||||||
|
|
||||||
|
/* TRY-CATCH statement */
|
||||||
|
return build (TRY_EXPR, void_type_node, try_block, catch_all, NULL_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 14.16 The throw Statement */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
patch_throw_statement (node, wfl_op1)
|
||||||
|
tree node, wfl_op1;
|
||||||
|
{
|
||||||
|
tree expr = TREE_OPERAND (node, 0);
|
||||||
|
tree type = TREE_TYPE (expr);
|
||||||
|
int unchecked_ok = 0, tryblock_throws_ok = 0;
|
||||||
|
|
||||||
|
/* Thrown expression must be assignable to java.lang.Throwable */
|
||||||
|
if (!try_reference_assignconv (throwable_type_node, expr))
|
||||||
|
{
|
||||||
|
SET_WFL_OPERATOR (wfl_operator, node, wfl_op1);
|
||||||
|
parse_error_context (wfl_operator, "Can't throw `%s'; it must be a "
|
||||||
|
"subclass of class `java.lang.Throwable'",
|
||||||
|
lang_printable_name (type));
|
||||||
|
/* If the thrown expression was a reference, we further the
|
||||||
|
compile-time check. */
|
||||||
|
if (!JREFERENCE_TYPE_P (type))
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At least one of the following must be true */
|
||||||
|
|
||||||
|
/* The type of the throw expression is a not checked exception,
|
||||||
|
i.e. is a unchecked expression. */
|
||||||
|
unchecked_ok = IS_UNCHECKED_EXPRESSION_P (TREE_TYPE (type));
|
||||||
|
|
||||||
|
/* Throw is contained in a try statement and at least one catch
|
||||||
|
clause can receive the thrown expression or the current method is
|
||||||
|
declared to throw such an exception. Or, the throw statement is
|
||||||
|
contained in a method or constructor declaration and the type of
|
||||||
|
the Expression is assignable to at least one type listed in the
|
||||||
|
throws clause the declaration. */
|
||||||
|
SET_WFL_OPERATOR (wfl_operator, node, wfl_op1);
|
||||||
|
if (!unchecked_ok)
|
||||||
|
tryblock_throws_ok =
|
||||||
|
check_thrown_exceptions_do (EXPR_WFL_LINECOL (wfl_operator),
|
||||||
|
TREE_TYPE (expr));
|
||||||
|
if (!(unchecked_ok || tryblock_throws_ok))
|
||||||
|
{
|
||||||
|
/* If there is a surrounding try block that has no matching
|
||||||
|
clatch clause, report it first. A surrounding try block exits
|
||||||
|
only if there is something after the list of checked
|
||||||
|
exception thrown by the current function (if any). */
|
||||||
|
if (IN_TRY_BLOCK_P ())
|
||||||
|
parse_error_context (wfl_operator, "Checked exception `%s' can't be "
|
||||||
|
"caught by any of the catch clause(s) "
|
||||||
|
"of the surrounding `try' block",
|
||||||
|
lang_printable_name (type));
|
||||||
|
/* If we have no surrounding try statement and the method doesn't have
|
||||||
|
any throws, report it now. FIXME */
|
||||||
|
else if (!EXCEPTIONS_P (currently_caught_type_list)
|
||||||
|
&& !tryblock_throws_ok)
|
||||||
|
parse_error_context (wfl_operator, "Checked exception `%s' isn't "
|
||||||
|
"thrown from a `try' block",
|
||||||
|
lang_printable_name (type));
|
||||||
|
/* Otherwise, the current method doesn't have the appropriate
|
||||||
|
throws declaration */
|
||||||
|
else
|
||||||
|
parse_error_context (wfl_operator, "Checked exception `%s' doesn't "
|
||||||
|
"match any of current method's `throws' "
|
||||||
|
"declaration(s)",
|
||||||
|
lang_printable_name (type));
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a throw statement is contained in a static initializer, then a
|
||||||
|
compile-time check ensures that either its value is always an
|
||||||
|
unchecked exception or its value is always caught by some try
|
||||||
|
statement that contains it. FIXME, static initializer. */
|
||||||
|
|
||||||
|
BUILD_THROW (node, expr);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that exception said to be thrown by method DECL can be
|
||||||
|
effectively caught from where DECL is invoked. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_thrown_exceptions (location, decl)
|
||||||
|
int location;
|
||||||
|
tree decl;
|
||||||
|
{
|
||||||
|
tree throws;
|
||||||
|
/* For all the unchecked exceptions thrown by DECL */
|
||||||
|
for (throws = DECL_FUNCTION_THROWS (decl); throws;
|
||||||
|
throws = TREE_CHAIN (throws))
|
||||||
|
if (!check_thrown_exceptions_do (location, TREE_VALUE (throws)))
|
||||||
|
{
|
||||||
|
EXPR_WFL_LINECOL (wfl_operator) = location;
|
||||||
|
parse_error_context
|
||||||
|
(wfl_operator, "Exception `%s' must be caught, or it must be "
|
||||||
|
"declared in the `throws' clause of `%s'",
|
||||||
|
lang_printable_name (TREE_VALUE (throws)),
|
||||||
|
IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return 1 if EXCEPTION is caught at the current nesting level of
|
||||||
|
try-catch blocks, OR is listed in the `throws' clause of the
|
||||||
|
current method. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_thrown_exceptions_do (location, exception)
|
||||||
|
int location;
|
||||||
|
tree exception;
|
||||||
|
{
|
||||||
|
tree list = currently_caught_type_list;
|
||||||
|
/* First, all the nested try-catch-finally at that stage. The
|
||||||
|
last element contains `throws' clause exceptions, if any. */
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
tree caught;
|
||||||
|
for (caught = TREE_VALUE (list); caught; caught = TREE_CHAIN (caught))
|
||||||
|
if (valid_ref_assignconv_cast_p (exception, TREE_VALUE (caught), 0))
|
||||||
|
return 1;
|
||||||
|
list = TREE_CHAIN (list);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
purge_unchecked_exceptions (mdecl)
|
||||||
|
tree mdecl;
|
||||||
|
{
|
||||||
|
tree throws = DECL_FUNCTION_THROWS (mdecl);
|
||||||
|
tree new = NULL_TREE;
|
||||||
|
|
||||||
|
while (throws)
|
||||||
|
{
|
||||||
|
tree next = TREE_CHAIN (throws);
|
||||||
|
if (!IS_UNCHECKED_EXPRESSION_P (TREE_VALUE (throws)))
|
||||||
|
{
|
||||||
|
TREE_CHAIN (throws) = new;
|
||||||
|
new = throws;
|
||||||
|
}
|
||||||
|
throws = next;
|
||||||
|
}
|
||||||
|
/* List is inverted here, but it doesn't matter */
|
||||||
|
DECL_FUNCTION_THROWS (mdecl) = new;
|
||||||
|
}
|
||||||
|
@ -662,7 +662,10 @@ lookup_argument_method (clas, method_name, method_signature)
|
|||||||
method != NULL_TREE; method = TREE_CHAIN (method))
|
method != NULL_TREE; method = TREE_CHAIN (method))
|
||||||
{
|
{
|
||||||
tree method_sig = build_java_argument_signature (TREE_TYPE (method));
|
tree method_sig = build_java_argument_signature (TREE_TYPE (method));
|
||||||
if (DECL_NAME (method) == method_name && method_sig == method_signature)
|
tree name = DECL_NAME (method);
|
||||||
|
if ((TREE_CODE (name) == EXPR_WITH_FILE_LOCATION ?
|
||||||
|
EXPR_WFL_NODE (DECL_NAME (method)) : name) == method_name
|
||||||
|
&& method_sig == method_signature)
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
clas = CLASSTYPE_SUPER (clas);
|
clas = CLASSTYPE_SUPER (clas);
|
||||||
@ -686,7 +689,8 @@ lookup_java_method (clas, method_name, method_signature)
|
|||||||
method != NULL_TREE; method = TREE_CHAIN (method))
|
method != NULL_TREE; method = TREE_CHAIN (method))
|
||||||
{
|
{
|
||||||
tree method_sig = build_java_signature (TREE_TYPE (method));
|
tree method_sig = build_java_signature (TREE_TYPE (method));
|
||||||
if (DECL_NAME (method) == method_name && method_sig == method_signature)
|
if (DECL_NAME (method) == method_name
|
||||||
|
&& method_sig == method_signature)
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
clas = CLASSTYPE_SUPER (clas);
|
clas = CLASSTYPE_SUPER (clas);
|
||||||
|
Loading…
Reference in New Issue
Block a user