diff options
author | Per Bothner <per@bothner.com> | 2001-12-04 11:30:13 -0800 |
---|---|---|
committer | Per Bothner <bothner@gcc.gnu.org> | 2001-12-04 11:30:13 -0800 |
commit | 4f88ccda2d6bba5651d3203aa88f88651b6e7ed2 (patch) | |
tree | 82756fc6205d2820616c3ac0ac02c08fdafcd100 /gcc/java/check-init.c | |
parent | ff524991302f07788509c6d81b505bf45f94260e (diff) | |
download | gcc-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.c | 416 |
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; |