X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=gcc%2Fjava%2Fcheck-init.c;fp=gcc%2Fjava%2Fcheck-init.c;h=0000000000000000000000000000000000000000;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=679353355c890d83d8b1c66ee7cadd10ed240683;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c deleted file mode 100644 index 67935335..00000000 --- a/gcc/java/check-init.c +++ /dev/null @@ -1,1025 +0,0 @@ -/* 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 -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. - -This program 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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, 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 , January 1999. */ - -#include "config.h" -#include "system.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 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; - -static tree wfl; - -#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 PARAMS ((tree, words, words, words)); -static void check_init PARAMS ((tree, words)); -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)); - -#define ALLOC_WORDS(NUM) ((word*) 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 (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 reassign 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 [un]assignment. - BEFORE, WHEN_FALSE, and WHEN_TRUE are as in check_bool_init. */ - -static void -check_cond_init (test_exp, then_exp, else_exp, - before, when_false, when_true) - tree test_exp, then_exp, else_exp; - words before, when_false, 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 (code, exp0, exp1, before, when_false, when_true) - enum tree_code code; tree exp0, exp1; - words before, when_false, 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 (exp, before, when_false, when_true) - tree exp; - words before, when_false, 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 MODIFY_EXPR: - { - tree tmp = TREE_OPERAND (exp, 0); - 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_ASSIGNED (when_false, index); - SET_ASSIGNED (when_true, index); - CLEAR_UNASSIGNED (when_false, index); - CLEAR_UNASSIGNED (when_true, index); - } - break; - } - } - goto do_default; - - 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: - do_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 stucture. - 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 (after, current) - 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 (exp, before) - tree exp; - words before; -{ - tree tmp; - again: - 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)) - { - parse_error_context - (wfl, "Variable `%s' may not have been initialized", - IDENTIFIER_POINTER (DECL_NAME (exp))); - /* Suppress further errors. */ - 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 ((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 */ - && 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)))) - hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl), - DECL_FUNCTION_INIT_TEST_CLASS(decl), TRUE, NULL); - } - 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; - return; - } - case EXIT_EXPR: - { - struct alternatives *alt = alternatives; - 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 (); -#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); - return; - } - 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); - return; - } - 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); - return; - } - 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); - return; - } - 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); - } - return; - - 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); - } - return; - - 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); - return; - - 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 (exp == empty_stmt_node) - 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 BIT_FIELD_REF: - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - case INDIRECT_REF: - case ADDR_EXPR: - case NON_LVALUE_EXPR: - case INSTANCEOF_EXPR: - case FIX_CEIL_EXPR: - case FIX_FLOOR_EXPR: - case FIX_ROUND_EXPR: - case ABS_EXPR: - case FFS_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)); - - /* Avoid needless recursion. */ - exp = TREE_OPERAND (exp, 0); - goto again; - - case SAVE_EXPR: - if (IS_INIT_CHECKED (exp)) - return; - 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: - 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 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 x = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); - for ( ; x != NULL_TREE; x = TREE_CHAIN (x)) - check_init (TREE_VALUE (x), before); - } - break; - - case EXPR_WITH_FILE_LOCATION: - { - const char *saved_input_filename = input_filename; - tree saved_wfl = wfl; - tree body = EXPR_WFL_NODE (exp); - int saved_lineno = lineno; - if (body == empty_stmt_node) - break; - wfl = exp; - input_filename = EXPR_WFL_FILENAME (exp); - lineno = EXPR_WFL_LINENO (exp); - check_init (body, before); - input_filename = saved_input_filename; - lineno = saved_lineno; - wfl = saved_wfl; - } - break; - - default: - internal_error - ("internal error in check-init: tree code not implemented: %s", - tree_code_name [(int) TREE_CODE (exp)]); - } -} - -void -check_for_initialization (body, mdecl) - tree body, 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 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 - a method to consider whether the type indirectly described by ENTRY - is definitly initialized and thus remembered as such. */ - -bool -attach_initialized_static_class (entry, ptr) - struct hash_entry *entry; - PTR ptr; -{ - struct init_test_hash_entry *ite = (struct init_test_hash_entry *) entry; - tree fndecl = DECL_CONTEXT (ite->init_test_decl); - int index = DECL_BIT_INDEX (ite->init_test_decl); - - /* If the initializer flag has been definitly assigned (not taking - into account its first mandatory assignment which has been - already added but escaped analysis.) */ - if (fndecl && METHOD_STATIC (fndecl) - && (DECL_INITIAL (ite->init_test_decl) == boolean_true_node - || (index >= 0 && ASSIGNED_P (((word *) ptr), index)))) - hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl), - entry->key, TRUE, NULL); - return true; -}