aboutsummaryrefslogtreecommitdiff
path: root/gcc/java/check-init.c
diff options
context:
space:
mode:
authorPer Bothner <per@bothner.com>2001-12-04 11:30:13 -0800
committerPer Bothner <bothner@gcc.gnu.org>2001-12-04 11:30:13 -0800
commit4f88ccda2d6bba5651d3203aa88f88651b6e7ed2 (patch)
tree82756fc6205d2820616c3ac0ac02c08fdafcd100 /gcc/java/check-init.c
parentff524991302f07788509c6d81b505bf45f94260e (diff)
downloadgcc-4f88ccda2d6bba5651d3203aa88f88651b6e7ed2.zip
gcc-4f88ccda2d6bba5651d3203aa88f88651b6e7ed2.tar.gz
gcc-4f88ccda2d6bba5651d3203aa88f88651b6e7ed2.tar.bz2
check-init.c: Handle definite unassignment to finals in addition to definite assignment.
* check-init.c: Handle definite unassignment to finals in addition to definite assignment. [see ChangeLog] From-SVN: r47619
Diffstat (limited to 'gcc/java/check-init.c')
-rw-r--r--gcc/java/check-init.c416
1 files changed, 334 insertions, 82 deletions
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;