aboutsummaryrefslogtreecommitdiff
path: root/gcc/java
diff options
context:
space:
mode:
authorAlexandre Petit-Bianco <apbianco@gcc.gnu.org>2000-12-06 10:55:42 -0800
committerAlexandre Petit-Bianco <apbianco@gcc.gnu.org>2000-12-06 10:55:42 -0800
commitc7303e411e27224a555ee8fae64bb421c26425cf (patch)
treebab5cce64b7453c82f9667ebeaae7027f855769d /gcc/java
parentee4570050a9b98deda6ec035906037a9e39c8335 (diff)
downloadgcc-c7303e411e27224a555ee8fae64bb421c26425cf.zip
gcc-c7303e411e27224a555ee8fae64bb421c26425cf.tar.gz
gcc-c7303e411e27224a555ee8fae64bb421c26425cf.tar.bz2
[multiple changes]
2000-10-18 Alexandre Petit-Bianco <apbianco@cygnus.com> * jcf-write.c (OP1): Update `last_bc'. (struct jcf_block): Fixed indentation and typo in comments. New field `last_bc'. (generate_bytecode_insns): Insert `nop' if `jsr' immediately follows `monitorenter'. * parse.y (patch_synchronized_statement): New local `tmp'. Call `patch_string'. Fixes gcj/232. 2000-10-13 Alexandre Petit-Bianco <apbianco@cygnus.com> * check-init.c (check_init): Fixed leading comment. Use LOCAL_FINAL_P. * decl.c (push_jvm_slot): Use MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC. (give_name_to_locals): Likewise. (lang_mark_tree): Handle FIELD_DECL. Register `am' and `wfl' fields in lang_decl_var. * java-tree.h (DECL_FUNCTION_SYNTHETIC_CTOR, DECL_FUNCTION_ALL_FINAL_INITIALIZED): New macros. (FIELD_INNER_ACCESS): Removed ugly cast, macro rewritten. (FIELD_INNER_ACCESS_P, DECL_FIELD_FINAL_IUD, DECL_FIELD_FINAL_LIIC, DECL_FIELD_FINAL_IERR, DECL_FIELD_FINAL_WFL): New macros. (LOCAL_FINAL): Rewritten. (LOCAL_FINAL_P, FINAL_VARIABLE_P, CLASS_FINAL_VARIABLE_P MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC): New macros. (struct lang_decl): Fixed comments. Added `synthetic_ctor' and `init_final' fields. (struct lang_decl_var): Fixed leading comment. Added `am', `wfl', `final_uid', `final_liic', `final_ierr' and `local_final' fields. (TYPE_HAS_FINAL_VARIABLE): New macro. (struct lang_type): Added `afv' field. * parse.y (check_static_final_variable_assignment_flag): New function. (reset_static_final_variable_assignment_flag): Likewise. (check_final_variable_local_assignment_flag): Likewise. (reset_final_variable_local_assignment_flag): Likewise. (check_final_variable_indirect_assignment): Likewise. (check_final_variable_global_assignment_flag): Likewise. (add_inner_class_fields): Use LOCAL_FINAL_P. (register_fields): Handle local finals and final variables. (craft_constructor): Set DECL_FUNCTION_SYNTHETIC_CTOR. (declare_local_variables): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC. (source_start_java_method): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC on local finals. (java_complete_expand_methods): Loop to set TYPE_HAS_FINAL_VARIABLE. Call `reset_final_variable_local_assignment_flag' and `check_final_variable_local_assignment_flag' accordingly before and after constructor expansion. Call `reset_static_final_variable_assignment_flag' before expanding <clinit> and after call `check_static_final_variable_assignment_flag' if the current_class isn't an interface. After all methods have been expanded, call `check_final_variable_global_assignment_flag' and `check_static_final_variable_assignment_flag' if the current class is an interface. (maybe_yank_clinit): Fixed typo in comment. (build_outer_field_access_methods): Removed old sanity check. Use FIELD_INNER_ACCESS_P. Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC. Don't create access methods for finals. (resolve_field_access): Use `CLASS_FINAL_VARIABLE_P'. (java_complete_tree): Likewise. Reset DECL_FIELD_FINAL_IUD if existing DECL_INIT has been processed. (java_complete_lhs): Likewise. (check_final_assignment): Filter input on `lvalue''s TREE_CODE. Test for COMPONENT_REF to get to the FIELD_DECL. Implemented new logic. (patch_assignment): Use LOCAL_FINAL_P. (fold_constant_for_init): Reset DECL_FIELD_FINAL_IUD if DECL_INITIAL is nullified. Fixes gcj/163. 2000-10-09 Alexandre Petit-Bianco <apbianco@cygnus.com> * parse.y (pop_current_osb): New function. (array_type:): Use `dims:', changed actions accordingly. Suggested by Anthony Green. (array_creation_expression:): Used pop_current_osb. (cast_expression:): Likewise. (search_applicable_method_list): Fixed indentation. 2000-10-08 Anthony Green <green@redhat.com> * parse.y (array_type_literal): Remove production. (type_literals): Refer to array_type, not array_type_literal. (http://gcc.gnu.org/ml/gcc-patches/2000-12/msg00317.html) From-SVN: r38070
Diffstat (limited to 'gcc/java')
-rw-r--r--gcc/java/ChangeLog87
-rw-r--r--gcc/java/check-init.c7
-rw-r--r--gcc/java/decl.c11
-rw-r--r--gcc/java/java-tree.h74
-rw-r--r--gcc/java/jcf-write.c24
-rw-r--r--gcc/java/parse.y484
6 files changed, 573 insertions, 114 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 69044f8..895f618 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -235,6 +235,17 @@ Thu Nov 23 02:19:14 2000 J"orn Rennecke <amylaar@redhat.com>
* verify.c (CHECK_PC_IN_RANGE): Cast result of stmt-expr to void.
+2000-10-18 Alexandre Petit-Bianco <apbianco@cygnus.com>
+
+ * jcf-write.c (OP1): Update `last_bc'.
+ (struct jcf_block): Fixed indentation and typo in comments. New
+ field `last_bc'.
+ (generate_bytecode_insns): Insert `nop' if `jsr' immediately
+ follows `monitorenter'.
+ * parse.y (patch_synchronized_statement): New local `tmp'. Call
+ `patch_string'.
+ Fixes gcj/232.
+
2000-10-16 Tom Tromey <tromey@cygnus.com>
* jvspec.c (lang_specific_driver): Recognize -MF and -MT.
@@ -298,6 +309,68 @@ Thu Nov 23 02:19:14 2000 J"orn Rennecke <amylaar@redhat.com>
* decl.c (init_decl_processing): Call init_class_processing before
anything else.
+2000-10-13 Alexandre Petit-Bianco <apbianco@cygnus.com>
+
+ * check-init.c (check_init): Fixed leading comment. Use
+ LOCAL_FINAL_P.
+ * decl.c (push_jvm_slot): Use MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
+ (give_name_to_locals): Likewise.
+ (lang_mark_tree): Handle FIELD_DECL. Register `am' and `wfl'
+ fields in lang_decl_var.
+ * java-tree.h (DECL_FUNCTION_SYNTHETIC_CTOR,
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED): New macros.
+ (FIELD_INNER_ACCESS): Removed ugly cast, macro rewritten.
+ (FIELD_INNER_ACCESS_P, DECL_FIELD_FINAL_IUD, DECL_FIELD_FINAL_LIIC,
+ DECL_FIELD_FINAL_IERR, DECL_FIELD_FINAL_WFL): New macros.
+ (LOCAL_FINAL): Rewritten.
+ (LOCAL_FINAL_P, FINAL_VARIABLE_P, CLASS_FINAL_VARIABLE_P
+ MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC): New macros.
+ (struct lang_decl): Fixed comments. Added `synthetic_ctor' and
+ `init_final' fields.
+ (struct lang_decl_var): Fixed leading comment. Added `am', `wfl',
+ `final_uid', `final_liic', `final_ierr' and `local_final' fields.
+ (TYPE_HAS_FINAL_VARIABLE): New macro.
+ (struct lang_type): Added `afv' field.
+ * parse.y (check_static_final_variable_assignment_flag): New function.
+ (reset_static_final_variable_assignment_flag): Likewise.
+ (check_final_variable_local_assignment_flag): Likewise.
+ (reset_final_variable_local_assignment_flag): Likewise.
+ (check_final_variable_indirect_assignment): Likewise.
+ (check_final_variable_global_assignment_flag): Likewise.
+ (add_inner_class_fields): Use LOCAL_FINAL_P.
+ (register_fields): Handle local finals and final variables.
+ (craft_constructor): Set DECL_FUNCTION_SYNTHETIC_CTOR.
+ (declare_local_variables): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
+ (source_start_java_method): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC
+ on local finals.
+ (java_complete_expand_methods): Loop to set
+ TYPE_HAS_FINAL_VARIABLE. Call
+ `reset_final_variable_local_assignment_flag' and
+ `check_final_variable_local_assignment_flag' accordingly before
+ and after constructor expansion. Call
+ `reset_static_final_variable_assignment_flag'
+ before expanding <clinit> and after call
+ `check_static_final_variable_assignment_flag' if the
+ current_class isn't an interface. After all methods have been
+ expanded, call `check_final_variable_global_assignment_flag' and
+ `check_static_final_variable_assignment_flag' if the current class
+ is an interface.
+ (maybe_yank_clinit): Fixed typo in comment.
+ (build_outer_field_access_methods): Removed old sanity check. Use
+ FIELD_INNER_ACCESS_P. Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
+ Don't create access methods for finals.
+ (resolve_field_access): Use `CLASS_FINAL_VARIABLE_P'.
+ (java_complete_tree): Likewise. Reset DECL_FIELD_FINAL_IUD if
+ existing DECL_INIT has been processed.
+ (java_complete_lhs): Likewise.
+ (check_final_assignment): Filter input on `lvalue''s TREE_CODE.
+ Test for COMPONENT_REF to get to the FIELD_DECL. Implemented new
+ logic.
+ (patch_assignment): Use LOCAL_FINAL_P.
+ (fold_constant_for_init): Reset DECL_FIELD_FINAL_IUD if
+ DECL_INITIAL is nullified.
+ Fixes gcj/163.
+
2000-10-13 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* Make-lang.in (parse.c, parse-scan.c): Create atomically.
@@ -403,6 +476,20 @@ Thu Nov 23 02:19:14 2000 J"orn Rennecke <amylaar@redhat.com>
fields.
* lex.h (java_lexer): Added out_buffer, out_first, out_last.
+2000-10-09 Alexandre Petit-Bianco <apbianco@cygnus.com>
+
+ * parse.y (pop_current_osb): New function.
+ (array_type:): Use `dims:', changed actions
+ accordingly. Suggested by Anthony Green.
+ (array_creation_expression:): Used pop_current_osb.
+ (cast_expression:): Likewise.
+ (search_applicable_method_list): Fixed indentation.
+
+2000-10-08 Anthony Green <green@redhat.com>
+
+ * parse.y (array_type_literal): Remove production.
+ (type_literals): Refer to array_type, not array_type_literal.
+
2000-10-07 Alexandre Petit-Bianco <apbianco@cygnus.com>
Patch contributed by Corey Minyard.
diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c
index f75e4fb..7de0e18 100644
--- a/gcc/java/check-init.c
+++ b/gcc/java/check-init.c
@@ -356,8 +356,7 @@ done_alternative (after, current)
start_current_locals = current.save_start_current_locals; \
}
-/* Check for (un)initialized local variables in EXP.
-*/
+/* Check for (un)initialized local variables in EXP. */
static void
check_init (exp, before)
@@ -387,14 +386,14 @@ check_init (exp, before)
/* We're interested in variable declaration and parameter
declaration when they're declared with the `final' modifier. */
if ((TREE_CODE (tmp) == VAR_DECL && ! FIELD_STATIC (tmp))
- || (TREE_CODE (tmp) == PARM_DECL && LOCAL_FINAL (tmp)))
+ || (TREE_CODE (tmp) == PARM_DECL && LOCAL_FINAL_P (tmp)))
{
int index;
check_init (TREE_OPERAND (exp, 1), before);
index = DECL_BIT_INDEX (tmp);
/* A final local already assigned or a final parameter
assigned must be reported as errors */
- if (LOCAL_FINAL (tmp)
+ if (LOCAL_FINAL_P (tmp)
&& (index == -1 || TREE_CODE (tmp) == PARM_DECL))
parse_error_context (wfl, "Can't assign here a value to the `final' variable `%s'", IDENTIFIER_POINTER (DECL_NAME (tmp)));
diff --git a/gcc/java/decl.c b/gcc/java/decl.c
index 04e0734..0ed7170 100644
--- a/gcc/java/decl.c
+++ b/gcc/java/decl.c
@@ -127,8 +127,7 @@ push_jvm_slot (index, decl)
/* Now link the decl into the decl_map. */
if (DECL_LANG_SPECIFIC (decl) == NULL)
{
- DECL_LANG_SPECIFIC (decl)
- = (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl_var));
+ MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
DECL_LOCAL_START_PC (decl) = 0;
DECL_LOCAL_END_PC (decl) = DECL_CODE_LENGTH (current_function_decl);
DECL_LOCAL_SLOT_NUMBER (decl) = index;
@@ -1620,8 +1619,7 @@ give_name_to_locals (jcf)
comments for expr.c:maybe_adjust_start_pc. */
start_pc = maybe_adjust_start_pc (jcf, code_offset, start_pc, slot);
- DECL_LANG_SPECIFIC (decl)
- = (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl_var));
+ MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
DECL_LOCAL_SLOT_NUMBER (decl) = slot;
DECL_LOCAL_START_PC (decl) = start_pc;
#if 0
@@ -1901,7 +1899,8 @@ lang_mark_tree (t)
ggc_mark_tree (li->utf8_ref);
}
else if (TREE_CODE (t) == VAR_DECL
- || TREE_CODE (t) == PARM_DECL)
+ || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == FIELD_DECL)
{
struct lang_decl_var *ldv =
((struct lang_decl_var *) DECL_LANG_SPECIFIC (t));
@@ -1909,6 +1908,8 @@ lang_mark_tree (t)
{
ggc_mark (ldv);
ggc_mark_tree (ldv->slot_chain);
+ ggc_mark_tree (ldv->am);
+ ggc_mark_tree (ldv->wfl);
}
}
else if (TREE_CODE (t) == FUNCTION_DECL)
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index fa898f8..f9b47dd 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -88,7 +88,6 @@ struct JCF;
3: METHOD_FINAL (in FUNCTION_DECL)
FIELD_FINAL (in FIELD_DECL)
CLASS_FINAL (in TYPE_DECL)
- LOCAL_FINAL (in VAR_DECL)
4: METHOD_SYNCHRONIZED (in FUNCTION_DECL).
LABEL_IN_SUBR (in LABEL_DECL)
CLASS_INTERFACE (in TYPE_DECL)
@@ -701,11 +700,12 @@ struct lang_identifier
is excluded, because sometimes created as a parameter before the
function decl exists. */
#define DECL_FUNCTION_NAP(DECL) (DECL_LANG_SPECIFIC(DECL)->nap)
-
-/* For a FIELD_DECL, holds the name of the access method used to
- read/write the content of the field from an inner class.
- The cast is ugly. FIXME */
-#define FIELD_INNER_ACCESS(DECL) ((tree)DECL_LANG_SPECIFIC (DECL))
+/* True if DECL is a synthetic ctor. */
+#define DECL_FUNCTION_SYNTHETIC_CTOR(DECL) \
+ (DECL_LANG_SPECIFIC(DECL)->synthetic_ctor)
+/* True if DECL initializes all its finals */
+#define DECL_FUNCTION_ALL_FINAL_INITIALIZED(DECL) \
+ (DECL_LANG_SPECIFIC(DECL)->init_final)
/* True when DECL aliases an outer context local variable. */
#define FIELD_LOCAL_ALIAS(DECL) DECL_LANG_FLAG_6 (DECL)
@@ -779,6 +779,46 @@ struct lang_identifier
slot_number in decl_map. */
#define DECL_LOCAL_SLOT_CHAIN(NODE) \
(((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->slot_chain)
+/* For a FIELD_DECL, holds the name of the access method. Used to
+ read/write the content of the field from an inner class. */
+#define FIELD_INNER_ACCESS(DECL) \
+ (((struct lang_decl_var*)DECL_LANG_SPECIFIC(DECL))->am)
+/* Safely tests whether FIELD_INNER_ACCESS exists or not. */
+#define FIELD_INNER_ACCESS_P(DECL) \
+ DECL_LANG_SPECIFIC (DECL) && FIELD_INNER_ACCESS (DECL)
+/* True if a final variable was initialized upon its declaration. */
+#define DECL_FIELD_FINAL_IUD(NODE) \
+ (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->final_iud)
+/* Set to true if a final variable is seen locally initialized on a
+ ctor. */
+#define DECL_FIELD_FINAL_LIIC(NODE) \
+ (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->final_liic)
+/* Set to true if an initialization error was already found with this
+ final variable. */
+#define DECL_FIELD_FINAL_IERR(NODE) \
+ (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->final_ierr)
+/* The original WFL of a final variable. */
+#define DECL_FIELD_FINAL_WFL(NODE) \
+ (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->wfl)
+/* True if NODE is a local final (as opposed to a final variable.)
+ This macro accesses the flag to read or set it. */
+#define LOCAL_FINAL(NODE) \
+ (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->local_final)
+/* True if NODE is a local final. */
+#define LOCAL_FINAL_P(NODE) (DECL_LANG_SPECIFIC (NODE) && LOCAL_FINAL (NODE))
+/* True if NODE is a final variable */
+#define FINAL_VARIABLE_P(NODE) (FIELD_FINAL (NODE) && !FIELD_STATIC (NODE))
+/* True if NODE is a class final variable */
+#define CLASS_FINAL_VARIABLE_P(NODE) \
+ (FIELD_FINAL (NODE) && FIELD_STATIC (NODE))
+/* Create a DECL_LANG_SPECIFIC if necessary. */
+#define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T) \
+ if (DECL_LANG_SPECIFIC (T) == NULL) \
+ { \
+ DECL_LANG_SPECIFIC ((T)) \
+ = ((struct lang_decl *) \
+ ggc_alloc_cleared (sizeof (struct lang_decl_var))); \
+ }
/* For a local VAR_DECL, holds the index into a words bitstring that
specifies if this decl is definitively assigned.
@@ -798,15 +838,15 @@ struct lang_decl
tree throws_list; /* Exception specified by `throws' */
tree function_decl_body; /* Hold all function's statements */
tree called_constructor; /* When decl is a constructor, the
- list of other constructor it calls. */
+ list of other constructor it calls */
struct hash_table init_test_table;
- /* Class initialization test variables. */
+ /* Class initialization test variables */
tree inner_access; /* The identifier of the access method
used for invocation from inner classes */
int nap; /* Number of artificial parameters */
-
- int native : 1; /* Nonzero if this is a native
- method. */
+ int native : 1; /* Nonzero if this is a native method */
+ int synthetic_ctor : 1; /* Nonzero if this is a synthetic ctor */
+ int init_final : 1; /* Nonzero all finals are initialized */
};
/* init_test_table hash table entry structure. */
@@ -816,13 +856,20 @@ struct init_test_hash_entry
tree init_test_decl;
};
-/* DECL_LANG_SPECIFIC for VAR_DECL and PARM_DECL. */
+/* DECL_LANG_SPECIFIC for VAR_DECL, PARM_DECL and sometimes FIELD_DECL
+ (access methods on outer class fields) and final fields. */
struct lang_decl_var
{
int slot_number;
int start_pc;
int end_pc;
tree slot_chain;
+ tree am; /* Access method for this field (1.1) */
+ tree wfl; /* Original wfl */
+ int final_iud : 1; /* Final initialized upon declaration */
+ int final_liic : 1; /* Final locally initialized in ctors */
+ int final_ierr : 1; /* Initialization error already detected */
+ int local_final : 1; /* True if the decl is a local final */
};
/* Macro to access fields in `struct lang_type'. */
@@ -847,6 +894,7 @@ struct lang_decl_var
#define TYPE_DOT_CLASS(T) (TYPE_LANG_SPECIFIC(T)->dot_class)
#define TYPE_PRIVATE_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->pic)
#define TYPE_PROTECTED_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->poic)
+#define TYPE_HAS_FINAL_VARIABLE(T) (TYPE_LANG_SPECIFIC(T)->afv)
struct lang_type
{
@@ -863,6 +911,7 @@ struct lang_type
<non_primitive_type>.class */
unsigned pic:1; /* Private Inner Class. */
unsigned poic:1; /* Protected Inner Class. */
+ unsigned afv:1; /* Has final variables */
};
#ifdef JAVA_USE_HANDLES
@@ -1110,7 +1159,6 @@ struct rtx_def * java_lang_expand_expr PARAMS ((tree, rtx, enum machine_mode,
#define FIELD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
#define FIELD_VOLATILE(DECL) DECL_LANG_FLAG_4 (DECL)
#define FIELD_TRANSIENT(DECL) DECL_LANG_FLAG_5 (DECL)
-#define LOCAL_FINAL(DECL) FIELD_FINAL(DECL)
/* Access flags etc for a class (a TYPE_DECL): */
diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c
index e08b37d..b66db93 100644
--- a/gcc/java/jcf-write.c
+++ b/gcc/java/jcf-write.c
@@ -57,7 +57,7 @@ char *jcf_write_base_directory = NULL;
/* Add a 1-byte instruction/operand I to bytecode.data,
assuming space has already been RESERVE'd. */
-#define OP1(I) (*state->bytecode.ptr++ = (I), CHECK_OP(state))
+#define OP1(I) (state->last_bc = *state->bytecode.ptr++ = (I), CHECK_OP(state))
/* Like OP1, but I is a 2-byte big endian integer. */
@@ -131,13 +131,14 @@ struct jcf_block
int linenumber;
- /* After finish_jcf_block is called, The actual instructions contained in this block.
- Before than NULL, and the instructions are in state->bytecode. */
+ /* After finish_jcf_block is called, The actual instructions
+ contained in this block. Before than NULL, and the instructions
+ are in state->bytecode. */
union {
struct chunk *chunk;
/* If pc==PENDING_CLEANUP_PC, start_label is the start of the region
- coveed by the cleanup. */
+ covered by the cleanup. */
struct jcf_block *start_label;
} v;
@@ -272,8 +273,10 @@ struct jcf_partial
/* If non-NULL, use this for the return value. */
tree return_value_decl;
- /* Information about the current switch statemenet. */
+ /* Information about the current switch statement. */
struct jcf_switch_state *sw_state;
+
+ enum java_opcode last_bc; /* The last emitted bytecode */
};
static void generate_bytecode_insns PARAMS ((tree, int, struct jcf_partial *));
@@ -2158,7 +2161,16 @@ generate_bytecode_insns (exp, target, state)
tree src = TREE_OPERAND (exp, 0);
tree src_type = TREE_TYPE (src);
tree dst_type = TREE_TYPE (exp);
- generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
+ /* Detect the situation of compiling an empty synchronized
+ block. A nop should be emitted in order to produce
+ verifiable bytecode. */
+ if (exp == empty_stmt_node
+ && state->last_bc == OPCODE_monitorenter
+ && state->labeled_blocks
+ && state->labeled_blocks->pc == PENDING_CLEANUP_PC)
+ OP1 (OPCODE_nop);
+ else
+ generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
if (target == IGNORE_TARGET || src_type == dst_type)
break;
if (TREE_CODE (dst_type) == POINTER_TYPE)
diff --git a/gcc/java/parse.y b/gcc/java/parse.y
index d89ace4..249dcfd 100644
--- a/gcc/java/parse.y
+++ b/gcc/java/parse.y
@@ -102,6 +102,12 @@ static int process_imports PARAMS ((void));
static void read_import_dir PARAMS ((tree));
static int find_in_imports_on_demand PARAMS ((tree));
static void find_in_imports PARAMS ((tree));
+static void check_static_final_variable_assignment_flag PARAMS ((tree));
+static void reset_static_final_variable_assignment_flag PARAMS ((tree));
+static void check_final_variable_local_assignment_flag PARAMS ((tree, tree));
+static void reset_final_variable_local_assignment_flag PARAMS ((tree));
+static int check_final_variable_indirect_assignment PARAMS ((tree));
+static void check_final_variable_global_assignment_flag PARAMS ((tree));
static void check_inner_class_access PARAMS ((tree, tree, tree));
static int check_pkg_class_access PARAMS ((tree, tree));
static void register_package PARAMS ((tree));
@@ -287,6 +293,7 @@ static void java_parser_context_pop_initialized_field PARAMS ((void));
static tree reorder_static_initialized PARAMS ((tree));
static void java_parser_context_suspend PARAMS ((void));
static void java_parser_context_resume PARAMS ((void));
+static int pop_current_osb PARAMS ((struct parser_ctxt *));
/* JDK 1.1 work. FIXME */
@@ -580,7 +587,7 @@ static tree currently_caught_type_list;
BOOLEAN_TK INTEGRAL_TK FP_TK
/* Added or modified JDK 1.1 rule types */
-%type <node> type_literals array_type_literal
+%type <node> type_literals
%%
/* 19.2 Production from 2.3: The Syntactic Grammar */
@@ -652,19 +659,23 @@ interface_type:
;
array_type:
- primitive_type OSB_TK CSB_TK
+ primitive_type dims
{
- $$ = build_java_array_type ($1, -1);
- CLASS_LOADED_P ($$) = 1;
+ int osb = pop_current_osb (ctxp);
+ tree t = build_java_array_type (($1), -1);
+ CLASS_LOADED_P (t) = 1;
+ while (--osb)
+ t = build_unresolved_array_type (t);
+ $$ = t;
+ }
+| name dims
+ {
+ int osb = pop_current_osb (ctxp);
+ tree t = $1;
+ while (osb--)
+ t = build_unresolved_array_type (t);
+ $$ = t;
}
-| name OSB_TK CSB_TK
- { $$ = build_unresolved_array_type ($1); }
-| array_type OSB_TK CSB_TK
- { $$ = build_unresolved_array_type ($1); }
-| primitive_type OSB_TK error
- {RULE ("']' expected"); RECOVER;}
-| array_type OSB_TK error
- {RULE ("']' expected"); RECOVER;}
;
/* 19.5 Productions from 6: Names */
@@ -1935,28 +1946,10 @@ primary_no_new_array:
{yyerror ("'class' expected" ); RECOVER;}
;
-/* Added, JDK1.1 type literals. We can't use `type' directly, so we
- broke the rule down a bit. */
-
-array_type_literal:
- primitive_type OSB_TK CSB_TK
- {
- $$ = build_java_array_type ($1, -1);
- CLASS_LOADED_P ($$) = 1;
- }
-| name OSB_TK CSB_TK
- { $$ = build_unresolved_array_type ($1); }
-/* This triggers two reduce/reduce conflict between array_type_literal and
- dims. FIXME.
-| array_type OSB_TK CSB_TK
- { $$ = build_unresolved_array_type ($1); }
-*/
-;
-
type_literals:
name DOT_TK CLASS_TK
{ $$ = build_incomplete_class_ref ($2.location, $1); }
-| array_type_literal DOT_TK CLASS_TK
+| array_type DOT_TK CLASS_TK
{ $$ = build_incomplete_class_ref ($2.location, $1); }
| primitive_type DOT_TK CLASS_TK
{ $$ = build_class_ref ($1); }
@@ -2085,15 +2078,16 @@ array_creation_expression:
| 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, CURRENT_OSB (ctxp));}
+ { $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));}
| NEW_TK class_or_interface_type dim_exprs dims
- { $$ = build_newarray_node ($2, $3, CURRENT_OSB (ctxp));}
+ { $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));}
/* Added, JDK1.1 anonymous array. Initial documentation rule
modified */
| NEW_TK class_or_interface_type dims array_initializer
{
char *sig;
- while (CURRENT_OSB (ctxp)--)
+ int osb = pop_current_osb (ctxp);
+ while (osb--)
obstack_1grow (&temporary_obstack, '[');
sig = obstack_finish (&temporary_obstack);
$$ = build (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE,
@@ -2101,8 +2095,9 @@ array_creation_expression:
}
| NEW_TK primitive_type dims array_initializer
{
+ int osb = pop_current_osb (ctxp);
tree type = $2;
- while (CURRENT_OSB (ctxp)--)
+ while (osb--)
type = build_java_array_type (type, -1);
$$ = build (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE,
build_pointer_type (type), NULL_TREE, $4);
@@ -2325,9 +2320,9 @@ cast_expression: /* Error handling here is potentially weak */
OP_TK primitive_type dims CP_TK unary_expression
{
tree type = $2;
- while (CURRENT_OSB (ctxp)--)
+ int osb = pop_current_osb (ctxp);
+ while (osb--)
type = build_java_array_type (type, -1);
- ctxp->osb_depth--;
$$ = build_cast ($1.location, type, $5);
}
| OP_TK primitive_type CP_TK unary_expression
@@ -2337,9 +2332,9 @@ cast_expression: /* Error handling here is potentially weak */
| OP_TK name dims CP_TK unary_expression_not_plus_minus
{
const char *ptr;
- while (CURRENT_OSB (ctxp)--)
+ int osb = pop_current_osb (ctxp);
+ while (osb--)
obstack_1grow (&temporary_obstack, '[');
- ctxp->osb_depth--;
obstack_grow0 (&temporary_obstack,
IDENTIFIER_POINTER (EXPR_WFL_NODE ($2)),
IDENTIFIER_LENGTH (EXPR_WFL_NODE ($2)));
@@ -2593,6 +2588,25 @@ constant_expression:
;
%%
+
+/* Helper function to retrieve an OSB count. Should be used when the
+ `dims:' rule is being used. */
+
+static int
+pop_current_osb (ctxp)
+ struct parser_ctxt *ctxp;
+{
+ int to_return;
+
+ if (ctxp->osb_depth < 0)
+ fatal ("osb stack underflow");
+
+ to_return = CURRENT_OSB (ctxp);
+ ctxp->osb_depth--;
+
+ return to_return;
+}
+
/* This section of the code deal with save/restoring parser contexts.
@@ -3952,7 +3966,7 @@ add_inner_class_fields (class_decl, fct_decl)
tree wfl, init, list;
/* Avoid non final arguments. */
- if (!LOCAL_FINAL (decl))
+ if (!LOCAL_FINAL_P (decl))
continue;
MANGLE_OUTER_LOCAL_VARIABLE_NAME (name, DECL_NAME (decl));
@@ -4185,11 +4199,29 @@ register_fields (flags, type, variable_list)
field_decl = add_field (class_type, current_name, real_type, flags);
CHECK_DEPRECATED (field_decl);
- /* If the couple initializer/initialized is marked ARG_FINAL_P, we
- mark the created field FIELD_LOCAL_ALIAS, so that we can
- hide parameters to this inner class finit$ and constructors. */
+ /* If the field denotes a final instance variable, then we
+ allocate a LANG_DECL_SPECIFIC part to keep track of its
+ initialization. We also mark whether the field was
+ initialized upon it's declaration. We don't do that if the
+ created field is an alias to a final local. */
+ if (!ARG_FINAL_P (current) && (flags & ACC_FINAL))
+ {
+ MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (field_decl);
+ DECL_FIELD_FINAL_WFL (field_decl) = cl;
+ if ((flags & ACC_STATIC) && init)
+ DECL_FIELD_FINAL_IUD (field_decl) = 1;
+ }
+
+ /* If the couple initializer/initialized is marked ARG_FINAL_P,
+ we mark the created field FIELD_LOCAL_ALIAS, so that we can
+ hide parameters to this inner class finit$ and
+ constructors. It also means that the field isn't final per
+ say. */
if (ARG_FINAL_P (current))
- FIELD_LOCAL_ALIAS (field_decl) = 1;
+ {
+ FIELD_LOCAL_ALIAS (field_decl) = 1;
+ FIELD_FINAL (field_decl) = 0;
+ }
/* Check if we must chain. */
if (must_chain)
@@ -5182,7 +5214,7 @@ craft_constructor (class_decl, args)
fix_method_argument_names (parm, decl);
/* Now, mark the artificial parameters. */
DECL_FUNCTION_NAP (decl) = artificial;
- DECL_CONSTRUCTOR_P (decl) = 1;
+ DECL_FUNCTION_SYNTHETIC_CTOR (decl) = DECL_CONSTRUCTOR_P (decl) = 1;
}
@@ -7039,6 +7071,7 @@ declare_local_variables (modifier, type, vlist)
/* Never layout this decl. This will be done when its scope
will be entered */
decl = build_decl (VAR_DECL, name, real_type);
+ MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
LOCAL_FINAL (decl) = final_p;
BLOCK_CHAIN_DECL (decl);
@@ -7116,7 +7149,10 @@ source_start_java_method (fndecl)
/* Remember if a local variable was declared final (via its
TREE_LIST of type/name.) Set LOCAL_FINAL accordingly. */
if (ARG_FINAL_P (tem))
- LOCAL_FINAL (parm_decl) = 1;
+ {
+ MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (parm_decl);
+ LOCAL_FINAL (parm_decl) = 1;
+ }
BLOCK_CHAIN_DECL (parm_decl);
}
@@ -7164,7 +7200,7 @@ static void
end_artificial_method_body (mdecl)
tree mdecl;
{
- BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_block ();
+ BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_blcok ();
exit_block ();
}
@@ -7472,6 +7508,14 @@ java_complete_expand_methods (class_decl)
current_class = TREE_TYPE (class_decl);
+ /* Find whether the class has final variables */
+ for (decl = TYPE_FIELDS (current_class); decl; decl = TREE_CHAIN (decl))
+ if (FIELD_FINAL (decl))
+ {
+ TYPE_HAS_FINAL_VARIABLE (current_class) = 1;
+ break;
+ }
+
/* Initialize a new constant pool */
init_outgoing_cpool ();
@@ -7504,7 +7548,15 @@ java_complete_expand_methods (class_decl)
if (no_body)
restore_line_number_status (1);
+ /* Reset the final local variable assignment flags */
+ if (TYPE_HAS_FINAL_VARIABLE (current_class))
+ reset_final_variable_local_assignment_flag (current_class);
+
java_complete_expand_method (decl);
+
+ /* Check for missed out final variable assignment */
+ if (TYPE_HAS_FINAL_VARIABLE (current_class))
+ check_final_variable_local_assignment_flag (current_class, decl);
if (no_body)
restore_line_number_status (0);
@@ -7532,10 +7584,17 @@ java_complete_expand_methods (class_decl)
/* If there is indeed a <clinit>, fully expand it now */
if (clinit)
{
+ /* Reset the final local variable assignment flags */
+ if (TYPE_HAS_FINAL_VARIABLE (current_class))
+ reset_static_final_variable_assignment_flag (current_class);
/* Prevent the use of `this' inside <clinit> */
ctxp->explicit_constructor_p = 1;
java_complete_expand_method (clinit);
ctxp->explicit_constructor_p = 0;
+ /* Check for missed out static final variable assignment */
+ if (TYPE_HAS_FINAL_VARIABLE (current_class)
+ && !CLASS_INTERFACE (class_decl))
+ check_static_final_variable_assignment_flag (current_class);
}
/* We might have generated a class$ that we now want to expand */
@@ -7550,6 +7609,15 @@ java_complete_expand_methods (class_decl)
&& verify_constructor_circularity (decl, decl))
break;
+ /* Final check on the initialization of final variables. */
+ if (TYPE_HAS_FINAL_VARIABLE (current_class))
+ {
+ check_final_variable_global_assignment_flag (current_class);
+ /* If we have an interface, check for uninitialized fields. */
+ if (CLASS_INTERFACE (class_decl))
+ check_static_final_variable_assignment_flag (current_class);
+ }
+
/* Save the constant pool. We'll need to restore it later. */
TYPE_CPOOL (current_class) = outgoing_cpool;
}
@@ -7690,7 +7758,7 @@ maybe_yank_clinit (mdecl)
continue;
/* Anything that isn't String or a basic type is ruled out -- or
- if we now how to deal with it (when doing things natively) we
+ if we know how to deal with it (when doing things natively) we
should generated an empty <clinit> so that SUID are computed
correctly. */
if (! JSTRING_TYPE_P (TREE_TYPE (current))
@@ -8045,14 +8113,11 @@ build_outer_field_access_methods (decl)
{
tree id, args, stmt, mdecl;
- /* Check point, to be removed. FIXME */
- if (FIELD_INNER_ACCESS (decl)
- && TREE_CODE (FIELD_INNER_ACCESS (decl)) != IDENTIFIER_NODE)
- abort ();
-
- if (FIELD_INNER_ACCESS (decl))
+ if (FIELD_INNER_ACCESS_P (decl))
return FIELD_INNER_ACCESS (decl);
+ MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
+
/* Create the identifier and a function named after it. */
id = build_new_access_id ();
@@ -8070,17 +8135,21 @@ build_outer_field_access_methods (decl)
TREE_TYPE (decl), id, args, stmt);
DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
- /* Create the write access method */
- args = build_tree_list (inst_id, build_pointer_type (DECL_CONTEXT (decl)));
- TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
- TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
- stmt = make_qualified_primary (build_wfl_node (inst_id),
- build_wfl_node (DECL_NAME (decl)), 0);
- stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
- build_wfl_node (wpv_id)));
-
- mdecl = build_outer_field_access_method (DECL_CONTEXT (decl),
- TREE_TYPE (decl), id, args, stmt);
+ /* Create the write access method. No write access for final variable */
+ if (!FIELD_FINAL (decl))
+ {
+ args = build_tree_list (inst_id,
+ build_pointer_type (DECL_CONTEXT (decl)));
+ TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
+ TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
+ stmt = make_qualified_primary (build_wfl_node (inst_id),
+ build_wfl_node (DECL_NAME (decl)), 0);
+ stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
+ build_wfl_node (wpv_id)));
+ mdecl = build_outer_field_access_method (DECL_CONTEXT (decl),
+ TREE_TYPE (decl), id,
+ args, stmt);
+ }
DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
/* Return the access name */
@@ -8986,7 +9055,7 @@ resolve_field_access (qual_wfl, field_decl, field_type)
if (!type_found)
type_found = DECL_CONTEXT (decl);
is_static = JDECL_P (decl) && FIELD_STATIC (decl);
- if (FIELD_FINAL (decl) && FIELD_STATIC (decl)
+ if (CLASS_FINAL_VARIABLE_P (decl)
&& JPRIMITIVE_TYPE_P (TREE_TYPE (decl))
&& DECL_INITIAL (decl))
{
@@ -10587,7 +10656,7 @@ search_applicable_methods_list (lc, method, name, arglist, list, all_list)
else if (!lc && (DECL_CONSTRUCTOR_P (method)
|| (GET_METHOD_NAME (method) != name)))
continue;
-
+
if (argument_types_convertible (method, arglist))
{
/* Retain accessible methods only */
@@ -10996,7 +11065,7 @@ java_complete_tree (node)
tree node;
{
node = java_complete_lhs (node);
- if (JDECL_P (node) && FIELD_STATIC (node) && FIELD_FINAL (node)
+ if (JDECL_P (node) && CLASS_FINAL_VARIABLE_P (node)
&& DECL_INITIAL (node) != NULL_TREE
&& !flag_emit_xref)
{
@@ -11015,6 +11084,8 @@ java_complete_tree (node)
else
return value;
}
+ else
+ DECL_FIELD_FINAL_IUD (node) = 0;
}
return node;
}
@@ -11505,6 +11576,8 @@ java_complete_lhs (node)
}
if (! flag_emit_class_files)
DECL_INITIAL (nn) = NULL_TREE;
+ if (CLASS_FINAL_VARIABLE_P (nn))
+ DECL_FIELD_FINAL_IUD (nn) = 0;
}
wfl_op2 = TREE_OPERAND (node, 1);
@@ -12062,6 +12135,214 @@ print_int_node (node)
return buffer;
}
+
+
+/* This section of the code handle assignment check with FINAL
+ variables. */
+
+static void
+reset_static_final_variable_assignment_flag (class)
+ tree class;
+{
+ tree field;
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (CLASS_FINAL_VARIABLE_P (field))
+ DECL_FIELD_FINAL_LIIC (field) = 0;
+}
+
+/* Figure whether all final static variable have been initialized. */
+
+static void
+check_static_final_variable_assignment_flag (class)
+ tree class;
+{
+ tree field;
+
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (CLASS_FINAL_VARIABLE_P (field)
+ && !DECL_FIELD_FINAL_IUD (field) && !DECL_FIELD_FINAL_LIIC (field))
+ parse_error_context
+ (DECL_FIELD_FINAL_WFL (field),
+ "Blank static final variable `%s' may not have be initialized",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+}
+
+/* This function marks all final variable locally unassigned. */
+
+static void
+reset_final_variable_local_assignment_flag (class)
+ tree class;
+{
+ tree field;
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FINAL_VARIABLE_P (field))
+ DECL_FIELD_FINAL_LIIC (field) = 0;
+}
+
+/* Figure whether all final variables have beem initialized in MDECL
+ and mark MDECL accordingly. */
+
+static void
+check_final_variable_local_assignment_flag (class, mdecl)
+ tree class;
+ tree mdecl;
+{
+ tree field;
+ int initialized = 0;
+ int non_initialized = 0;
+
+ if (DECL_FUNCTION_SYNTHETIC_CTOR (mdecl))
+ return;
+
+ /* First find out whether all final variables or no final variable
+ are initialized in this ctor. We don't take into account final
+ variable that have been initialized upon declaration. */
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FINAL_VARIABLE_P (field) && !DECL_FIELD_FINAL_IUD (field))
+ {
+ if (DECL_FIELD_FINAL_LIIC (field))
+ initialized++;
+ else
+ non_initialized++;
+ }
+
+ /* There were no non initialized variable and no initialized variable.
+ This ctor is fine. */
+ if (!non_initialized && !initialized)
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+ /* If no variables have been initialized, that fine. We'll check
+ later whether this ctor calls a constructor which initializes
+ them. We mark the ctor as not initializing all its finals. */
+ else if (initialized == 0)
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 0;
+ /* If we have a mixed bag, then we have a problem. We need to report
+ all the variables we're not initializing. */
+ else if (initialized && non_initialized)
+ {
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 0;
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FIELD_FINAL (field)
+ && !DECL_FIELD_FINAL_IUD (field) && !DECL_FIELD_FINAL_LIIC (field))
+ {
+ parse_error_context
+ (lookup_cl (mdecl),
+ "Blank final variable `%s' may not have been initialized in this constructor",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+ DECL_FIELD_FINAL_IERR (field) = 1;
+ }
+ }
+ /* Otherwise we know this ctor is initializing all its final
+ variable. We mark it so. */
+ else
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+}
+
+/* This function recurses in a simple what through STMT and stops when
+ it finds a constructor call. It then verifies that the called
+ constructor initialized its final properly. Return 1 upon success,
+ 0 or -1 otherwise. */
+
+static int
+check_final_variable_indirect_assignment (stmt)
+ tree stmt;
+{
+ int res;
+ switch (TREE_CODE (stmt))
+ {
+ case EXPR_WITH_FILE_LOCATION:
+ return check_final_variable_indirect_assignment (EXPR_WFL_NODE (stmt));
+ case COMPOUND_EXPR:
+ res = check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 0));
+ if (res)
+ return res;
+ return check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 1));
+ case SAVE_EXPR:
+ return check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 0));
+ case CALL_EXPR:
+ {
+ tree decl = TREE_OPERAND (stmt, 0);
+ tree fbody;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ fatal ("Can't find FUNCTION_DECL in CALL_EXPR - check_final_variable_indirect_assignment");
+ if (DECL_FUNCTION_ALL_FINAL_INITIALIZED (decl))
+ return 1;
+ if (DECL_FINIT_P (decl) || DECL_CONTEXT (decl) != current_class)
+ return -1;
+ fbody = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (decl));
+ if (fbody == error_mark_node)
+ return -1;
+ fbody = BLOCK_EXPR_BODY (fbody);
+ return check_final_variable_indirect_assignment (fbody);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* This is the last chance to catch a final variable initialization
+ problem. This routine will report an error if a final variable was
+ never (globally) initialized and never reported as not having been
+ initialized properly. */
+
+static void
+check_final_variable_global_assignment_flag (class)
+ tree class;
+{
+ tree field, mdecl;
+ int nnctor = 0;
+
+ /* We go through all natural ctors and see whether they're
+ initializing all their final variables or not. */
+ current_function_decl = NULL_TREE; /* For the error report. */
+ for (mdecl = TYPE_METHODS (class); mdecl; mdecl = TREE_CHAIN (mdecl))
+ if (DECL_CONSTRUCTOR_P (mdecl) && ! DECL_FUNCTION_SYNTHETIC_CTOR (mdecl))
+ {
+ if (!DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl))
+ {
+ /* It doesn't. Maybe it calls a constructor that initializes
+ them. find out. */
+ tree fbody = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl));
+ if (fbody == error_mark_node)
+ continue;
+ fbody = BLOCK_EXPR_BODY (fbody);
+ if (check_final_variable_indirect_assignment (fbody) == 1)
+ {
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+ nnctor++;
+ }
+ else
+ parse_error_context
+ (lookup_cl (mdecl),
+ "Final variable initialization error in this constructor");
+ }
+ else
+ nnctor++;
+ }
+
+ /* Finally we catch final variables that never were initialized */
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FINAL_VARIABLE_P (field)
+ /* If the field wasn't initialized upon declaration */
+ && !DECL_FIELD_FINAL_IUD (field)
+ /* There wasn't natural ctor in which the field could have been
+ initialized */
+ && !nnctor
+ /* If we never reported a problem with this field */
+ && !DECL_FIELD_FINAL_IERR (field))
+ {
+ current_function_decl = NULL;
+ parse_error_context
+ (DECL_FIELD_FINAL_WFL (field),
+ "Final variable `%s' hasn't been initialized upon its declaration",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+ }
+
+}
+
/* Return 1 if an assignment to a FINAL is attempted in a non suitable
context. */
@@ -12069,27 +12350,52 @@ static int
check_final_assignment (lvalue, wfl)
tree lvalue, wfl;
{
- if (TREE_CODE (lvalue) == COMPOUND_EXPR
+ if (TREE_CODE (lvalue) != COMPONENT_REF && !JDECL_P (lvalue))
+ return 0;
+
+ if (TREE_CODE (lvalue) == COMPONENT_REF
&& JDECL_P (TREE_OPERAND (lvalue, 1)))
lvalue = TREE_OPERAND (lvalue, 1);
- /* When generating class files, references to the `length' field
- look a bit different. */
- if ((flag_emit_class_files
- && TREE_CODE (lvalue) == COMPONENT_REF
- && TYPE_ARRAY_P (TREE_TYPE (TREE_OPERAND (lvalue, 0)))
- && FIELD_FINAL (TREE_OPERAND (lvalue, 1)))
- || (TREE_CODE (lvalue) == FIELD_DECL
- && FIELD_FINAL (lvalue)
- && !DECL_CLINIT_P (current_function_decl)
- && !DECL_FINIT_P (current_function_decl)))
+ if (!FIELD_FINAL (lvalue))
+ return 0;
+
+ /* Now the logic. We can modify a final VARIABLE:
+ 1) in finit$, (its declaration was followed by an initialization,)
+ 2) consistently in each natural ctor, if it wasn't initialized in
+ finit$ or once in <clinit>. In any other cases, an error should be
+ reported. */
+ if (DECL_FINIT_P (current_function_decl))
{
- parse_error_context
- (wfl, "Can't assign a value to the final variable `%s'",
- IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
- return 1;
+ DECL_FIELD_FINAL_IUD (lvalue) = 1;
+ return 0;
}
- return 0;
+
+ if (!DECL_FUNCTION_SYNTHETIC_CTOR (current_function_decl)
+ /* Only if it wasn't given a value upon initialization */
+ && DECL_LANG_SPECIFIC (lvalue) && !DECL_FIELD_FINAL_IUD (lvalue)
+ /* If it was never assigned a value in this constructor */
+ && !DECL_FIELD_FINAL_LIIC (lvalue))
+ {
+ /* Turn the locally assigned flag on, it will be checked later
+ on to point out at discrepancies. */
+ DECL_FIELD_FINAL_LIIC (lvalue) = 1;
+ if (DECL_CLINIT_P (current_function_decl))
+ DECL_FIELD_FINAL_IUD (lvalue) = 1;
+ return 0;
+ }
+
+ /* Other problems should be reported right away. */
+ parse_error_context
+ (wfl, "Can't %sassign a value to the final variable `%s'",
+ (FIELD_STATIC (lvalue) ? "re" : ""),
+ IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
+
+ /* Note that static field can be initialized once and only once. */
+ if (FIELD_STATIC (lvalue))
+ DECL_FIELD_FINAL_IERR (lvalue) = 1;
+
+ return 1;
}
/* Inline references to java.lang.PRIMTYPE.TYPE when accessed in
@@ -12297,7 +12603,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
/* Final locals can be used as case values in switch
statement. Prepare them for this eventuality. */
if (TREE_CODE (lvalue) == VAR_DECL
- && LOCAL_FINAL (lvalue)
+ && LOCAL_FINAL_P (lvalue)
&& TREE_CONSTANT (new_rhs)
&& IDENTIFIER_LOCAL_VALUE (DECL_NAME (lvalue))
&& JINTEGRAL_TYPE_P (TREE_TYPE (lvalue))
@@ -14820,7 +15126,7 @@ patch_synchronized_statement (node, wfl_op1)
tree expr = java_complete_tree (TREE_OPERAND (node, 0));
tree block = TREE_OPERAND (node, 1);
- tree enter, exit, expr_decl, assignment;
+ tree tmp, enter, exit, expr_decl, assignment;
if (expr == error_mark_node)
{
@@ -14828,6 +15134,10 @@ patch_synchronized_statement (node, wfl_op1)
return expr;
}
+ /* We might be trying to synchronize on a STRING_CST */
+ if ((tmp = patch_string (expr)))
+ expr = tmp;
+
/* The TYPE of expr must be a reference type */
if (!JREFERENCE_TYPE_P (TREE_TYPE (expr)))
{
@@ -15265,6 +15575,8 @@ fold_constant_for_init (node, context)
DECL_INITIAL (node) = NULL_TREE;
val = fold_constant_for_init (val, node);
DECL_INITIAL (node) = val;
+ if (!val && CLASS_FINAL_VARIABLE_P (node))
+ DECL_FIELD_FINAL_IUD (node) = 0;
return val;
case EXPR_WITH_FILE_LOCATION: