Commit 9bbc7d9f by Per Bothner Committed by Per Bothner

decl.c (error_mark_node): New global.

�
	* decl.c (error_mark_node), java-tree.h:  New global.
	* parse.y:  Use empty_stmt_node instead of size_zero_node.
	(build_if_else_statement):  If missing else, use empty_stmt_node.
	* parse.y (not_initialized_as_it_should_p):  Removed, with its callers.
	(java_complete_expand_method):  Complain if return is missing.
	(java_check_regular_methods):  Comment out incorrect error check.
	(not_accessible_p):  Fix incorrect handling of protected methods.
	(patch_method_invocation):  Pass correct context to not_accessible_p.
	(find_applicable_accessible_methods_list):  Likewise.
	(qualify_ambiguous_name):  If ARRAY_REF, it's an expression name.
	(java_complete_tree):  For CASE_EXPR and DEFAULT_EXPR, set
	TREE_TYPE (to void_type_node);  otherwise expand_expr crashes.
	(patch_if_else_statement):  Fix setting of CAN_COMPLETE_NORMALLY.
	* jcf-write.c (CHECK_OP, CHECK_PUT):  Add some error checking.
	(push_int_const):  Remove reundant NOTE_PUSH.
	(generate_bytecode_insns - case STRING_CST):  Do NOTE_PUSH.
	(- case SWITCH_EXPR):  Fix code generation bug.
	(- case PREDECREMENT_EXPR etc):  Remove redundant NOTE_PUSH.
	(generate_classfile):  More robust for abstract methods.

From-SVN: r23661
parent 175135a6
Sun Nov 15 14:36:29 1998 Per Bothner <bothner@cygnus.com>
* decl.c (error_mark_node), java-tree.h: New global.
* parse.y: Use empty_stmt_node instead of size_zero_node.
(build_if_else_statement): If missing else, use empty_stmt_node.
* parse.y (not_initialized_as_it_should_p): Removed, with its callers.
(java_complete_expand_method): Complain if return is missing.
(java_check_regular_methods): Comment out incorrect error check.
(not_accessible_p): Fix incorrect handling of protected methods.
(patch_method_invocation): Pass correct context to not_accessible_p.
(find_applicable_accessible_methods_list): Likewise.
(qualify_ambiguous_name): If ARRAY_REF, it's an expression name.
(java_complete_tree): For CASE_EXPR and DEFAULT_EXPR, set
TREE_TYPE (to void_type_node); otherwise expand_expr crashes.
(patch_if_else_statement): Fix setting of CAN_COMPLETE_NORMALLY.
* jcf-write.c (CHECK_OP, CHECK_PUT): Add some error checking.
(push_int_const): Remove reundant NOTE_PUSH.
(generate_bytecode_insns - case STRING_CST): Do NOTE_PUSH.
(- case SWITCH_EXPR): Fix code generation bug.
(- case PREDECREMENT_EXPR etc): Remove redundant NOTE_PUSH.
(generate_classfile): More robust for abstract methods.
Sun Nov 15 13:52:39 1998 Anthony Green <green@cygnus.com>
* Makefile.in: jv-scan and jvgenmain all require libiberty.
......
......@@ -318,6 +318,7 @@ tree error_mark_node;
The first is of type `int', the second of type `void *'. */
tree integer_zero_node;
tree null_pointer_node;
tree empty_stmt_node;
/* Nodes for boolean constants TRUE and FALSE. */
tree boolean_true_node, boolean_false_node;
......@@ -431,8 +432,6 @@ init_decl_processing ()
TREE_TYPE (size_zero_node) = sizetype;
size_one_node = build_int_2 (1, 0);
TREE_TYPE (size_one_node) = sizetype;
/* Used by the parser to represent empty statements and blocks. */
CAN_COMPLETE_NORMALLY (size_zero_node) = 1;
byte_type_node = make_signed_type (8);
pushdecl (build_decl (TYPE_DECL, get_identifier ("byte"), byte_type_node));
......@@ -475,6 +474,10 @@ init_decl_processing ()
null_pointer_node = build_int_2 (0, 0);
TREE_TYPE (null_pointer_node) = ptr_type_node;
/* Used by the parser to represent empty statements and blocks. */
empty_stmt_node = build1 (NOP_EXPR, void_type_node, size_zero_node);
CAN_COMPLETE_NORMALLY (empty_stmt_node) = 1;
#if 0
/* Make a type to be the domain of a few array types
whose domains don't really matter.
......
......@@ -220,6 +220,7 @@ extern tree boolean_true_node, boolean_false_node;
extern tree integer_negative_one_node;
extern tree integer_two_node;
extern tree integer_four_node;
extern tree empty_stmt_node;
/* The type for struct methodtable. */
extern tree methodtable_type;
......
......@@ -50,34 +50,25 @@ char *jcf_write_base_directory = NULL;
/* Make sure bytecode.data is big enough for at least N more bytes. */
#define RESERVE(N) \
do { if (state->bytecode.ptr + (N) > state->bytecode.limit) \
do { CHECK_OP(state); \
if (state->bytecode.ptr + (N) > state->bytecode.limit) \
buffer_grow (&state->bytecode, N); } while (0)
/* Add a 1-byte instruction/operand I to bytecode.data,
assuming space has already been RESERVE'd. */
#define OP1(I) (*state->bytecode.ptr++ = (I))
#define OP1(I) (*state->bytecode.ptr++ = (I), CHECK_OP(state))
/* Like OP1, but I is a 2-byte big endian integer. */
#define OP2(I) \
do { int _i = (I); OP1 (_i >> 8); OP1 (_i); } while (0)
do { int _i = (I); OP1 (_i >> 8); OP1 (_i); CHECK_OP(state); } while (0)
/* Like OP1, but I is a 4-byte big endian integer. */
#define OP4(I) \
do { int _i = (I); OP1 (_i >> 24); OP1 (_i >> 16); \
OP1 (_i >> 8); OP1 (_i); } while (0)
/* The current stack size (stack pointer) in the current method. */
int code_SP = 0;
/* The largest extent of stack size (stack pointer) in the current method. */
int code_SP_max = 0;
CPool *code_cpool;
OP1 (_i >> 8); OP1 (_i); CHECK_OP(state); } while (0)
/* Macro to call each time we push I words on the JVM stack. */
......@@ -138,7 +129,13 @@ struct jcf_block
} u;
};
/* A "relocation" type for the 0-3 bytes of padding at the start
of a tableswitch or a lookupswitch. */
#define SWITCH_ALIGN_RELOC 4
/* A relocation type for the labels in a tableswitch or a lookupswitch;
these are relative to the start of the instruction, but (due to
th 0-3 bytes of padding), we don't know the offset before relocation. */
#define BLOCK_START_RELOC 1
struct jcf_relocation
......@@ -253,10 +250,26 @@ static void generate_bytecode_insns PROTO ((tree, int, struct jcf_partial *));
We assume a local variable 'ptr' points into where we want to
write next, and we assume enoygh space has been allocated. */
#define PUT1(X) (*ptr++ = (X))
#ifdef ENABLE_CHECKING
int
CHECK_PUT(ptr, state, i)
void *ptr;
struct jcf_partial *state;
int i;
{
if (ptr < state->chunk->data
|| (char*)ptr + i > state->chunk->data + state->chunk->size)
fatal ("internal error - CHECK_PUT failed");
return 0;
}
#else
#define CHECK_PUT(PTR, STATE, I) 0
#endif
#define PUT1(X) (CHECK_PUT(ptr, state, 1), *ptr++ = (X))
#define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF))
#define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF))
#define PUTN(P, N) (memcpy(ptr, P, N), ptr += (N))
#define PUTN(P, N) (CHECK_PUT(ptr, state, N), memcpy(ptr, P, N), ptr += (N))
/* Allocate a new chunk on obstack WORK, and link it in after LAST.
......@@ -284,6 +297,20 @@ alloc_chunk (last, data, size, work)
return chunk;
}
#ifdef ENABLE_CHECKING
int
CHECK_OP(struct jcf_partial *state)
{
if (state->bytecode.ptr > state->bytecode.limit)
{
fatal("internal error - CHECK_OP failed");
}
return 0;
}
#else
#define CHECK_OP(STATE) 0
#endif
unsigned char *
append_chunk (data, size, state)
unsigned char *data;
......@@ -574,6 +601,9 @@ write_chunks (stream, chunks)
fwrite (chunks->data, chunks->size, 1, stream);
}
/* Push a 1-word constant in the constant pool at the given INDEX.
(Caller is responsible for doing NOTE_PUSH.) */
static void
push_constant1 (index, state)
int index;
......@@ -592,6 +622,9 @@ push_constant1 (index, state)
}
}
/* Push a 2-word constant in the constant pool at the given INDEX.
(Caller is responsible for doing NOTE_PUSH.) */
static void
push_constant2 (index, state)
int index;
......@@ -622,7 +655,6 @@ push_int_const (i, state)
{
OP1(OPCODE_sipush);
OP2(i);
NOTE_PUSH (1);
}
else
{
......@@ -1257,6 +1289,7 @@ generate_bytecode_insns (exp, target, state)
break;
case STRING_CST:
push_constant1 (find_string_constant (&state->cpool, exp), state);
NOTE_PUSH (1);
break;
case VAR_DECL:
if (TREE_STATIC (exp))
......@@ -1473,12 +1506,16 @@ generate_bytecode_insns (exp, target, state)
OP4 (sw_state.max_case);
for (i = sw_state.min_case; ; )
{
if (i == sw_state.min_case + index)
emit_case_reloc (relocs[index++], state);
reloc = relocs[index];
if (i == reloc->offset)
{
emit_case_reloc (reloc, state);
if (i == sw_state.max_case)
break;
index++;
}
else
emit_switch_reloc (sw_state.default_label, state);
if (i == sw_state.max_case)
break;
i++;
}
}
......@@ -1619,12 +1656,8 @@ generate_bytecode_insns (exp, target, state)
if (target != IGNORE_TARGET && post_op)
emit_load (exp, state);
emit_iinc (exp, value, state);
if (target != IGNORE_TARGET)
{
if (! post_op)
emit_load (exp, state);
NOTE_PUSH (1);
}
if (target != IGNORE_TARGET && ! post_op)
emit_load (exp, state);
break;
}
if (TREE_CODE (exp) == COMPONENT_REF)
......@@ -2225,6 +2258,8 @@ perform_relocations (state)
*--new_ptr = 0;
*--new_ptr = - reloc->kind;
}
if (new_ptr != chunk->data)
fatal ("internal error - perform_relocations");
}
}
state->code_length = pc;
......@@ -2352,7 +2387,9 @@ generate_classfile (clas, state)
for (part = TYPE_METHODS (clas); part; part = TREE_CHAIN (part))
{
struct jcf_block *block;
tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (part));
tree function_body = DECL_FUNCTION_BODY (part);
tree body = function_body == NULL_TREE ? NULL_TREE
: BLOCK_EXPR_BODY (function_body);
tree name = DECL_CONSTRUCTOR_P (part) ? init_identifier_node
: DECL_NAME (part);
tree type = TREE_TYPE (part);
......
......@@ -786,7 +786,7 @@ constructor_body:
addition (super invocation and field initialization) */
block_begin block_end
{
BLOCK_EXPR_BODY ($2) = size_zero_node;
BLOCK_EXPR_BODY ($2) = empty_stmt_node;
$$ = $2;
}
| block_begin explicit_constructor_invocation block_end
......@@ -951,7 +951,7 @@ variable_initializers:
/* 19.11 Production from 14: Blocks and Statements */
block:
OCB_TK CCB_TK
{ $$ = size_zero_node; }
{ $$ = empty_stmt_node; }
| block_begin block_statements block_end
{ $$ = $3; }
;
......@@ -1033,7 +1033,7 @@ statement_without_trailing_substatement:
empty_statement:
SC_TK
{ $$ = size_zero_node; }
{ $$ = empty_stmt_node; }
;
label_decl:
......@@ -1273,7 +1273,7 @@ for_statement:
$$ = complete_for_loop (0, NULL_TREE, $4, $6);
/* We have not condition, so we get rid of the EXIT_EXPR */
LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY ($$), 0) =
size_zero_node;
empty_stmt_node;
}
| for_begin SC_TK error
{yyerror ("Invalid control expression"); RECOVER;}
......@@ -1291,7 +1291,7 @@ for_statement_nsi:
$$ = complete_for_loop (0, NULL_TREE, $4, $6);
/* We have not condition, so we get rid of the EXIT_EXPR */
LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY ($$), 0) =
size_zero_node;
empty_stmt_node;
}
;
......@@ -1322,7 +1322,7 @@ for_begin:
}
;
for_init: /* Can be empty */
{ $$ = size_zero_node; }
{ $$ = empty_stmt_node; }
| statement_expression_list
{
/* Init statement recorded within the previously
......@@ -1340,7 +1340,7 @@ for_init: /* Can be empty */
;
for_update: /* Can be empty */
{$$ = size_zero_node;}
{$$ = empty_stmt_node;}
| statement_expression_list
{ $$ = build_debugable_stmt (BUILD_LOCATION (), $1); }
;
......@@ -1636,6 +1636,8 @@ dims:
field_access:
primary DOT_TK identifier
{ $$ = make_qualified_primary ($1, $3, $2.location); }
/* FIXME - REWRITE TO:
{ $$ = build_binop (COMPONENT_REF, $2.location, $1, $3); } */
| SUPER_TK DOT_TK identifier
{
tree super_wfl =
......@@ -2164,7 +2166,7 @@ parse_jdk1_1_error (msg)
{
sorry (": `%s' JDK1.1(TM) feature", msg);
java_error_count++;
return size_zero_node;
return empty_stmt_node;
}
static int do_warning = 0;
......@@ -4206,6 +4208,7 @@ java_check_regular_methods (class_decl)
exceptions, if any */
check_throws_clauses (method, method_wfl, found);
#if 0
/* If the method has default access in an other package, then
issue a warning that the current method doesn't override the
one that was found elsewhere. Do not issue this warning when
......@@ -4220,6 +4223,7 @@ java_check_regular_methods (class_decl)
lang_printable_name (found, 0),
IDENTIFIER_POINTER (DECL_NAME (class_decl)),
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
#endif
/* Inheriting multiple methods with the same signature. FIXME */
}
......@@ -5239,6 +5243,8 @@ java_complete_expand_method (mdecl)
/* Expand functions that have a body */
if (DECL_FUNCTION_BODY (mdecl))
{
tree fbody = DECL_FUNCTION_BODY (mdecl);
tree block_body = BLOCK_EXPR_BODY (fbody);
expand_start_java_method (mdecl);
current_this
......@@ -5251,9 +5257,16 @@ java_complete_expand_method (mdecl)
/* Install exceptions thrown with `throws' */
PUSH_EXCEPTIONS (DECL_FUNCTION_THROWS (mdecl));
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)))
java_complete_tree (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)));
if (block_body != NULL_TREE)
block_body = java_complete_tree (block_body);
BLOCK_EXPR_BODY (fbody) = block_body;
if ((block_body == NULL_TREE || CAN_COMPLETE_NORMALLY (block_body))
&& TREE_CODE (TREE_TYPE (TREE_TYPE (mdecl))) != VOID_TYPE)
{
parse_error_context (fbody, "Missing return statement");
}
/* Don't go any further if we've found error(s) during the
expansion */
if (!java_error_count)
......@@ -6040,26 +6053,14 @@ int not_accessible_p (reference, member, from_super)
if (class_in_current_package (DECL_CONTEXT (member)))
return 0;
if (TREE_CODE (member) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (member))
{
/* Access from SUPER is granted */
if (from_super)
return 0;
/* Otherwise, access isn't granted */
return 1;
}
else
{
/* If accessed with the form `super.member', then access is
granted */
if (from_super)
return 0;
/* If accessed with the form `super.member', then access is granted */
if (from_super)
return 0;
/* Otherwise, access is granted if occuring from the class where
member is declared or a subclass of it */
if (inherits_from_p (reference, current_class))
return 0;
}
/* Otherwise, access is granted if occuring from the class where
member is declared or a subclass of it */
if (inherits_from_p (reference, current_class))
return 0;
return 1;
}
......@@ -6376,7 +6377,7 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl, super)
/* Check accessibility, position the is_static flag, build and
return the call */
if (not_accessible_p (DECL_CONTEXT (list), list, 0))
if (not_accessible_p (DECL_CONTEXT (current_function_decl), list, 0))
{
char *fct_name = strdup (lang_printable_name (list, 0));
parse_error_context
......@@ -6646,7 +6647,7 @@ find_applicable_accessible_methods_list (lc, class, name, arglist)
if (argument_types_convertible (method, arglist))
{
/* Retain accessible methods only */
if (!not_accessible_p (class, method, 0))
if (!not_accessible_p (DECL_CONTEXT (current_function_decl), method, 0))
list = tree_cons (NULL_TREE, method, list);
else
/* Also retain all selected method here */
......@@ -6884,7 +6885,8 @@ qualify_ambiguous_name (id)
}
/* Method call are expression name */
else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR)
else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR
|| TREE_CODE (QUAL_WFL (qual)) == ARRAY_REF)
RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
/* Check here that NAME isn't declared by more than one
......@@ -6945,22 +6947,6 @@ breakdown_qualified (left, right, source)
return 0;
}
static int
not_initialized_as_it_should_p (decl)
tree decl;
{
if (DECL_P (decl))
{
if (FIELD_FINAL (decl))
return 0;
if (TREE_CODE (decl) == FIELD_DECL
&& (METHOD_STATIC (current_function_decl)))
return 0;
return DECL_P (decl) && !INITIALIZED_P (decl);
}
return 0;
}
/* Patch tree nodes in a function body. When a BLOCK is found, push
local variable decls if present. */
......@@ -7127,6 +7113,7 @@ java_complete_tree (node)
value is checked during code generation. The case
expression is allright so far. */
TREE_OPERAND (node, 0) = cn;
TREE_TYPE (node) = void_type_node;
CAN_COMPLETE_NORMALLY (node) = 1;
break;
......@@ -7142,6 +7129,7 @@ java_complete_tree (node)
}
else
SWITCH_HAS_DEFAULT (nn) = 1;
TREE_TYPE (node) = void_type_node;
CAN_COMPLETE_NORMALLY (node) = 1;
break;
......@@ -7427,6 +7415,13 @@ java_complete_tree (node)
TREE_OPERAND (node, 1) = save_expr (TREE_OPERAND (node, 1));
return patch_array_ref (node, wfl_op1, wfl_op2);
#if 0
COMPONENT_REF:
/* Planned re-write FIXME */
TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0));
break;
#endif
case THIS_EXPR:
/* Can't use THIS in a static environment */
if (!current_this)
......@@ -7490,11 +7485,6 @@ complete_function_arguments (node)
parm = maybe_build_primttype_type_ref (parm, wfl);
TREE_VALUE (cn) = parm;
if (not_initialized_as_it_should_p (parm))
{
ERROR_VARIABLE_NOT_INITIALIZED (wfl, EXPR_WFL_NODE (wfl));
INITIALIZED_P (parm) = 1;
}
}
ctxp->explicit_constructor_p -= (CALL_THIS_CONSTRUCTOR_P (node) ? 1 : 0);
return flag;
......@@ -7622,14 +7612,14 @@ maybe_absorb_scoping_blocks ()
are building incomplete tree nodes and the patch_* functions that
are completing them. */
/* Build a super() constructor invocation. Returns size_zero_node if
/* Build a super() constructor invocation. Returns empty_stmt_node if
we're currently dealing with the class java.lang.Object. */
static tree
build_super_invocation ()
{
if (current_class == object_type_node)
return size_zero_node;
return empty_stmt_node;
else
{
tree super_wfl = build_wfl_node (super_identifier_node,
......@@ -7880,14 +7870,6 @@ patch_assignment (node, wfl_op1, wfl_op2)
error_found = 1;
}
/* Before reporting type incompatibility errors, check that the rhs
is initialized, if a variable */
if (not_initialized_as_it_should_p (rhs))
{
ERROR_VARIABLE_NOT_INITIALIZED (wfl_op2, DECL_NAME (rhs));
INITIALIZED_P (rhs) = 1;
}
/* Inline read access to java.lang.PRIMTYPE.TYPE */
rhs = maybe_build_primttype_type_ref (rhs, wfl_op2);
......@@ -8296,14 +8278,6 @@ patch_binop (node, wfl_op1, wfl_op2)
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
/* Check initialization of LHS first. We then silence further error
message if the variable wasn't initialized */
if (not_initialized_as_it_should_p (cfi))
{
ERROR_VARIABLE_NOT_INITIALIZED (cfi_wfl, DECL_NAME (cfi));
INITIALIZED_P (op1) = 1;
}
switch (code)
{
/* 15.16 Multiplicative operators */
......@@ -8581,16 +8555,6 @@ patch_binop (node, wfl_op1, wfl_op2)
break;
}
/* Then check the initialization of the RHS. We don't do that if
we're dealing with a node that is part of a compound
assignment. We then silence further error message if the variable
wasn't initialized */
if (not_initialized_as_it_should_p (op2) && !COMPOUND_ASSIGN_P (node))
{
ERROR_VARIABLE_NOT_INITIALIZED (wfl_op2, DECL_NAME (op2));
INITIALIZED_P (op2) = 1;
}
if (error_found)
return error_mark_node;
......@@ -9424,10 +9388,8 @@ build_if_else_statement (location, expression, if_body, else_body)
tree expression, if_body, else_body;
{
tree node;
/* FIXME: make else body be a void node, where this function is
called */
if (!else_body)
else_body = build (COMPOUND_EXPR, void_type_node, NULL_TREE, NULL_TREE);
else_body = empty_stmt_node;
node = build (COND_EXPR, NULL_TREE, expression, if_body, else_body);
EXPR_WFL_LINECOL (node) = location;
node = build_debugable_stmt (location, node);
......@@ -9457,8 +9419,8 @@ patch_if_else_statement (node)
TREE_TYPE (node) = void_type_node;
TREE_SIDE_EFFECTS (node) = 1;
CAN_COMPLETE_NORMALLY (node)
= CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0))
| CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1));
= CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1))
| CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 2));
return node;
}
......@@ -9584,7 +9546,7 @@ build_loop_body (location, condition, reversed)
second = (reversed ? condition : body);
return
build (COMPOUND_EXPR, NULL_TREE,
build (COMPOUND_EXPR, NULL_TREE, first, second), size_zero_node);
build (COMPOUND_EXPR, NULL_TREE, first, second), empty_stmt_node);
}
/* Install CONDITION (if any) and loop BODY (using REVERSED to tell
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment