This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PATH: check definite unassigment to final variables


I checked this into the trunk.  It is basically the same as the
patch I posted yesterday, except for some extra code to check
for assignment to ARRAY.length.

It passes a bootstrap and make check in libjava.  No regressions
except for BlankFinal.java, which is a testcase error.
-- 
	--Per Bothner
per@bothner.com   http://www.bothner.com/per/
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.

Index: check-init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/check-init.c,v
retrieving revision 1.34
diff -u -p -r1.34 check-init.c
--- check-init.c	2001/12/04 01:10:08	1.34
+++ check-init.c	2001/12/04 18:57:33
@@ -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 independ
 #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,8 +42,12 @@ 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.
 
    The variables whose DECL_BIT_INDEX are in the range from
@@ -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 ((tre
 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, els
      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, befo
      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, befo
     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
     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 = NUL
   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);
@@ -547,21 +722,23 @@ check_init (exp, before)
 	    COPY (tmp, save);
 	    check_init (catch_clause, tmp);
 	    done_alternative (tmp, &alt);
+	  }
+	if (tmp != buf)
+	  {
+	    FREE_WORDS (tmp);
 	  }
-	FREE_WORDS (tmp);
-	FREE_WORDS (save);
 	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:
@@ -719,14 +897,88 @@ check_init (exp, before)
 	 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 <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;
+	    }
+	}
+    }
 
-unsigned int
-check_for_initialization (body)
-     tree body;
-{
-  word before = 0;
-  check_init (body, &before);
-  return before;
+  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, 
      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;
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.121
diff -u -p -r1.121 expr.c
--- expr.c	2001/12/03 19:13:40	1.121
+++ expr.c	2001/12/04 18:57:35
@@ -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
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.125
diff -u -p -r1.125 java-tree.h
--- java-tree.h	2001/11/15 10:01:08	1.125
+++ java-tree.h	2001/12/04 18:57:36
@@ -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 (
   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 P
 					       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 P
 #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 */
Index: parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.329
diff -u -p -r1.329 parse.y
--- parse.y	2001/12/04 01:24:59	1.329
+++ parse.y	2001/12/04 18:57:45
@@ -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 PARA
 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_l
       /* 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,
 	 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:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]