#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "flags.h"
#include "java-tree.h"
#include "toplev.h"
typedef unsigned int word;
typedef word *words;
static int num_current_locals = 0;
static int loop_current_locals;
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))
#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)
static tree
get_variable_decl (tree exp)
{
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;
}
else if (TREE_CODE (exp) == PARM_DECL)
{
if (DECL_FINAL (exp))
return exp;
}
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)
{
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);
if (DECL_FINAL (decl) && index != -2
&& (index < loop_current_locals
|| (DECL_LOCAL_FINAL_IUD (decl) ? ASSIGNED_P (before, index)
: ! UNASSIGNED_P (before, index))))
{
final_assign_error (DECL_NAME (decl));
}
}
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;
}
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)
{
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);
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
{
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);
}
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:
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);
}
}
struct alternatives
{
struct alternatives *outer;
int num_locals;
words saved;
int save_start_current_locals;
word one_word;
words combined;
tree block;
};
struct alternatives * alternatives = NULL;
#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; \
}
static void
done_alternative (words after, struct alternatives *current)
{
INTERSECTN (current->combined, current->combined, after,
WORDS_NEEDED (2 * current->num_locals));
}
#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; \
}
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);
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);
DECL_BIT_INDEX (tmp) = -2;
}
}
break;
case MODIFY_EXPR:
tmp = TREE_OPERAND (exp, 0);
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);
}
if (! STATIC_CLASS_INIT_OPT_P ()
&& ! 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))
{
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);
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:
{
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;
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 FIX_CEIL_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case ABS_EXPR:
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)
{
tree decl = TREE_OPERAND (tmp, 1);
if (DECL_FINAL (decl))
final_assign_error (DECL_NAME (decl));
}
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);
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);
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;
DECL_BIT_INDEX (decl) = -1;
}
}
}
start_current_locals = num_current_locals = 0;
}