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]

PATH: check definite unassigment to final variables


Ok - here it is, what today's earlier patches have led up to.
The big patch to implement checking for assignment to final
variables (locals and fields) following the rules using the
concept of "definite unassignment" as defined in the second
edition of the Java Language Specification.  Whew.

This means that code like the following should now work:

   final int fld;
   { if (foo()) fld = 1;  else fld = 2; }

while the following will fail:

   final int fld;
   { if (foo()) fld = 1; }

Actually, we do violate the rules in at least one area:  The
extra complication dealing with loop statements discussed in
the JLS.  The JLS uses rules involving "hypothetical
assignment".  This looked like being more painful than seemed
justified, so I implemented something simpler:  Disallow
all assignments inside loops to finals declared outside it.
This might disallow some assignments that should strictly
speaking be allowed, but I don't think it matters.

As a bonus, we get rid of a bunch of code, with a net code-size
reduction of over 100 lines.

I haven't checked this in yet.  I am doing one more boostrap and
check first.  That will uncover at least one regression:  With the
new algorithm libjava.compile/BlankFinal.java now fails where it
didn't use to. That is because the testcase is wrong - the compiler
really *should* reject the program.  Tom, you checked the testcase
in - I don't know what you want to do about it - change it to a
"non-compile" testcase?

One more note:  I temporarily disabled the static class
initialization optimization.  I'll look into that next, but
I think it will be easier for me to figure out the exiting code
and how it needs to be fixed after checking these patches in.
-- 
	--Per Bothner
per@bothner.com   http://www.bothner.com/per/
2001-12-03  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 (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 01:52:27
@@ -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,111 @@ 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 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
+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)))
+    {
+      parse_error_context (wfl, "Can't re-assign here a value to the 'final' variable '%s'", IDENTIFIER_POINTER (DECL_NAME (decl)));
+      DECL_BIT_INDEX (decl) = -2;
+    }
+}
+
 /* 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 +217,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 +244,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 +296,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 +336,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 +420,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 +437,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 +475,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) = -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 (exp) = -1;
+	      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 +539,16 @@ 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))
+	    parse_error_context (wfl, "Can't re-assign here a value to the 'final' variable '%s'", IDENTIFIER_POINTER (DECL_NAME (decl)));
+	  break;
+	}
      else
        goto binop;
     case BLOCK:
@@ -434,7 +565,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 +575,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 +588,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 +633,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 +660,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 +681,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 +691,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 +707,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 +742,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 +762,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 +826,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 +883,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 +984,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: 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 01:52:28
@@ -92,6 +92,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 +477,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 +742,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 +826,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 +865,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 +891,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 +915,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 +944,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 +963,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 +1094,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 +1183,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 +1229,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)
@@ -1610,9 +1600,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 01:52:37
@@ -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]