diff options
author | Tom Tromey <tromey@gcc.gnu.org> | 2007-01-09 19:58:05 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2007-01-09 19:58:05 +0000 |
commit | 97b8365cafc3a344a22d3980b8ed885f5c6d8357 (patch) | |
tree | 996a5f57d4a68c53473382e45cb22f574cb3e4db /gcc/java/check-init.c | |
parent | c648dedbde727ca3f883bb5fd773aa4af70d3369 (diff) | |
download | gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.zip gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.tar.gz gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.tar.bz2 |
Merged gcj-eclipse branch to trunk.
From-SVN: r120621
Diffstat (limited to 'gcc/java/check-init.c')
-rw-r--r-- | gcc/java/check-init.c | 1032 |
1 files changed, 0 insertions, 1032 deletions
diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c deleted file mode 100644 index 4aca992..0000000 --- a/gcc/java/check-init.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* Code to test for "definitive [un]assignment". - Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free Software Foundation, - Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. - -Java and all Java-based marks are trademarks or registered trademarks -of Sun Microsystems, Inc. in the United States and other countries. -The Free Software Foundation is independent of Sun Microsystems, Inc. */ - -/* Written by Per Bothner <bothner@cygnus.com>, January 1999. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "flags.h" /* Needed for optimize. */ -#include "java-tree.h" -#include "toplev.h" /* Needed for fatal. */ - -/* The basic idea is that we assign each local variable declaration - 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 (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; - -/* Pointer to a bitstring. */ -typedef word *words; - -/* Number of locals variables currently active. */ -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. - - The variables whose DECL_BIT_INDEX are in the range from - start_current_locals (inclusive) up to num_current_locals (exclusive) - are declared in the "current" block. If there is a loop or branch - form, we set start_current_locals to num_current_locals to indicate - there is no current block. - - The point is that if a variable in the current block is set, - there are no other control paths that we have to worry about. - Hence, we can remove it from the set of variables we are - checking, making its bit index available for some other variable. - For simplicity, we only do that if the variable's bit index - is (num_current_locals-1); freeing up its bit index is then - just a simple matter of decrementing num_current_locals. - The reason this is worth doing is that it is simple, and - allows us to use short (usually one-word) bit-strings, - even for methods with thousands of local variables, as - long as most of them are initialized immediately after or in - their declaration. */ -static int start_current_locals = 0; - -static int num_current_words; - -#define COPYN(DST, SRC, NWORDS) memcpy (DST, SRC, NWORDS * sizeof(word)) -#define COPY(DST, SRC) COPYN (DST, SRC, num_current_words) - -#define SET_ALL(DST) memset (DST, ~0, num_current_words * sizeof(word)) -#define CLEAR_ALL(DST) memset (DST, 0, num_current_words * sizeof(word)) - -#define INTERSECTN(DST, SRC1, SRC2, N) \ - do { int n = N; \ - while (--n >= 0) DST[n] = SRC1[n] & SRC2[n]; \ - } while (0) - -#define UNION(DST, SRC1, SRC2) \ - UNIONN (DST, SRC1, SRC2, num_current_words) - -#define UNIONN(DST, SRC1, SRC2, N) \ - do { int n = N; \ - while (--n >= 0) DST[n] = SRC1[n] | SRC2[n]; \ - } while (0) - -#define INTERSECT(DST, SRC1, SRC2) \ - INTERSECTN (DST, SRC1, SRC2, num_current_words) - -#define WORD_SIZE ((unsigned int)(sizeof(word) * BITS_PER_UNIT)) - -static void check_bool_init (tree, words, words, words); -static void check_init (tree, words); -static void check_cond_init (tree, tree, tree, words, words, words); -static void check_bool2_init (enum tree_code, tree, tree, words, words, words); -struct alternatives; -static void done_alternative (words, struct alternatives *); -static tree get_variable_decl (tree); -static void final_assign_error (tree); -static void check_final_reassigned (tree, words); - -#define ALLOC_WORDS(NUM) (xmalloc ((NUM) * sizeof (word))) -#define FREE_WORDS(PTR) (free (PTR)) - -/* 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))) - -#define CLEAR_BIT(WORDS, BIT) \ - (WORDS[(BIT) / WORD_SIZE] &= ~ (1 << ((BIT) % WORD_SIZE))) - -#define SET_BIT(WORDS, BIT) \ - (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 (tree exp) -{ - /* A static field can be wrapped in a COMPOUND_EXPR where the first - argument initializes the class. */ - if (TREE_CODE (exp) == COMPOUND_EXPR) - exp = extract_field_decl (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; - } - } - else if (TREE_CODE (exp) == INDIRECT_REF) - { - /* For indirect dispatch, look for an expression of the form - (indirect_ref (+ (array_ref otable <N>) this)). - FIXME: it would probably be better to generate a JAVA_FIELD_REF - expression that gets converted to OTABLE access at - gimplification time. */ - exp = TREE_OPERAND (exp, 0); - if (TREE_CODE (exp) == PLUS_EXPR) - { - tree op0 = TREE_OPERAND (exp, 0); - STRIP_NOPS (op0); - if (TREE_CODE (op0) == ARRAY_REF) - { - tree table = TREE_OPERAND (op0, 0); - if (TREE_CODE (table) == VAR_DECL - && DECL_LANG_SPECIFIC (table) - && DECL_OWNER (table) - && TYPE_OTABLE_DECL (DECL_OWNER (table)) == table) - { - HOST_WIDE_INT index - = TREE_INT_CST_LOW (TREE_OPERAND (op0, 1)); - tree otable_methods - = TYPE_OTABLE_METHODS (DECL_OWNER (table)); - tree element; - for (element = otable_methods; - element; - element = TREE_CHAIN (element)) - { - if (index == 1) - { - tree purpose = TREE_PURPOSE (element); - if (TREE_CODE (purpose) == FIELD_DECL) - return purpose; - else - return NULL_TREE; - } - --index; - } - } - } - } - } - - return NULL_TREE; -} - -static void -final_assign_error (tree name) -{ - error ("Can't reassign a value to the final variable %qs", - IDENTIFIER_POINTER (name)); -} - -static void -check_final_reassigned (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. */ - || (DECL_LOCAL_FINAL_IUD (decl) ? ASSIGNED_P (before, index) - : ! UNASSIGNED_P (before, index)))) - { - final_assign_error (DECL_NAME (decl)); - } -} - -/* Check a conditional form (TEST_EXP ? THEN_EXP : ELSE_EXP) for - definite [un]assignment. - BEFORE, WHEN_FALSE, and WHEN_TRUE are as in check_bool_init. */ - -static void -check_cond_init (tree test_exp, tree then_exp, tree else_exp, - words before, words when_false, words when_true) -{ - 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); - RELEASE_BUFFERS(test_false); - start_current_locals = save_start_current_locals; -} - -/* Check a boolean binary form CODE (EXP0, EXP1), - where CODE is one of EQ_EXPR, BIT_AND_EXPR, or BIT_IOR_EXPR. - BEFORE, WHEN_FALSE, and WHEN_TRUE are as in check_bool_init. */ - -static void -check_bool2_init (enum tree_code code, tree exp0, tree exp1, - words before, words when_false, words when_true) -{ - 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; - words when_true_0 = tmp+2*num_current_words; - words when_true_1 = tmp+3*num_current_words; - check_bool_init (exp0, before, when_false_0, when_true_0); - INTERSECT (before, when_false_0, when_true_0); - check_bool_init (exp1, before, when_false_1, when_true_1); - - INTERSECT (before, when_false_1, when_true_1); - - if (code == EQ_EXPR) - { - /* Now set: - * when_true = (when_false_1 INTERSECTION when_true_1) - * UNION (when_true_0 INTERSECTION when_false_1) - * UNION (when_false_0 INTERSECTION when_true_1); - * using when_false and before as temporary working areas. */ - INTERSECT (when_true, when_true_0, when_false_1); - INTERSECT (when_false, when_true_0, when_false_1); - UNION (when_true, when_true, when_false); - UNION (when_true, when_true, before); - - /* Now set: - * when_false = (when_false_1 INTERSECTION when_true_1) - * UNION (when_true_0 INTERSECTION when_true_1) - * UNION (when_false_0 INTERSECTION when_false_1); - * using before as a temporary working area. */ - INTERSECT (when_false, when_true_0, when_true_1); - UNION (when_false, when_false, before); - INTERSECT (before, when_false_0, when_false_1); - UNION (when_false, when_false, before); - } - else if (code == BIT_AND_EXPR || code == TRUTH_AND_EXPR) - { - UNION (when_true, when_true_0, when_true_1); - INTERSECT (when_false, when_false_0, when_false_1); - UNION (when_false, when_false, before); - } - else /* if (code == BIT_IOR_EXPR || code == TRUTH_OR_EXPR) */ - { - UNION (when_false, when_false_0, when_false_1); - INTERSECT (when_true, when_true_0, when_true_1); - UNION (when_true, when_true, before); - } - - if (tmp != buf) - FREE_WORDS (tmp); -} - -/* 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 [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 - be used as temporary working areas. */ - -static void -check_bool_init (tree exp, words before, words when_false, words when_true) -{ - switch (TREE_CODE (exp)) - { - case COND_EXPR: - check_cond_init (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), - TREE_OPERAND (exp, 2), - before, when_false, when_true); - return; - - case TRUTH_ANDIF_EXPR: - check_cond_init (TREE_OPERAND (exp, 0), - TREE_OPERAND (exp, 1), boolean_false_node, - before, when_false, when_true); - return; - case TRUTH_ORIF_EXPR: - check_cond_init (TREE_OPERAND (exp, 0), - boolean_true_node, TREE_OPERAND (exp, 1), - before, when_false, when_true); - return; - case TRUTH_NOT_EXPR: - check_bool_init (TREE_OPERAND (exp, 0), before, when_true, when_false); - return; - - case BIT_AND_EXPR: - case BIT_IOR_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case EQ_EXPR: - check_bool2_init (TREE_CODE (exp), - TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), - before, when_false, when_true); - return; - - case TRUTH_XOR_EXPR: - case BIT_XOR_EXPR: - case NE_EXPR: - /* Just like EQ_EXPR, but switch when_true and when_false. */ - check_bool2_init (EQ_EXPR, TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), - before, when_true, when_false); - - return; - - case INTEGER_CST: - if (integer_zerop (exp)) - { - SET_ALL (when_true); - COPY (when_false, before); - } - else - { - SET_ALL (when_false); - COPY (when_true, before); - } - break; - - default: - check_init (exp, before); - COPY (when_false, before); - COPY (when_true, before); - } -} - -/* Used to keep track of control flow branches. */ - -struct alternatives -{ - struct alternatives *outer; - - /* The value of num_current_locals at the start of this compound. */ - int num_locals; - - /* The value of the "before" set at the start of the control structure. - Used for SWITCH_EXPR but not set for LABELED_BLOCK_EXPR. */ - words saved; - - int save_start_current_locals; - - /* If num_current_words==1, combined==&one_word, for efficiency. */ - word one_word; - - /* The intersection of the "after" sets from previous branches. */ - words combined; - - tree block; -}; - -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; \ - current.num_locals = num_current_locals; \ - current.combined = num_current_words <= 1 ? ¤t.one_word \ - : ALLOC_WORDS (num_current_words); \ - SET_ALL (current.combined); \ - current.outer = alternatives; \ - alternatives = ¤t; \ - current.save_start_current_locals = start_current_locals; \ - 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 (words after, struct alternatives *current) -{ - INTERSECTN (current->combined, current->combined, after, - 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; \ - COPY (after, current.combined); \ - if (current.combined != ¤t.one_word) \ - FREE_WORDS (current.combined); \ - start_current_locals = current.save_start_current_locals; \ -} - -/* Check for (un)initialized local variables in EXP. */ - -static void -check_init (tree exp, words before) -{ - tree tmp; - location_t save_location = input_location; - again: - if (EXPR_HAS_LOCATION (exp)) - input_location = EXPR_LOCATION (exp); - switch (TREE_CODE (exp)) - { - case VAR_DECL: - 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 class - initialization flags. */ - if (! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp) - && index >= 0 && ! ASSIGNED_P (before, index)) - { - error ("variable %qD may not have been initialized", exp); - 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)) - { - error ("variable %qD may not have been initialized", 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 ((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); - if (index >= 0) - { - 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 () /* FIXME */ - && ! DECL_FINAL (tmp) - && index >= start_current_locals - && index == num_current_locals - 1) - { - num_current_locals--; - DECL_BIT_INDEX (tmp) = -1; - } - 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) == COMPONENT_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: - if (BLOCK_EXPR_BODY (exp)) - { - tree decl = BLOCK_EXPR_DECLS (exp); - int words_needed; - word* tmp; - int i; - int save_start_current_locals = start_current_locals; - int save_num_current_words = num_current_words; - start_current_locals = num_current_locals; - for (; decl != NULL_TREE; decl = TREE_CHAIN (decl)) - { - DECL_BIT_INDEX (decl) = num_current_locals++; - } - words_needed = WORDS_NEEDED (2 * num_current_locals); - if (words_needed > num_current_words) - { - tmp = ALLOC_WORDS (words_needed); - COPY (tmp, before); - num_current_words = words_needed; - } - else - tmp = before; - for (i = start_current_locals; i < num_current_locals; i++) - { - CLEAR_ASSIGNED (tmp, i); - SET_UNASSIGNED (tmp, i); - } - check_init (BLOCK_EXPR_BODY (exp), 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)) - { - if (LOCAL_CLASS_INITIALIZATION_FLAG_P (decl)) - { - int index = DECL_BIT_INDEX (decl); - tree fndecl = DECL_CONTEXT (decl); - if (fndecl && METHOD_STATIC (fndecl) - && (DECL_INITIAL (decl) == boolean_true_node - || (index >= 0 && ASSIGNED_P (tmp, index)))) - *(htab_find_slot - (DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl), - DECL_FUNCTION_INIT_TEST_CLASS (decl), INSERT)) = - DECL_FUNCTION_INIT_TEST_CLASS (decl); - } - DECL_BIT_INDEX (decl) = -1; - } - - num_current_locals = start_current_locals; - start_current_locals = save_start_current_locals; - if (tmp != before) - { - num_current_words = save_num_current_words; - COPY (before, tmp); - FREE_WORDS (tmp); - } - } - 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; - break; - } - case EXIT_EXPR: - { - struct alternatives *alt = alternatives; - DECLARE_BUFFERS(when_true, 2); - words when_false = when_true + num_current_words; -#ifdef ENABLE_JC1_CHECKING - gcc_assert (TREE_CODE (alt->block) == LOOP_EXPR); -#endif - check_bool_init (TREE_OPERAND (exp, 0), before, when_false, when_true); - done_alternative (when_true, alt); - COPY (before, when_false); - RELEASE_BUFFERS(when_true); - break; - } - case LABELED_BLOCK_EXPR: - { - struct alternatives alt; - BEGIN_ALTERNATIVES (before, alt); - alt.block = exp; - if (LABELED_BLOCK_BODY (exp)) - check_init (LABELED_BLOCK_BODY (exp), before); - done_alternative (before, &alt); - END_ALTERNATIVES (before, alt); - break; - } - case EXIT_BLOCK_EXPR: - { - tree block = TREE_OPERAND (exp, 0); - struct alternatives *alt = alternatives; - while (alt->block != block) - alt = alt->outer; - done_alternative (before, alt); - SET_ALL (before); - break; - } - case SWITCH_EXPR: - { - struct alternatives alt; - word buf[2]; - check_init (TREE_OPERAND (exp, 0), before); - BEGIN_ALTERNATIVES (before, alt); - 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); - if (! SWITCH_HAS_DEFAULT (exp)) - done_alternative (alt.saved, &alt); - FREE_BUFFER(alt.saved, buf); - END_ALTERNATIVES (before, alt); - break; - } - case CASE_EXPR: - case DEFAULT_EXPR: - { - int i; - struct alternatives *alt = alternatives; - while (TREE_CODE (alt->block) != SWITCH_EXPR) - alt = alt->outer; - COPYN (before, alt->saved, WORDS_NEEDED (2 * alt->num_locals)); - for (i = alt->num_locals; i < num_current_locals; i++) - CLEAR_ASSIGNED (before, i); - break; - } - - case TRY_EXPR: - { - tree try_clause = TREE_OPERAND (exp, 0); - tree clause = TREE_OPERAND (exp, 1); - 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); - COPY (tmp, save); - check_init (try_clause, tmp); - done_alternative (tmp, &alt); - for ( ; clause != NULL_TREE; clause = TREE_CHAIN (clause)) - { - tree catch_clause = TREE_OPERAND (clause, 0); - COPY (tmp, save); - check_init (catch_clause, tmp); - done_alternative (tmp, &alt); - } - if (tmp != buf) - { - FREE_WORDS (tmp); - } - END_ALTERNATIVES (before, alt); - } - break; - - case TRY_FINALLY_EXPR: - { - 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); - RELEASE_BUFFERS(tmp); - } - break; - - case RETURN_EXPR: - case THROW_EXPR: - if (TREE_OPERAND (exp, 0)) - check_init (TREE_OPERAND (exp, 0), before); - goto never_continues; - - case ERROR_MARK: - never_continues: - SET_ALL (before); - break; - - case COND_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - { - 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); - RELEASE_BUFFERS(when_true); - } - break; - - case NOP_EXPR: - if (IS_EMPTY_STMT (exp)) - break; - /* ... else fall through ... */ - case UNARY_PLUS_EXPR: - case NEGATE_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_NOT_EXPR: - case BIT_NOT_EXPR: - case CONVERT_EXPR: - case VIEW_CONVERT_EXPR: - case BIT_FIELD_REF: - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - case INDIRECT_REF: - case ADDR_EXPR: - case NON_LVALUE_EXPR: - case INSTANCEOF_EXPR: - case ABS_EXPR: - /* Avoid needless recursion. */ - exp = TREE_OPERAND (exp, 0); - goto again; - - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - tmp = get_variable_decl (TREE_OPERAND (exp, 0)); - if (tmp != NULL_TREE && DECL_FINAL (tmp)) - final_assign_error (DECL_NAME (tmp)); - else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF) - { - /* Take care of array length accesses too. */ - tree decl = TREE_OPERAND (tmp, 1); - if (DECL_FINAL (decl)) - final_assign_error (DECL_NAME (decl)); - } - - /* Avoid needless recursion. */ - exp = TREE_OPERAND (exp, 0); - goto again; - - case SAVE_EXPR: - if (IS_INIT_CHECKED (exp)) - break; - IS_INIT_CHECKED (exp) = 1; - exp = TREE_OPERAND (exp, 0); - goto again; - - case COMPOUND_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case TRUNC_MOD_EXPR: - case RDIV_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case URSHIFT_EXPR: - case BIT_AND_EXPR: - case BIT_XOR_EXPR: - case BIT_IOR_EXPR: - case EQ_EXPR: - case NE_EXPR: - case GT_EXPR: - case GE_EXPR: - case LT_EXPR: - case LE_EXPR: - case MAX_EXPR: - case MIN_EXPR: - case ARRAY_REF: - case LROTATE_EXPR: - case RROTATE_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - case EXACT_DIV_EXPR: - case UNLT_EXPR: - case UNLE_EXPR: - case UNGT_EXPR: - case UNGE_EXPR: - case UNEQ_EXPR: - case LTGT_EXPR: - binop: - check_init (TREE_OPERAND (exp, 0), before); - /* Avoid needless recursion, especially for COMPOUND_EXPR. */ - exp = TREE_OPERAND (exp, 1); - goto again; - - case RESULT_DECL: - case FUNCTION_DECL: - case INTEGER_CST: - case REAL_CST: - case STRING_CST: - case DECL_EXPR: - case JAVA_EXC_OBJ_EXPR: - break; - - case NEW_CLASS_EXPR: - case CALL_EXPR: - { - tree func = TREE_OPERAND (exp, 0); - tree x = TREE_OPERAND (exp, 1); - if (TREE_CODE (func) == ADDR_EXPR) - func = TREE_OPERAND (func, 0); - check_init (func, before); - - for ( ; x != NULL_TREE; x = TREE_CHAIN (x)) - check_init (TREE_VALUE (x), before); - if (func == throw_node) - goto never_continues; - } - break; - - case NEW_ARRAY_INIT: - { - tree value; - unsigned HOST_WIDE_INT idx; - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)), - idx, value) - check_init (value, before); - } - break; - - case EXPR_WITH_FILE_LOCATION: - { - location_t saved_location = input_location; - tree body = EXPR_WFL_NODE (exp); - if (IS_EMPTY_STMT (body)) - break; -#ifdef USE_MAPPED_LOCATION - input_location = EXPR_LOCATION (exp); -#else - input_filename = EXPR_WFL_FILENAME (exp); - input_line = EXPR_WFL_LINENO (exp); -#endif - check_init (body, before); - input_location = saved_location; - } - break; - - default: - internal_error - ("internal error in check-init: tree code not implemented: %s", - tree_code_name [(int) TREE_CODE (exp)]); - } - input_location = save_location; -} - -void -check_for_initialization (tree body, tree mdecl) -{ - 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 ("%Jfinal field %qD may not have been initialized", - decl, decl); - } - 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; -} |