check-init.c: Handle definite unassignment to finals in addition to definite assignment.

* check-init.c:   Handle definite unassignment to finals in addition
	to definite assignment.		[see ChangeLog]

From-SVN: r47619
This commit is contained in:
Per Bothner 2001-12-04 11:30:13 -08:00 committed by Per Bothner
parent ff52499130
commit 4f88ccda2d
5 changed files with 446 additions and 479 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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: