diff options
Diffstat (limited to 'gcc/java')
-rw-r--r-- | gcc/java/ChangeLog | 53 | ||||
-rw-r--r-- | gcc/java/check-init.c | 416 | ||||
-rw-r--r-- | gcc/java/expr.c | 10 | ||||
-rw-r--r-- | gcc/java/java-tree.h | 73 | ||||
-rw-r--r-- | gcc/java/parse.y | 373 |
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: |