/* Code to test for "definitive [un]assignment".
- Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free Software Foundation,
+ Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
Java and all Java-based marks are trademarks or registered trademarks
of Sun Microsystems, Inc. in the United States and other countries.
/* The 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
+ is i is definitely assigned, and the (2*i=1)'th bit is set if
decl whose DECL_BIT_INDEX is i is definitely unassigned */
/* One segment of a bitstring. */
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)
static tree
get_variable_decl (tree exp)
{
+ /* A static field can be wrapped in a COMPOUND_EXPR where the first
+ argument initializes the class. */
+ if (TREE_CODE (exp) == COMPOUND_EXPR)
+ exp = extract_field_decl (exp);
+
if (TREE_CODE (exp) == VAR_DECL)
{
if (! TREE_STATIC (exp) || FIELD_FINAL (exp))
return op1;
}
}
+ else if (TREE_CODE (exp) == INDIRECT_REF)
+ {
+ /* For indirect dispatch, look for an expression of the form
+ (indirect_ref (+ (array_ref otable <N>) this)).
+ FIXME: it would probably be better to generate a JAVA_FIELD_REF
+ expression that gets converted to OTABLE access at
+ gimplification time. */
+ exp = TREE_OPERAND (exp, 0);
+ if (TREE_CODE (exp) == PLUS_EXPR)
+ {
+ tree op0 = TREE_OPERAND (exp, 0);
+ STRIP_NOPS (op0);
+ if (TREE_CODE (op0) == ARRAY_REF)
+ {
+ tree table = TREE_OPERAND (op0, 0);
+ if (TREE_CODE (table) == VAR_DECL
+ && DECL_LANG_SPECIFIC (table)
+ && DECL_OWNER (table)
+ && TYPE_OTABLE_DECL (DECL_OWNER (table)) == table)
+ {
+ HOST_WIDE_INT index
+ = TREE_INT_CST_LOW (TREE_OPERAND (op0, 1));
+ tree otable_methods
+ = TYPE_OTABLE_METHODS (DECL_OWNER (table));
+ tree element;
+ for (element = otable_methods;
+ element;
+ element = TREE_CHAIN (element))
+ {
+ if (index == 1)
+ {
+ tree purpose = TREE_PURPOSE (element);
+ if (TREE_CODE (purpose) == FIELD_DECL)
+ return purpose;
+ else
+ return NULL_TREE;
+ }
+ --index;
+ }
+ }
+ }
+ }
+ }
+
return NULL_TREE;
}
static void
final_assign_error (tree name)
{
- static const char format[]
- = "can't reassign a value to the final variable '%s'";
- parse_error_context (wfl, format, IDENTIFIER_POINTER (name));
+ error ("Can't reassign a value to the final variable %qs",
+ IDENTIFIER_POINTER (name));
}
static void
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)))
+ || (DECL_LOCAL_FINAL_IUD (decl) ? ASSIGNED_P (before, index)
+ : ! UNASSIGNED_P (before, index))))
{
final_assign_error (DECL_NAME (decl));
}
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:
COPY (when_true, before);
}
break;
+
default:
- do_default:
check_init (exp, before);
COPY (when_false, before);
COPY (when_true, before);
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:
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. */
+ error ("variable %qD may not have been initialized", exp);
DECL_BIT_INDEX (exp) = -2;
}
}
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)));
+ error ("variable %qD may not have been initialized", tmp);
/* Suppress further errors. */
DECL_BIT_INDEX (tmp) = -2;
}
definitely assigned when once we checked the whole
function. */
if (! STATIC_CLASS_INIT_OPT_P () /* FIXME */
+ && ! DECL_FINAL (tmp)
&& index >= start_current_locals
&& index == num_current_locals - 1)
{
END_ALTERNATIVES (before, alt);
loop_current_locals = save_loop_current_locals;
start_current_locals = save_start_current_locals;
- return;
+ break;
}
case EXIT_EXPR:
{
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 ();
+ 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);
- return;
+ break;
}
case LABELED_BLOCK_EXPR:
{
check_init (LABELED_BLOCK_BODY (exp), before);
done_alternative (before, &alt);
END_ALTERNATIVES (before, alt);
- return;
+ break;
}
case EXIT_BLOCK_EXPR:
{
alt = alt->outer;
done_alternative (before, alt);
SET_ALL (before);
- return;
+ break;
}
case SWITCH_EXPR:
{
done_alternative (alt.saved, &alt);
FREE_BUFFER(alt.saved, buf);
END_ALTERNATIVES (before, alt);
- return;
+ break;
}
case CASE_EXPR:
case DEFAULT_EXPR:
}
END_ALTERNATIVES (before, alt);
}
- return;
+ break;
case TRY_FINALLY_EXPR:
{
UNION (before, before, tmp);
RELEASE_BUFFERS(tmp);
}
- return;
+ break;
case RETURN_EXPR:
case THROW_EXPR:
case ERROR_MARK:
never_continues:
SET_ALL (before);
- return;
+ break;
case COND_EXPR:
case TRUTH_ANDIF_EXPR:
break;
case NOP_EXPR:
- if (exp == empty_stmt_node)
+ if (IS_EMPTY_STMT (exp))
break;
/* ... else fall through ... */
case UNARY_PLUS_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 POSTINCREMENT_EXPR:
tmp = get_variable_decl (TREE_OPERAND (exp, 0));
if (tmp != NULL_TREE && DECL_FINAL (tmp))
- final_assign_error (DECL_NAME (tmp));
+ final_assign_error (DECL_NAME (tmp));
+ else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF)
+ {
+ /* Take care of array length accesses too. */
+ tree decl = TREE_OPERAND (tmp, 1);
+ if (DECL_FINAL (decl))
+ final_assign_error (DECL_NAME (decl));
+ }
/* Avoid needless recursion. */
exp = TREE_OPERAND (exp, 0);
case SAVE_EXPR:
if (IS_INIT_CHECKED (exp))
- return;
+ break;
IS_INIT_CHECKED (exp) = 1;
exp = TREE_OPERAND (exp, 0);
goto again;
case FLOOR_MOD_EXPR:
case ROUND_MOD_EXPR:
case EXACT_DIV_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ case LTGT_EXPR:
binop:
check_init (TREE_OPERAND (exp, 0), before);
/* Avoid needless recursion, especially for COMPOUND_EXPR. */
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
+ case DECL_EXPR:
case JAVA_EXC_OBJ_EXPR:
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);
+ 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 saved_wfl = wfl;
tree body = EXPR_WFL_NODE (exp);
- if (body == empty_stmt_node)
+ if (IS_EMPTY_STMT (body))
break;
- wfl = exp;
+#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;
- wfl = saved_wfl;
}
break;
("internal error in check-init: tree code not implemented: %s",
tree_code_name [(int) TREE_CODE (exp)]);
}
+ input_location = save_location;
}
void
if (index >= 0 && ! ASSIGNED_P (before, index))
{
if (! is_finit_method)
- error ("%Jfinal field '%D' may not have been initialized",
+ error ("%Jfinal field %qD may not have been initialized",
decl, decl);
}
else if (is_finit_method)