aboutsummaryrefslogtreecommitdiff
path: root/gcc/java
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/java')
-rw-r--r--gcc/java/ChangeLog53
-rw-r--r--gcc/java/check-init.c416
-rw-r--r--gcc/java/expr.c10
-rw-r--r--gcc/java/java-tree.h73
-rw-r--r--gcc/java/parse.y373
5 files changed, 446 insertions, 479 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index ae85b1a1..5b06dde 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,56 @@
+2001-12-04 Per Bothner <per@bothner.com>
+
+ * check-init.c: Handle definite unassignment to finals in addition
+ to definite assignment.
+ (loop_current_locals): New field.
+ (num_current_locals, int start_current_locals, num_current_words):
+ Make static.
+ (SET_P, CLEAR_P, SET_BIT): Add needed but missing parentheses.
+ (ASSIGNED_P, UNASSIGNED_P, SET_ASSIGNED, SET_UNASSIGNED,
+ CLEAR_ASSIGNED, CLEAR_UNASSIGNED): New macros.
+ (get_variable_decl, check_final_reassigned): New functions.
+ (check_init, check_bool_init): Modify as needed for checking finals.
+ (check_for_initialization): Take extra parameter and return void.
+ Do extra start-up logic to check final fields for assignment.
+ * parse.y (check_static_final_variable_assignment_flag,
+ reset_static_final_variable_assignment_flag, check_final_assignment,
+ check_final_variable_local_assignment_flag,
+ reset_final_variable_indirect_assignment_flag,
+ reset_final_variable_global_assignment_flag): Remove functions.
+ (java_complete_expand_methods, outer_field_access_fix,
+ patch_assignment): Remove no-longer used logic.
+ * java-tree.h (DECL_FIELD_FINAL_IUD): Change usage and comments.
+ * parse.y (register_fields, java_complete_tree): Update accordingly.
+
+ * check-init.c (ALLOC_WORDS/FREE_WORDS): Use xmalloc/free, not alloca.
+ (DECLARE_BUFFERS, RELEASE_BUFFERS, ALLOC_BUFFER, FREE_BUFFER): New.
+ (check_cond_init, check_bool2_init): Use DECLARE_BUFFERS.
+
+ * java-tree.h (STATIC_CLASS_INIT_OPT_P): Temporarily turn off.
+
+ * java-tree.h (DECL FINAL): New bit-field.
+ (METHOD_FINAL, FIELD_FINAL, CLASS_FINAL): Define as DECL_FINAL.
+ (LOCAL_FINAL_P): Use DECL_FINAL rather than old LOCAL_FINAL.
+ (DECL_INIT_CALLS_THIS): New macro.
+ (struct lang_decl): New bit-field init_calls_this.
+ (DECL_FUNCTION_ALL_FINAL_INITIALIZED, DECL_FIELD_FINAL_LIIC,
+ DECL_FIELD_FINAL_IERR, LOCAL_FINAL, TYPE_HAS_FINAL_VARIABLE
+ (DECL_BIT_INDEX): Change to use pointer_alias_set since we now
+ use it for both local variables and final fields.
+ (struct lang_decl_var): Remove bit-fields final_liic, final_ierr,
+ and local_final.
+ (struct lang_type): Remove hfv bit-field.
+ (check_for_initialization): Change to return void.
+
+ * java-tree.h (IS_ARRAY_LENGTH_ACCESS): New macros.
+ * expr.c (build_java_array_length_access): Set IS_ARRAY_LENGTH_ACCESS.
+ * check-init.c (final_assign_error): New helper function.
+ (check_final_reassigned, check_init): Use it.
+ (check_init): Also check IS_ARRAY_LENGTH_ACCESS for ARRAY.length.
+
+ * java-tree.h (struct lang_decl, struct lang_decl_var): Change all
+ bit-fields to unsigned.
+
2001-12-03 Per Bothner <per@bothner.com>
* parse.y (patch_binop): Minor constant folding.
diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c
index 7aea182..e8329c9 100644
--- a/gcc/java/check-init.c
+++ b/gcc/java/check-init.c
@@ -1,4 +1,4 @@
-/* Code to test for "definitive assignment".
+/* Code to test for "definitive [un]assignment".
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
@@ -30,8 +30,10 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
#include "toplev.h" /* Needed for fatal. */
/* The basic idea is that we assign each local variable declaration
- an index, and then we pass around bitstrings, where the i'th bit
- is set if decl whose DECL_BIT_INDEX is i is definitely assigned. */
+ and each blank final field an index, and then we pass around
+ bitstrings, where the (2*i)'th bit is set if decl whose DECL_BIT_INDEX
+ is i is definitely assigned, and the the (2*i=1)'th bit is set if
+ decl whose DECL_BIT_INDEX is i is definitely unassigned */
/* One segment of a bitstring. */
typedef unsigned int word;
@@ -40,7 +42,11 @@ typedef unsigned int word;
typedef word *words;
/* Number of locals variables currently active. */
-int num_current_locals = 0;
+static int num_current_locals = 0;
+
+/* The value of num_current_locals when we entered the closest
+ enclosing LOOP_EXPR. */
+static int loop_current_locals;
/* The index of the first local variable in the current block.
@@ -62,9 +68,9 @@ int num_current_locals = 0;
even for methods with thousands of local variables, as
long as most of them are initialized immediately after or in
their declaration. */
-int start_current_locals = 0;
+static int start_current_locals = 0;
-int num_current_words = 1;
+static int num_current_words;
static tree wfl;
@@ -98,28 +104,120 @@ static void check_cond_init PARAMS ((tree, tree, tree, words, words, words));
static void check_bool2_init PARAMS ((enum tree_code, tree, tree, words, words, words));
struct alternatives;
static void done_alternative PARAMS ((words, struct alternatives *));
+static tree get_variable_decl PARAMS ((tree));
+static void final_assign_error PARAMS ((tree));
+static void check_final_reassigned PARAMS ((tree, words));
-#if 0
#define ALLOC_WORDS(NUM) ((word*) xmalloc ((NUM) * sizeof (word)))
#define FREE_WORDS(PTR) (free (PTR))
-#else
-#define ALLOC_WORDS(NUM) ((word*)alloca ((NUM) * sizeof (word)))
-#define FREE_WORDS(PTR) ((void)0)
-#endif
+
+/* DECLARE_BUFFERS is used to allocate NUMBUFFER bit sets, each of
+ which is an array of length num_current_words number of words.
+ Declares a new local variable BUFFER to hold the result (or rather
+ a pointer to the first of the bit sets). In almost all cases
+ num_current_words will be 1 or at most 2, so we try to stack
+ allocate the arrays in that case, using a stack array
+ named BUFFER##_short. Each DECLARE_BUFFERS must be matched by
+ a corresponding RELEASE_BUFFERS to avoid memory leaks. */
+
+#define DECLARE_BUFFERS(BUFFER, NUMBUFFERS) \
+ word BUFFER##_short[2 * NUMBUFFERS]; \
+ words BUFFER = ALLOC_BUFFER(BUFFER##_short, NUMBUFFERS * num_current_words)
+
+#define RELEASE_BUFFERS(BUFFER) \
+ FREE_BUFFER(BUFFER, BUFFER##_short)
+
+#define ALLOC_BUFFER(SHORTBUFFER, NUMWORDS) \
+ ((NUMWORDS) * sizeof(word) <= sizeof(SHORTBUFFER) ? SHORTBUFFER \
+ : ALLOC_WORDS(NUMWORDS))
+
+#define FREE_BUFFER(BUFFER, SHORTBUFFER) \
+ if (BUFFER != SHORTBUFFER) FREE_WORDS(BUFFER)
#define SET_P(WORDS, BIT) \
- (WORDS[BIT / WORD_SIZE] & (1 << (BIT % WORD_SIZE)))
+ (WORDS[(BIT) / WORD_SIZE] & (1 << ((BIT) % WORD_SIZE)))
#define CLEAR_BIT(WORDS, BIT) \
- (WORDS[BIT / WORD_SIZE] &= ~ (1 << (BIT % WORD_SIZE)))
+ (WORDS[(BIT) / WORD_SIZE] &= ~ (1 << ((BIT) % WORD_SIZE)))
#define SET_BIT(WORDS, BIT) \
- (WORDS[BIT / WORD_SIZE] |= (1 << (BIT % WORD_SIZE)))
+ (WORDS[(BIT) / WORD_SIZE] |= (1 << ((BIT) % WORD_SIZE)))
#define WORDS_NEEDED(BITS) (((BITS)+(WORD_SIZE-1))/(WORD_SIZE))
+#define ASSIGNED_P(WORDS, BIT) SET_P(WORDS, 2 * (BIT))
+#define UNASSIGNED_P(WORDS, BIT) SET_P(WORDS, 2 * (BIT) + 1)
+
+#define SET_ASSIGNED(WORDS, INDEX) SET_BIT (WORDS, 2 * (INDEX))
+#define SET_UNASSIGNED(WORDS, INDEX) SET_BIT (WORDS, 2 * (INDEX) + 1)
+
+#define CLEAR_ASSIGNED(WORDS, INDEX) CLEAR_BIT (WORDS, 2 * (INDEX))
+#define CLEAR_UNASSIGNED(WORDS, INDEX) CLEAR_BIT (WORDS, 2 * (INDEX) + 1)
+
+/* Get the "interesting" declaration from a MODIFY_EXPR or COMPONENT_REF.
+ Return the declaration or NULL_TREE if no interesting declaration. */
+
+static tree
+get_variable_decl (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == VAR_DECL)
+ {
+ if (! TREE_STATIC (exp) || FIELD_FINAL (exp))
+ return exp;
+ }
+ /* We only care about final parameters. */
+ else if (TREE_CODE (exp) == PARM_DECL)
+ {
+ if (DECL_FINAL (exp))
+ return exp;
+ }
+ /* See if exp is this.field. */
+ else if (TREE_CODE (exp) == COMPONENT_REF)
+ {
+ tree op0 = TREE_OPERAND (exp, 0);
+ tree op1 = TREE_OPERAND (exp, 1);
+ tree mdecl = current_function_decl;
+ if (TREE_CODE (op0) == INDIRECT_REF
+ && TREE_CODE (op1) == FIELD_DECL
+ && ! METHOD_STATIC (mdecl)
+ && FIELD_FINAL (op1))
+ {
+ op0 = TREE_OPERAND (op0, 0);
+ if (op0 == BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)))
+ return op1;
+ }
+ }
+ return NULL_TREE;
+}
+
+static void
+final_assign_error (name)
+ tree name;
+{
+ static const char format[]
+ = "can't re-assign here a value to the final variable '%s'";
+ parse_error_context (wfl, format, IDENTIFIER_POINTER (name));
+}
+
+static void
+check_final_reassigned (decl, before)
+ tree decl;
+ words before;
+{
+ int index = DECL_BIT_INDEX (decl);
+ /* A final local already assigned or a final parameter
+ assigned must be reported as errors */
+ if (DECL_FINAL (decl) && index != -2
+ && (index < loop_current_locals /* I.e. -1, or outside current loop. */
+ || ! UNASSIGNED_P (before, index)))
+ {
+ final_assign_error (DECL_NAME (decl));
+ }
+}
+
/* Check a conditional form (TEST_EXP ? THEN_EXP : ELSE_EXP) for
- definite assignment.
+ definite [un]assignment.
BEFORE, WHEN_FALSE, and WHEN_TRUE are as in check_bool_init. */
static void
@@ -128,19 +226,22 @@ check_cond_init (test_exp, then_exp, else_exp,
tree test_exp, then_exp, else_exp;
words before, when_false, when_true;
{
- words tmp = ALLOC_WORDS (6 * num_current_words);
- words test_false = tmp;
- words test_true = tmp + num_current_words;
- words then_false = tmp + 2 * num_current_words;
- words then_true = tmp + 3 * num_current_words;
- words else_false = tmp + 4 * num_current_words;
- words else_true = tmp + 5 * num_current_words;
+ int save_start_current_locals = start_current_locals;
+ DECLARE_BUFFERS(test_false, 6);
+ words test_true = test_false + num_current_words;
+ words then_false = test_true + num_current_words;
+ words then_true = then_false + num_current_words;
+ words else_false = then_true + num_current_words;
+ words else_true = else_false + num_current_words;
+ start_current_locals = num_current_locals;
+
check_bool_init (test_exp, before, test_false, test_true);
check_bool_init (then_exp, test_true, then_false, then_true);
check_bool_init (else_exp, test_false, else_false, else_true);
INTERSECT (when_false, then_false, else_false);
INTERSECT (when_true, then_true, else_true);
- FREE_WORDS (tmp);
+ RELEASE_BUFFERS(test_false);
+ start_current_locals = save_start_current_locals;
}
/* Check a boolean binary form CODE (EXP0, EXP1),
@@ -152,8 +253,8 @@ check_bool2_init (code, exp0, exp1, before, when_false, when_true)
enum tree_code code; tree exp0, exp1;
words before, when_false, when_true;
{
- word buf[4];
- words tmp = num_current_words <= 1 ? buf
+ word buf[2*4];
+ words tmp = num_current_words <= 2 ? buf
: ALLOC_WORDS (4 * num_current_words);
words when_false_0 = tmp;
words when_false_1 = tmp+num_current_words;
@@ -204,12 +305,12 @@ check_bool2_init (code, exp0, exp1, before, when_false, when_true)
FREE_WORDS (tmp);
}
-/* Check a boolean expression EXP for definite assignment.
- BEFORE is the set of variables definitely assigned before the conditional.
- (This bitstring may be modified arbitrarily in this function.)
- On output, WHEN_FALSE is the set of variables definitely assigned after
+/* Check a boolean expression EXP for definite [un]assignment.
+ BEFORE is the set of variables definitely [un]assigned before the
+ conditional. (This bitstring may be modified arbitrarily in this function.)
+ On output, WHEN_FALSE is the set of variables [un]definitely assigned after
the conditional when the conditional is false.
- On output, WHEN_TRUE is the set of variables definitely assigned after
+ On output, WHEN_TRUE is the set of variables definitely [un]assigned after
the conditional when the conditional is true.
(WHEN_FALSE and WHEN_TRUE are overwritten with initial values ignored.)
(None of BEFORE, WHEN_FALSE, or WHEN_TRUE can overlap, as they may
@@ -244,16 +345,19 @@ check_bool_init (exp, before, when_false, when_true)
case MODIFY_EXPR:
{
tree tmp = TREE_OPERAND (exp, 0);
- if (TREE_CODE (tmp) == VAR_DECL && ! FIELD_STATIC (tmp))
+ if ((tmp = get_variable_decl (tmp)) != NULL_TREE)
{
int index;
check_bool_init (TREE_OPERAND (exp, 1), before,
when_false, when_true);
+ check_final_reassigned (tmp, before);
index = DECL_BIT_INDEX (tmp);
if (index >= 0)
{
- SET_BIT (when_false, index);
- SET_BIT (when_true, index);
+ SET_ASSIGNED (when_false, index);
+ SET_ASSIGNED (when_true, index);
+ CLEAR_UNASSIGNED (when_false, index);
+ CLEAR_UNASSIGNED (when_true, index);
}
break;
}
@@ -325,6 +429,10 @@ struct alternatives
struct alternatives * alternatives = NULL;
+/* Begin handling a control flow branch.
+ BEFORE is the state of [un]assigned variables on entry.
+ CURRENT is a struct alt to manage the branch alternatives. */
+
#define BEGIN_ALTERNATIVES(before, current) \
{ \
current.saved = NULL; \
@@ -338,15 +446,23 @@ struct alternatives * alternatives = NULL;
start_current_locals = num_current_locals; \
}
+/* We have finished with one branch of branching control flow.
+ Store the [un]assigned state, merging (intersecting) it with the state
+ of previous alternative branches. */
+
static void
done_alternative (after, current)
words after;
struct alternatives *current;
{
INTERSECTN (current->combined, current->combined, after,
- WORDS_NEEDED (current->num_locals));
+ WORDS_NEEDED (2 * current->num_locals));
}
+/* Used when we done with a control flow branch and are all merged again.
+ * AFTER is the merged state of [un]assigned variables,
+ CURRENT is a struct alt that was passed to BEGIN_ALTERNATIVES. */
+
#define END_ALTERNATIVES(after, current) \
{ \
alternatives = current.outer; \
@@ -368,48 +484,62 @@ check_init (exp, before)
switch (TREE_CODE (exp))
{
case VAR_DECL:
- if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE)
+ case PARM_DECL:
+ if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE
+ && DECL_NAME (exp) != this_identifier_node)
{
int index = DECL_BIT_INDEX (exp);
- /* We don't want to report and mark as non initialized flags
- the are, they will be marked initialized later on when
- assigned to `true.' */
- if ((STATIC_CLASS_INIT_OPT_P ()
- && ! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp))
- && index >= 0 && ! SET_P (before, index))
+ /* We don't want to report and mark as non initialized class
+ initialization flags. */
+ if (! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp)
+ && index >= 0 && ! ASSIGNED_P (before, index))
{
parse_error_context
(wfl, "Variable `%s' may not have been initialized",
IDENTIFIER_POINTER (DECL_NAME (exp)));
/* Suppress further errors. */
- DECL_BIT_INDEX (exp) = -1;
+ DECL_BIT_INDEX (exp) = -2;
}
}
break;
+
+ case COMPONENT_REF:
+ check_init (TREE_OPERAND (exp, 0), before);
+ if ((tmp = get_variable_decl (exp)) != NULL_TREE)
+ {
+ int index = DECL_BIT_INDEX (tmp);
+ if (index >= 0 && ! ASSIGNED_P (before, index))
+ {
+ parse_error_context
+ (wfl, "variable '%s' may not have been initialized",
+ IDENTIFIER_POINTER (DECL_NAME (tmp)));
+ /* Suppress further errors. */
+ DECL_BIT_INDEX (tmp) = -2;
+ }
+ }
+ break;
+
case MODIFY_EXPR:
tmp = TREE_OPERAND (exp, 0);
/* 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_P (tmp)))
+ if ((tmp = get_variable_decl (tmp)) != NULL_TREE)
{
int index;
check_init (TREE_OPERAND (exp, 1), before);
+ check_final_reassigned (tmp, before);
index = DECL_BIT_INDEX (tmp);
- /* A final local already assigned or a final parameter
- assigned must be reported as errors */
- 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)));
-
if (index >= 0)
- SET_BIT (before, index);
+ {
+ SET_ASSIGNED (before, index);
+ CLEAR_UNASSIGNED (before, index);
+ }
/* Minor optimization. See comment for start_current_locals.
If we're optimizing for class initialization, we keep
this information to check whether the variable is
definitely assigned when once we checked the whole
function. */
- if (! STATIC_CLASS_INIT_OPT_P ()
+ if (! STATIC_CLASS_INIT_OPT_P () /* FIXME */
&& index >= start_current_locals
&& index == num_current_locals - 1)
{
@@ -418,6 +548,22 @@ check_init (exp, before)
}
break;
}
+ else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF)
+ {
+ tree decl;
+ check_init (tmp, before);
+ check_init (TREE_OPERAND (exp, 1), before);
+ decl = TREE_OPERAND (tmp, 1);
+ if (DECL_FINAL (decl))
+ final_assign_error (DECL_NAME (decl));
+ break;
+ }
+ else if (TREE_CODE (tmp) == INDIRECT_REF && IS_ARRAY_LENGTH_ACCESS (tmp))
+ {
+ /* We can't emit a more specific message here, because when
+ compiling to bytecodes we don't get here. */
+ final_assign_error (length_identifier_node);
+ }
else
goto binop;
case BLOCK:
@@ -434,7 +580,7 @@ check_init (exp, before)
{
DECL_BIT_INDEX (decl) = num_current_locals++;
}
- words_needed = WORDS_NEEDED (num_current_locals);
+ words_needed = WORDS_NEEDED (2 * num_current_locals);
if (words_needed > num_current_words)
{
tmp = ALLOC_WORDS (words_needed);
@@ -444,7 +590,10 @@ check_init (exp, before)
else
tmp = before;
for (i = start_current_locals; i < num_current_locals; i++)
- CLEAR_BIT (tmp, i);
+ {
+ CLEAR_ASSIGNED (tmp, i);
+ SET_UNASSIGNED (tmp, i);
+ }
check_init (BLOCK_EXPR_BODY (exp), tmp);
num_current_locals = start_current_locals;
start_current_locals = save_start_current_locals;
@@ -454,23 +603,44 @@ check_init (exp, before)
COPY (before, tmp);
FREE_WORDS (tmp);
}
+
+ /* Re-set DECL_BIT_INDEX since it is also DECL_POINTER_ALIAS_SET. */
+ for (decl = BLOCK_EXPR_DECLS (exp);
+ decl != NULL_TREE; decl = TREE_CHAIN (decl))
+ {
+ DECL_BIT_INDEX (decl) = -1;
+ }
}
break;
case LOOP_EXPR:
{
+ /* The JLS 2nd edition discusses a complication determining
+ definite unassignment of loop statements. They define a
+ "hypothetical" analysis model. We do something much
+ simpler: We just disallow assignments inside loops to final
+ variables declared outside the loop. This means we may
+ disallow some contrived assignments that the JLS, but I
+ can't see how anything except a very contrived testcase (a
+ do-while whose condition is false?) would care. */
+
struct alternatives alt;
+ int save_loop_current_locals = loop_current_locals;
+ int save_start_current_locals = start_current_locals;
+ loop_current_locals = num_current_locals;
+ start_current_locals = num_current_locals;
BEGIN_ALTERNATIVES (before, alt);
alt.block = exp;
check_init (TREE_OPERAND (exp, 0), before);
END_ALTERNATIVES (before, alt);
+ loop_current_locals = save_loop_current_locals;
+ start_current_locals = save_start_current_locals;
return;
}
case EXIT_EXPR:
{
struct alternatives *alt = alternatives;
- words tmp = ALLOC_WORDS (2 * num_current_words);
- words when_true = tmp;
- words when_false = tmp + num_current_words;
+ DECLARE_BUFFERS(when_true, 2);
+ words when_false = when_true + num_current_words;
#ifdef ENABLE_JC1_CHECKING
if (TREE_CODE (alt->block) != LOOP_EXPR)
abort ();
@@ -478,7 +648,7 @@ check_init (exp, before)
check_bool_init (TREE_OPERAND (exp, 0), before, when_false, when_true);
done_alternative (when_true, alt);
COPY (before, when_false);
- FREE_WORDS (tmp);
+ RELEASE_BUFFERS(when_true);
return;
}
case LABELED_BLOCK_EXPR:
@@ -505,14 +675,17 @@ check_init (exp, before)
case SWITCH_EXPR:
{
struct alternatives alt;
+ word buf[2];
check_init (TREE_OPERAND (exp, 0), before);
BEGIN_ALTERNATIVES (before, alt);
- alt.saved = ALLOC_WORDS (num_current_words);
+ alt.saved = ALLOC_BUFFER(buf, num_current_words);
COPY (alt.saved, before);
alt.block = exp;
check_init (TREE_OPERAND (exp, 1), before);
done_alternative (before, &alt);
- FREE_WORDS (alt.saved);
+ FREE_BUFFER(alt.saved, buf);
+ if (alt.saved != buf)
+ FREE_WORDS (alt.saved);
END_ALTERNATIVES (before, alt);
return;
}
@@ -523,9 +696,9 @@ check_init (exp, before)
struct alternatives *alt = alternatives;
while (TREE_CODE (alt->block) != SWITCH_EXPR)
alt = alt->outer;
- COPYN (before, alt->saved, WORDS_NEEDED (alt->num_locals));
+ COPYN (before, alt->saved, WORDS_NEEDED (2 * alt->num_locals));
for (i = alt->num_locals; i < num_current_locals; i++)
- CLEAR_BIT (before, i);
+ CLEAR_ASSIGNED (before, i);
break;
}
@@ -533,8 +706,10 @@ check_init (exp, before)
{
tree try_clause = TREE_OPERAND (exp, 0);
tree clause = TREE_OPERAND (exp, 1);
- words save = ALLOC_WORDS (num_current_words);
- words tmp = ALLOC_WORDS (num_current_words);
+ word buf[2*2];
+ words tmp = (num_current_words <= 2 ? buf
+ : ALLOC_WORDS (2 * num_current_words));
+ words save = tmp + num_current_words;
struct alternatives alt;
BEGIN_ALTERNATIVES (before, alt);
COPY (save, before);
@@ -548,20 +723,22 @@ check_init (exp, before)
check_init (catch_clause, tmp);
done_alternative (tmp, &alt);
}
- FREE_WORDS (tmp);
- FREE_WORDS (save);
+ if (tmp != buf)
+ {
+ FREE_WORDS (tmp);
+ }
END_ALTERNATIVES (before, alt);
}
return;
case TRY_FINALLY_EXPR:
{
- words tmp = ALLOC_WORDS (num_current_words);
+ DECLARE_BUFFERS(tmp, 1);
COPY (tmp, before);
check_init (TREE_OPERAND (exp, 0), before);
check_init (TREE_OPERAND (exp, 1), tmp);
UNION (before, before, tmp);
- FREE_WORDS (tmp);
+ RELEASE_BUFFERS(tmp);
}
return;
@@ -580,14 +757,18 @@ check_init (exp, before)
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
{
- words tmp = ALLOC_WORDS (2 * num_current_words);
- words when_true = tmp;
- words when_false = tmp + num_current_words;
+ DECLARE_BUFFERS(when_true, 2);
+ words when_false = when_true + num_current_words;
check_bool_init (exp, before, when_false, when_true);
INTERSECT (before, when_false, when_true);
- FREE_WORDS (tmp);
+ RELEASE_BUFFERS(when_true);
}
break;
+
+ case NOP_EXPR:
+ if (exp == empty_stmt_node)
+ break;
+ /* ... else fall through ... */
case UNARY_PLUS_EXPR:
case NEGATE_EXPR:
case TRUTH_AND_EXPR:
@@ -596,9 +777,7 @@ check_init (exp, before)
case TRUTH_NOT_EXPR:
case BIT_NOT_EXPR:
case CONVERT_EXPR:
- case COMPONENT_REF:
case BIT_FIELD_REF:
- case NOP_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case INDIRECT_REF:
@@ -662,7 +841,6 @@ check_init (exp, before)
exp = TREE_OPERAND (exp, 1);
goto again;
- case PARM_DECL:
case RESULT_DECL:
case FUNCTION_DECL:
case INTEGER_CST:
@@ -720,13 +898,87 @@ check_init (exp, before)
}
}
-unsigned int
-check_for_initialization (body)
- tree body;
+void
+check_for_initialization (body, mdecl)
+ tree body, mdecl;
{
- word before = 0;
- check_init (body, &before);
- return before;
+ tree decl;
+ word buf[2];
+ words before = buf;
+ tree owner = DECL_CONTEXT (mdecl);
+ int is_static_method = METHOD_STATIC (mdecl);
+ /* We don't need to check final fields of <init> it it calls this(). */
+ int is_finit_method = DECL_FINIT_P (mdecl) || DECL_INSTINIT_P (mdecl);
+ int is_init_method
+ = (is_finit_method || DECL_CLINIT_P (mdecl)
+ || (DECL_INIT_P (mdecl) && ! DECL_INIT_CALLS_THIS (mdecl)));
+
+ start_current_locals = num_current_locals = 0;
+ num_current_words = 2;
+
+ if (is_init_method)
+ {
+ int words_needed, i;
+ for (decl = TYPE_FIELDS (owner);
+ decl != NULL_TREE; decl = TREE_CHAIN (decl))
+ {
+ if (DECL_FINAL (decl) && FIELD_STATIC (decl) == is_static_method)
+ {
+ if (DECL_FIELD_FINAL_IUD (decl))
+ DECL_BIT_INDEX (decl) = -1;
+ else
+ DECL_BIT_INDEX (decl) = num_current_locals++;
+ }
+ }
+ words_needed = WORDS_NEEDED (2 * num_current_locals);
+ if (words_needed > 2)
+ {
+ num_current_words = words_needed;
+ before = ALLOC_WORDS(words_needed);
+ }
+ i = 0;
+ for (decl = TYPE_FIELDS (owner);
+ decl != NULL_TREE; decl = TREE_CHAIN (decl))
+ {
+ if (FIELD_FINAL (decl) && FIELD_STATIC (decl) == is_static_method)
+ {
+ if (! DECL_FIELD_FINAL_IUD (decl))
+ {
+ CLEAR_ASSIGNED (before, i);
+ SET_UNASSIGNED (before, i);
+ i++;
+ }
+ }
+ }
+
+ }
+
+ check_init (body, before);
+
+ if (is_init_method)
+ {
+ for (decl = TYPE_FIELDS (owner);
+ decl != NULL_TREE; decl = TREE_CHAIN (decl))
+ {
+ if (FIELD_FINAL (decl) && FIELD_STATIC (decl) == is_static_method)
+ {
+ int index = DECL_BIT_INDEX (decl);
+ if (index >= 0 && ! ASSIGNED_P (before, index))
+ {
+ if (! is_finit_method)
+ error_with_decl (decl, "final field '%s' may not have been initialized");
+ }
+ else if (is_finit_method)
+ DECL_FIELD_FINAL_IUD (decl) = 1;
+
+ /* Re-set to initial state, since we later may use the
+ same bit for DECL_POINTER_ALIAS_SET. */
+ DECL_BIT_INDEX (decl) = -1;
+ }
+ }
+ }
+
+ start_current_locals = num_current_locals = 0;
}
/* Call for every element in DECL_FUNCTION_INITIALIZED_CLASS_TABLE of
@@ -747,7 +999,7 @@ attach_initialized_static_class (entry, ptr)
already added but escaped analysis.) */
if (fndecl && METHOD_STATIC (fndecl)
&& (DECL_INITIAL (ite->init_test_decl) == boolean_true_node
- || (index >= 0 && SET_P (((word *) ptr), index))))
+ || (index >= 0 && ASSIGNED_P (((word *) ptr), index))))
hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
entry->key, TRUE, NULL);
return true;
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index ef347d6..78ca165 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -706,10 +706,12 @@ build_java_array_length_access (node)
length = java_array_type_length (type);
if (length >= 0)
return build_int_2 (length, 0);
- return fold (build1 (INDIRECT_REF, int_type_node,
- fold (build (PLUS_EXPR, ptr_type_node,
- java_check_reference (node, 1),
- JAVA_ARRAY_LENGTH_OFFSET(node)))));
+ node = build1 (INDIRECT_REF, int_type_node,
+ fold (build (PLUS_EXPR, ptr_type_node,
+ java_check_reference (node, 1),
+ JAVA_ARRAY_LENGTH_OFFSET(node))));
+ IS_ARRAY_LENGTH_ACCESS (node) = 1;
+ return fold (node);
}
/* Optionally checks a reference against the NULL pointer. ARG1: the
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index e2e8cf3..0ca0e3f 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -63,6 +63,7 @@ struct JCF;
4: IS_A_COMMAND_LINE_FILENAME_P (in IDENTIFIER_NODE)
RESOLVE_TYPE_NAME_P (in EXPR_WITH_FILE_LOCATION)
CALL_USING_SUPER (in CALL_EXPR)
+ IS_ARRAY_LENGTH_ACCESS (in INDIRECT_REF)
5: HAS_BEEN_ALREADY_PARSED_P (in IDENTIFIER_NODE)
IS_BREAK_STMT_P (in EXPR_WITH_FILE_LOCATION)
IS_CRAFTED_STRING_BUFFER_P (in CALL_EXPR)
@@ -92,6 +93,7 @@ struct JCF;
3: METHOD_FINAL (in FUNCTION_DECL)
FIELD_FINAL (in FIELD_DECL)
CLASS_FINAL (in TYPE_DECL)
+ DECL_FINAL (in any decl)
4: METHOD_SYNCHRONIZED (in FUNCTION_DECL).
LABEL_IN_SUBR (in LABEL_DECL)
CLASS_INTERFACE (in TYPE_DECL)
@@ -476,6 +478,7 @@ extern tree java_global_trees[JTI_MAX];
java_global_trees[JTI_FINIT_IDENTIFIER_NODE] /* "finit$" */
#define finit_leg_identifier_node \
java_global_trees[JTI_FINIT_LEG_IDENTIFIER_NODE] /* "$finit$" */
+/* FIXME "instinit$" and "finit$" should be merged */
#define instinit_identifier_node \
java_global_trees[JTI_INSTINIT_IDENTIFIER_NODE] /* "instinit$" */
#define void_signature_node \
@@ -740,11 +743,11 @@ struct lang_identifier
/* 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)
#define DECL_FIXED_CONSTRUCTOR_P(DECL) (DECL_LANG_SPECIFIC(DECL)->fixed_ctor)
+/* A constructor that calls this. */
+#define DECL_INIT_CALLS_THIS(DECL) (DECL_LANG_SPECIFIC(DECL)->init_calls_this)
+
/* True when DECL aliases an outer context local variable. */
#define FIELD_LOCAL_ALIAS(DECL) DECL_LANG_FLAG_6 (DECL)
@@ -824,29 +827,18 @@ struct lang_identifier
/* 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. */
+/* True if a final variable was initialized upon its declaration,
+ or (if a field) in an initializer. Set after definite assignment. */
#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. */
+/* True if NODE is a local variable final. */
+#define LOCAL_FINAL_P(NODE) (DECL_LANG_SPECIFIC (NODE) && DECL_FINAL (NODE))
+/* True if NODE is a final field. */
#define FINAL_VARIABLE_P(NODE) (FIELD_FINAL (NODE) && !FIELD_STATIC (NODE))
-/* True if NODE is a class final variable. */
+/* True if NODE is a class final field. */
#define CLASS_FINAL_VARIABLE_P(NODE) \
(FIELD_FINAL (NODE) && FIELD_STATIC (NODE))
/* True if NODE is a class initialization flag. This macro accesses
@@ -874,8 +866,9 @@ struct lang_identifier
/* For a local VAR_DECL, holds the index into a words bitstring that
specifies if this decl is definitively assigned.
- A DECL_BIT_INDEX of -1 means we no longer care. */
-#define DECL_BIT_INDEX(DECL) (DECL_CHECK (DECL)->decl.u2.i)
+ The value -1 means the variable has been definitely assigned (and not
+ definitely unassigned). The value -2 means we already reported an error. */
+#define DECL_BIT_INDEX(DECL) (DECL_CHECK (DECL)->decl.pointer_alias_set)
/* DECL_LANG_SPECIFIC for FUNCTION_DECLs. */
struct lang_decl
@@ -899,10 +892,11 @@ struct lang_decl
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 synthetic_ctor : 1; /* Nonzero if this is a synthetic ctor */
- int init_final : 1; /* Nonzero all finals are initialized */
- int fixed_ctor : 1;
+ unsigned int native : 1; /* Nonzero if this is a native method */
+ unsigned int synthetic_ctor : 1; /* Nonzero if this is a synthetic ctor */
+ unsigned int init_final : 1; /* Nonzero all finals are initialized */
+ unsigned int fixed_ctor : 1;
+ unsigned int init_calls_this : 1;
};
/* init_test_table hash table entry structure. */
@@ -922,11 +916,8 @@ struct lang_decl_var
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 */
- int cif : 1; /* True: decl is a class initialization flag */
+ unsigned int final_iud : 1; /* Final initialized upon declaration */
+ unsigned int cif : 1; /* True: decl is a class initialization flag */
};
/* Macro to access fields in `struct lang_type'. */
@@ -954,7 +945,6 @@ struct lang_decl_var
#define TYPE_IMPORT_DEMAND_LIST(T) (TYPE_LANG_SPECIFIC(T)->import_demand_list)
#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)->hfv)
struct lang_type
{
@@ -974,7 +964,6 @@ struct lang_type
tree import_demand_list; /* Imported types, in the CU of this class */
unsigned pic:1; /* Private Inner Class. */
unsigned poic:1; /* Protected Inner Class. */
- unsigned hfv:1; /* Has final variables */
};
#ifdef JAVA_USE_HANDLES
@@ -1106,7 +1095,7 @@ extern void parse_error_context PARAMS ((tree cl, const char *, ...))
ATTRIBUTE_PRINTF_2;
extern void finish_class PARAMS ((void));
extern void java_layout_seen_class_methods PARAMS ((void));
-extern unsigned int check_for_initialization PARAMS ((tree));
+extern void check_for_initialization PARAMS ((tree, tree));
extern tree pushdecl_top_level PARAMS ((tree));
extern int alloc_class_constant PARAMS ((tree));
@@ -1195,13 +1184,15 @@ struct rtx_def * java_lang_expand_expr PARAMS ((tree, rtx, enum machine_mode,
enum expand_modifier));
#endif /* TREE_CODE && RTX_CODE && HAVE_MACHINE_MODES && ARGS_SIZE_RTX */
+#define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
+
/* Access flags etc for a method (a FUNCTION_DECL): */
#define METHOD_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL)
#define METHOD_PRIVATE(DECL) TREE_PRIVATE (DECL)
#define METHOD_PROTECTED(DECL) TREE_PROTECTED (DECL)
#define METHOD_STATIC(DECL) DECL_LANG_FLAG_2 (DECL)
-#define METHOD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
+#define METHOD_FINAL(DECL) DECL_FINAL (DECL)
#define METHOD_SYNCHRONIZED(DECL) DECL_LANG_FLAG_4 (DECL)
#define METHOD_NATIVE(DECL) (DECL_LANG_SPECIFIC(DECL)->native)
#define METHOD_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL)
@@ -1239,14 +1230,14 @@ struct rtx_def * java_lang_expand_expr PARAMS ((tree, rtx, enum machine_mode,
#define FIELD_PROTECTED(DECL) TREE_PROTECTED (DECL)
#define FIELD_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL)
#define FIELD_STATIC(DECL) TREE_STATIC (DECL)
-#define FIELD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
+#define FIELD_FINAL(DECL) DECL_FINAL (DECL)
#define FIELD_VOLATILE(DECL) DECL_LANG_FLAG_4 (DECL)
#define FIELD_TRANSIENT(DECL) DECL_LANG_FLAG_5 (DECL)
/* Access flags etc for a class (a TYPE_DECL): */
#define CLASS_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL)
-#define CLASS_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
+#define CLASS_FINAL(DECL) DECL_FINAL (DECL)
#define CLASS_INTERFACE(DECL) DECL_LANG_FLAG_4 (DECL)
#define CLASS_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL)
#define CLASS_SUPER(DECL) DECL_LANG_FLAG_6 (DECL)
@@ -1350,6 +1341,9 @@ extern tree *type_map;
/* True iff TYPE is a Java array type. */
#define TYPE_ARRAY_P(TYPE) TYPE_LANG_FLAG_1 (TYPE)
+/* True for an INDIRECT_REF created from a 'ARRAY.length' operation. */
+#define IS_ARRAY_LENGTH_ACCESS(NODE) TREE_LANG_FLAG_4 (NODE)
+
/* If FUNCTION_TYPE or METHOD_TYPE: cache for build_java_argument_signature. */
#define TYPE_ARGUMENT_SIGNATURE(TYPE) TYPE_VFIELD(TYPE)
@@ -1610,9 +1604,10 @@ extern tree *type_map;
/* True when we can perform static class initialization optimization */
#define STATIC_CLASS_INIT_OPT_P() \
- (flag_optimize_sci && (optimize >= 2) && ! flag_emit_class_files)
+ 0 /* ??? Temporarily turn off this optimization -PB */
+/* (flag_optimize_sci && (optimize >= 2) && ! flag_emit_class_files)*/
-extern int java_error_count; \
+extern int java_error_count;
/* Make the current function where this macro is invoked report error
messages and and return, if any */
diff --git a/gcc/java/parse.y b/gcc/java/parse.y
index 608ec91..11318be 100644
--- a/gcc/java/parse.y
+++ b/gcc/java/parse.y
@@ -101,12 +101,6 @@ static int process_imports PARAMS ((void));
static void read_import_dir PARAMS ((tree));
static int find_in_imports_on_demand PARAMS ((tree, tree));
static void find_in_imports PARAMS ((tree, 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, bool));
static void register_package PARAMS ((tree));
@@ -163,7 +157,6 @@ static tree build_method_invocation PARAMS ((tree, tree));
static tree build_new_invocation PARAMS ((tree, tree));
static tree build_assignment PARAMS ((int, int, tree, tree));
static tree build_binop PARAMS ((enum tree_code, int, tree, tree));
-static int check_final_assignment PARAMS ((tree ,tree));
static tree patch_assignment PARAMS ((tree, tree));
static tree patch_binop PARAMS ((tree, tree, tree));
static tree build_unaryop PARAMS ((int, int, tree));
@@ -415,7 +408,7 @@ static tree wpv_id;
/* The list of all packages we've seen so far */
static tree package_list = NULL_TREE;
-/* Hold THIS for the scope of the current public method decl. */
+/* Hold THIS for the scope of the current method decl. */
static tree current_this;
/* Hold a list of catch clauses list. The first element of this list is
@@ -4351,14 +4344,12 @@ register_fields (flags, type, variable_list)
/* 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
+ initialized upon its 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,
@@ -7273,7 +7264,7 @@ declare_local_variables (modifier, type, vlist)
will be entered */
decl = build_decl (VAR_DECL, name, real_type);
MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
- LOCAL_FINAL (decl) = final_p;
+ DECL_FINAL (decl) = final_p;
BLOCK_CHAIN_DECL (decl);
/* If doing xreferencing, replace the line number with the WFL
@@ -7348,11 +7339,11 @@ source_start_java_method (fndecl)
parm_decl = build_decl (PARM_DECL, name, type);
/* Remember if a local variable was declared final (via its
- TREE_LIST of type/name.) Set LOCAL_FINAL accordingly. */
+ TREE_LIST of type/name.) Set DECL_FINAL accordingly. */
if (ARG_FINAL_P (tem))
{
MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (parm_decl);
- LOCAL_FINAL (parm_decl) = 1;
+ DECL_FINAL (parm_decl) = 1;
}
BLOCK_CHAIN_DECL (parm_decl);
@@ -7658,14 +7649,6 @@ 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 ();
@@ -7700,16 +7683,8 @@ 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);
}
@@ -7741,17 +7716,10 @@ 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 */
@@ -7766,15 +7734,6 @@ 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;
}
@@ -8052,25 +8011,27 @@ java_complete_expand_method (mdecl)
if (! flag_emit_xref && ! METHOD_NATIVE (mdecl))
{
- unsigned int state = check_for_initialization (block_body);
+ check_for_initialization (block_body, mdecl);
/* Go through all the flags marking the initialization of
static variables and see whether they're definitively
assigned, in which case the type is remembered as
definitively initialized in MDECL. */
+ /* FIXME this doesn't work state is too short.
if (STATIC_CLASS_INIT_OPT_P ())
{
hash_traverse (&DECL_FUNCTION_INIT_TEST_TABLE (mdecl),
attach_initialized_static_class, (PTR)&state);
- /* Always register the context as properly initialized in
+ / * Always register the context as properly initialized in
MDECL. This used with caution helps removing extra
- initialization of self. */
+ initialization of self. * /
if (METHOD_STATIC (mdecl))
hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (mdecl),
(hash_table_key) DECL_CONTEXT (mdecl),
TRUE, NULL);
}
+ */
}
ctxp->explicit_constructor_p = 0;
}
@@ -8292,14 +8253,6 @@ outer_field_access_fix (wfl, node, rhs)
if (outer_field_expanded_access_p (node, &name, &arg_type, &arg))
{
- /* At any rate, check whether we're trying to assign a value to
- a final. */
- tree accessed = (JDECL_P (node) ? node :
- (TREE_CODE (node) == COMPONENT_REF ?
- TREE_OPERAND (node, 1) : node));
- if (check_final_assignment (accessed, wfl))
- return error_mark_node;
-
node = build_outer_field_access_expr (EXPR_WFL_LINECOL (wfl),
arg_type, name, arg, rhs);
return java_complete_tree (node);
@@ -8886,6 +8839,8 @@ fix_constructors (mdecl)
TREE_OPERAND (found_call, 0) = empty_stmt_node;
}
+ DECL_INIT_CALLS_THIS (mdecl) = invokes_this;
+
/* Insert the instance initializer block right after. */
if (!invokes_this && (iii = build_instinit_invocation (class_type)))
compound = add_stmt_to_compound (compound, NULL_TREE, iii);
@@ -11457,8 +11412,8 @@ java_complete_tree (node)
DECL_INITIAL (node) = value;
if (value != NULL_TREE)
{
- /* fold_constant_for_init sometimes widen the original type
- of the constant (i.e. byte to int.) It's not desirable,
+ /* fold_constant_for_init sometimes widens the original type
+ of the constant (i.e. byte to int). It's not desirable,
especially if NODE is a function argument. */
if ((TREE_CODE (value) == INTEGER_CST
|| TREE_CODE (value) == REAL_CST)
@@ -11467,8 +11422,6 @@ java_complete_tree (node)
else
return value;
}
- else
- DECL_FIELD_FINAL_IUD (node) = 0;
}
return node;
}
@@ -11662,7 +11615,7 @@ java_complete_lhs (node)
TREE_OPERAND (cn, 1));
}
/* Accept final locals too. */
- else if (TREE_CODE (cn) == VAR_DECL && LOCAL_FINAL (cn))
+ else if (TREE_CODE (cn) == VAR_DECL && DECL_FINAL (cn))
cn = fold_constant_for_init (DECL_INITIAL (cn), cn);
if (!TREE_CONSTANT (cn) && !flag_emit_xref)
@@ -11972,13 +11925,12 @@ java_complete_lhs (node)
DECL_INITIAL (nn) = patched;
else
DECL_INITIAL (nn) = TREE_OPERAND (node, 1);
+ DECL_FIELD_FINAL_IUD (nn) = 1;
return empty_stmt_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);
@@ -12056,9 +12008,6 @@ java_complete_lhs (node)
}
else
{
- /* Can't assign to a (blank) final. */
- if (check_final_assignment (TREE_OPERAND (node, 0), wfl_op1))
- return error_mark_node;
node = patch_assignment (node, wfl_op1);
/* Reorganize the tree if necessary. */
if (flag && (!JREFERENCE_TYPE_P (TREE_TYPE (node))
@@ -12541,271 +12490,9 @@ print_int_node (node)
}
-
-/* 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 been 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 > 0)
- 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)
- abort ();
- 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;
- int error_found = 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");
- error_found = 1;
- }
- }
- 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 a natural ctor in which the field could have been
- initialized or we found an error looking for one. */
- && (error_found || !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. */
-static int
-check_final_assignment (lvalue, wfl)
- tree lvalue, wfl;
-{
- 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);
-
- 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))
- {
- DECL_FIELD_FINAL_IUD (lvalue) = 1;
- 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;
-}
-
/* 15.25 Assignment operators. */
static tree
@@ -12844,15 +12531,7 @@ patch_assignment (node, wfl_op1)
else if (TREE_CODE (wfl_op1) == EXPR_WITH_FILE_LOCATION
&& resolve_expression_name (wfl_op1, &llvalue))
{
- if (!error_found && check_final_assignment (llvalue, wfl_op1))
- {
- /* What we should do instead is resetting the all the flags
- previously set, exchange lvalue for llvalue and continue. */
- error_found = 1;
- return error_mark_node;
- }
- else
- lhs_type = TREE_TYPE (lvalue);
+ lhs_type = TREE_TYPE (lvalue);
}
else
{
@@ -13003,7 +12682,7 @@ patch_assignment (node, wfl_op1)
/* Final locals can be used as case values in switch
statement. Prepare them for this eventuality. */
if (TREE_CODE (lvalue) == VAR_DECL
- && LOCAL_FINAL_P (lvalue)
+ && DECL_FINAL (lvalue)
&& TREE_CONSTANT (new_rhs)
&& IDENTIFIER_LOCAL_VALUE (DECL_NAME (lvalue))
&& JINTEGRAL_TYPE_P (TREE_TYPE (lvalue))
@@ -14267,26 +13946,14 @@ patch_unaryop (node, wfl_op)
&& TREE_OPERAND (decl, 1)
&& (TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)))
{
- tree lvalue;
- /* Before screaming, check that we're not in fact trying to
- increment a optimized static final access, in which case
- we issue an different error message. */
- if (!(TREE_CODE (wfl_op) == EXPR_WITH_FILE_LOCATION
- && resolve_expression_name (wfl_op, &lvalue)
- && check_final_assignment (lvalue, wfl_op)))
- parse_error_context (wfl_operator, "Invalid argument to `%s'",
- operator_string (node));
TREE_TYPE (node) = error_mark_node;
error_found = 1;
}
- if (check_final_assignment (op, wfl_op))
- error_found = 1;
-
/* From now on, we know that op if a variable and that it has a
valid wfl. We use wfl_op to locate errors related to the
++/-- operand. */
- else if (!JNUMERIC_TYPE_P (op_type))
+ if (!JNUMERIC_TYPE_P (op_type))
{
parse_error_context
(wfl_op, "Invalid argument type `%s' to `%s'",
@@ -16171,8 +15838,6 @@ 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: