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]

[PATCH] Java: fix to gcj/232, gcj/163 + others.



The patch fixes gcj/163, gcj/232 and the multidimentional array class
literal bug:

  http://sources.redhat.com/ml/java-prs/2000-q1/msg00138.html
  http://sources.redhat.com/ml/java-prs/2000-q2/msg00186.html
  http://gcc.gnu.org/ml/gcc-patches/2000-10/msg00220.html

I'm checking this in.

./A

2000-10-18  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* jcf-write.c (OP1): Update `last_bc'.
	(struct jcf_block): Fixed indentation and typo in comments.  New
	field `last_bc'.
	(generate_bytecode_insns): Insert `nop' if `jsr' immediately
	follows `monitorenter'.
	* parse.y (patch_synchronized_statement): New local `tmp'. Call
	`patch_string'.
	Fixes gcj/232.

2000-10-13  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* check-init.c (check_init): Fixed leading comment. Use
	LOCAL_FINAL_P.
	* decl.c (push_jvm_slot): Use MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
	(give_name_to_locals): Likewise.
	(lang_mark_tree): Handle FIELD_DECL. Register `am' and `wfl'
	fields in lang_decl_var.
	* java-tree.h (DECL_FUNCTION_SYNTHETIC_CTOR,
	DECL_FUNCTION_ALL_FINAL_INITIALIZED): New macros.
	(FIELD_INNER_ACCESS): Removed ugly cast, macro rewritten.
	(FIELD_INNER_ACCESS_P, DECL_FIELD_FINAL_IUD, DECL_FIELD_FINAL_LIIC,
	DECL_FIELD_FINAL_IERR, DECL_FIELD_FINAL_WFL): New macros.
	(LOCAL_FINAL): Rewritten.
	(LOCAL_FINAL_P, FINAL_VARIABLE_P, CLASS_FINAL_VARIABLE_P
	MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC): New macros.
	(struct lang_decl): Fixed comments. Added `synthetic_ctor' and
	`init_final' fields.
	(struct lang_decl_var): Fixed leading comment. Added `am', `wfl',
	`final_uid', `final_liic', `final_ierr' and `local_final' fields.
	(TYPE_HAS_FINAL_VARIABLE): New macro.
	(struct lang_type): Added `afv' field.
	* parse.y (check_static_final_variable_assignment_flag): New function.
	(reset_static_final_variable_assignment_flag): Likewise.
	(check_final_variable_local_assignment_flag): Likewise.
	(reset_final_variable_local_assignment_flag): Likewise.
	(check_final_variable_indirect_assignment): Likewise.
	(check_final_variable_global_assignment_flag): Likewise.
	(add_inner_class_fields): Use LOCAL_FINAL_P.
	(register_fields): Handle local finals and final variables.
	(craft_constructor): Set DECL_FUNCTION_SYNTHETIC_CTOR.
	(declare_local_variables): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
	(source_start_java_method): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC
	on local finals.
	(java_complete_expand_methods): Loop to set
	TYPE_HAS_FINAL_VARIABLE. Call
	`reset_final_variable_local_assignment_flag' and 
	`check_final_variable_local_assignment_flag' accordingly before
	and after constructor expansion. Call
	`reset_static_final_variable_assignment_flag'
	before expanding <clinit> and after call 
	`check_static_final_variable_assignment_flag' if the
	current_class isn't an interface. After all methods have been
	expanded, call `check_final_variable_global_assignment_flag' and
	`check_static_final_variable_assignment_flag' if the current class
	is an interface. 
	(maybe_yank_clinit): Fixed typo in comment.
	(build_outer_field_access_methods): Removed old sanity check. Use
	FIELD_INNER_ACCESS_P. Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
	Don't create access methods for finals.
	(resolve_field_access): Use `CLASS_FINAL_VARIABLE_P'.
	(java_complete_tree): Likewise. Reset DECL_FIELD_FINAL_IUD if
	existing DECL_INIT has been processed. 
	(java_complete_lhs): Likewise.
	(check_final_assignment): Filter input on `lvalue''s TREE_CODE.
	Test for COMPONENT_REF to get to the FIELD_DECL. Implemented new
	logic.
	(patch_assignment): Use LOCAL_FINAL_P.
	(fold_constant_for_init): Reset DECL_FIELD_FINAL_IUD if
	DECL_INITIAL is nullified.
	Fixes gcj/163.

2000-10-09  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* parse.y (pop_current_osb): New function.
	(array_type:): Use `dims:', changed actions
	accordingly. Suggested by Anthony Green.
	(array_creation_expression:): Used pop_current_osb.
	(cast_expression:): Likewise.
	(search_applicable_method_list): Fixed indentation.

2000-10-08  Anthony Green  <green@redhat.com>

	* parse.y (array_type_literal): Remove production.
	(type_literals): Refer to array_type, not array_type_literal.
 
Index: check-init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/check-init.c,v
retrieving revision 1.24
diff -u -p -r1.24 check-init.c
--- check-init.c	2000/08/13 16:48:54	1.24
+++ check-init.c	2000/12/06 18:28:25
@@ -356,8 +356,7 @@ done_alternative (after, current)
   start_current_locals = current.save_start_current_locals; \
 }
 
-/* Check for (un)initialized local variables in EXP.
-*/
+/* Check for (un)initialized local variables in EXP.  */
 
 static void
 check_init (exp, before)
@@ -387,14 +386,14 @@ check_init (exp, before)
       /* 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 (tmp)))
+	  || (TREE_CODE (tmp) == PARM_DECL && LOCAL_FINAL_P (tmp)))
 	{
 	  int index;
 	  check_init (TREE_OPERAND (exp, 1), before);
 	  index = DECL_BIT_INDEX (tmp);
 	  /* A final local already assigned or a final parameter
              assigned must be reported as errors */
-	  if (LOCAL_FINAL (tmp) 
+	  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)));
 
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/decl.c,v
retrieving revision 1.78
diff -u -p -r1.78 decl.c
--- decl.c	2000/11/10 16:01:20	1.78
+++ decl.c	2000/12/06 18:28:30
@@ -127,8 +127,7 @@ push_jvm_slot (index, decl)
   /* Now link the decl into the decl_map. */
   if (DECL_LANG_SPECIFIC (decl) == NULL)
     {
-      DECL_LANG_SPECIFIC (decl)
-	= (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl_var));
+      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
       DECL_LOCAL_START_PC (decl) = 0;
       DECL_LOCAL_END_PC (decl) = DECL_CODE_LENGTH (current_function_decl);
       DECL_LOCAL_SLOT_NUMBER (decl) = index;
@@ -1620,8 +1619,7 @@ give_name_to_locals (jcf)
 	     comments for expr.c:maybe_adjust_start_pc. */
 	  start_pc = maybe_adjust_start_pc (jcf, code_offset, start_pc, slot);
 
-	  DECL_LANG_SPECIFIC (decl)
-	    = (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl_var));
+	  MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
 	  DECL_LOCAL_SLOT_NUMBER (decl) = slot;
 	  DECL_LOCAL_START_PC (decl) = start_pc;
 #if 0
@@ -1901,7 +1899,8 @@ lang_mark_tree (t)
       ggc_mark_tree (li->utf8_ref);
     }
   else if (TREE_CODE (t) == VAR_DECL
-	   || TREE_CODE (t) == PARM_DECL)
+	   || TREE_CODE (t) == PARM_DECL
+	   || TREE_CODE (t) == FIELD_DECL)
     {
       struct lang_decl_var *ldv = 
 	((struct lang_decl_var *) DECL_LANG_SPECIFIC (t));
@@ -1909,6 +1908,8 @@ lang_mark_tree (t)
 	{
 	  ggc_mark (ldv);
 	  ggc_mark_tree (ldv->slot_chain);
+	  ggc_mark_tree (ldv->am);
+	  ggc_mark_tree (ldv->wfl);
 	}
     }
   else if (TREE_CODE (t) == FUNCTION_DECL)
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/java-tree.h,v
retrieving revision 1.89
diff -u -p -r1.89 java-tree.h
--- java-tree.h	2000/11/19 12:56:21	1.89
+++ java-tree.h	2000/12/06 18:28:34
@@ -88,7 +88,6 @@ struct JCF;
    3: METHOD_FINAL (in FUNCTION_DECL)
       FIELD_FINAL (in FIELD_DECL)
       CLASS_FINAL (in TYPE_DECL)
-      LOCAL_FINAL (in VAR_DECL)
    4: METHOD_SYNCHRONIZED (in FUNCTION_DECL).
       LABEL_IN_SUBR (in LABEL_DECL)
       CLASS_INTERFACE (in TYPE_DECL)
@@ -701,12 +700,13 @@ struct lang_identifier
    is excluded, because sometimes created as a parameter before the
    function decl exists. */
 #define DECL_FUNCTION_NAP(DECL) (DECL_LANG_SPECIFIC(DECL)->nap)
+/* 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)
 
-/* For a FIELD_DECL, holds the name of the access method used to
-   read/write the content of the field from an inner class. 
-   The cast is ugly. FIXME  */
-#define FIELD_INNER_ACCESS(DECL)       ((tree)DECL_LANG_SPECIFIC (DECL))
-
 /* True when DECL aliases an outer context local variable.  */
 #define FIELD_LOCAL_ALIAS(DECL) DECL_LANG_FLAG_6 (DECL)
 
@@ -779,6 +779,46 @@ struct lang_identifier
    slot_number in decl_map. */
 #define DECL_LOCAL_SLOT_CHAIN(NODE) \
   (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->slot_chain)
+/* For a FIELD_DECL, holds the name of the access method. Used to
+   read/write the content of the field from an inner class.  */
+#define FIELD_INNER_ACCESS(DECL) \
+  (((struct lang_decl_var*)DECL_LANG_SPECIFIC(DECL))->am)
+/* 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. */
+#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 */
+#define FINAL_VARIABLE_P(NODE) (FIELD_FINAL (NODE) && !FIELD_STATIC (NODE))
+/* True if NODE is a class final variable */
+#define CLASS_FINAL_VARIABLE_P(NODE) \
+  (FIELD_FINAL (NODE) && FIELD_STATIC (NODE))
+/* Create a DECL_LANG_SPECIFIC if necessary. */
+#define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T)			\
+  if (DECL_LANG_SPECIFIC (T) == NULL)				\
+    {								\
+      DECL_LANG_SPECIFIC ((T))					\
+	= ((struct lang_decl *)					\
+	   ggc_alloc_cleared (sizeof (struct lang_decl_var)));	\
+    }
 
 /* For a local VAR_DECL, holds the index into a words bitstring that
    specifies if this decl is definitively assigned.
@@ -798,15 +838,15 @@ struct lang_decl
   tree throws_list;		/* Exception specified by `throws' */
   tree function_decl_body;	/* Hold all function's statements */
   tree called_constructor;	/* When decl is a constructor, the
-				   list of other constructor it calls. */
+				   list of other constructor it calls */
   struct hash_table init_test_table;
-				/* Class initialization test variables.  */
+				/* Class initialization test variables  */
   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 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 */
 };
 
 /* init_test_table hash table entry structure.  */
@@ -816,13 +856,20 @@ struct init_test_hash_entry
   tree init_test_decl;
 };
 
-/* DECL_LANG_SPECIFIC for VAR_DECL and PARM_DECL. */
+/* DECL_LANG_SPECIFIC for VAR_DECL, PARM_DECL and sometimes FIELD_DECL
+   (access methods on outer class fields) and final fields. */
 struct lang_decl_var
 {
   int slot_number;
   int start_pc;
   int end_pc;
   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 */
 };
 
 /* Macro to access fields in `struct lang_type'.  */
@@ -847,6 +894,7 @@ struct lang_decl_var
 #define TYPE_DOT_CLASS(T)        (TYPE_LANG_SPECIFIC(T)->dot_class)
 #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)->afv)
 
 struct lang_type
 {
@@ -863,6 +911,7 @@ struct lang_type
 				   <non_primitive_type>.class */
   unsigned pic:1;		/* Private Inner Class. */
   unsigned poic:1;		/* Protected Inner Class. */
+  unsigned afv:1;		/* Has final variables */
 };
 
 #ifdef JAVA_USE_HANDLES
@@ -1110,7 +1159,6 @@ struct rtx_def * java_lang_expand_expr P
 #define FIELD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
 #define FIELD_VOLATILE(DECL) DECL_LANG_FLAG_4 (DECL)
 #define FIELD_TRANSIENT(DECL) DECL_LANG_FLAG_5 (DECL)
-#define LOCAL_FINAL(DECL) FIELD_FINAL(DECL)
 
 /* Access flags etc for a class (a TYPE_DECL): */
 
Index: jcf-write.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/jcf-write.c,v
retrieving revision 1.69
diff -u -p -r1.69 jcf-write.c
--- jcf-write.c	2000/09/23 17:09:39	1.69
+++ jcf-write.c	2000/12/06 18:28:42
@@ -57,7 +57,7 @@ char *jcf_write_base_directory = NULL;
 /* Add a 1-byte instruction/operand I to bytecode.data,
    assuming space has already been RESERVE'd. */
 
-#define OP1(I) (*state->bytecode.ptr++ = (I), CHECK_OP(state))
+#define OP1(I) (state->last_bc = *state->bytecode.ptr++ = (I), CHECK_OP(state))
 
 /* Like OP1, but I is a 2-byte big endian integer. */
 
@@ -131,13 +131,14 @@ struct jcf_block
 
   int linenumber;
 
-  /* After finish_jcf_block is called, The actual instructions contained in this block.
-     Before than NULL, and the instructions are in state->bytecode. */
+  /* After finish_jcf_block is called, The actual instructions
+     contained in this block.  Before than NULL, and the instructions
+     are in state->bytecode. */
   union {
     struct chunk *chunk;
 
     /* If pc==PENDING_CLEANUP_PC, start_label is the start of the region
-       coveed by the cleanup. */
+       covered by the cleanup. */
     struct jcf_block *start_label;
   } v;
 
@@ -272,8 +273,10 @@ struct jcf_partial
   /* If non-NULL, use this for the return value. */
   tree return_value_decl;
 
-  /* Information about the current switch statemenet. */
+  /* Information about the current switch statement. */
   struct jcf_switch_state *sw_state;
+
+  enum java_opcode last_bc;	/* The last emitted bytecode */
 };
 
 static void generate_bytecode_insns PARAMS ((tree, int, struct jcf_partial *));
@@ -2158,7 +2161,16 @@ generate_bytecode_insns (exp, target, st
 	tree src = TREE_OPERAND (exp, 0);
 	tree src_type = TREE_TYPE (src);
 	tree dst_type = TREE_TYPE (exp);
-	generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
+	/* Detect the situation of compiling an empty synchronized
+	   block.  A nop should be emitted in order to produce
+	   verifiable bytecode. */
+	if (exp == empty_stmt_node
+	    && state->last_bc == OPCODE_monitorenter
+	    && state->labeled_blocks
+	    && state->labeled_blocks->pc == PENDING_CLEANUP_PC)
+	  OP1 (OPCODE_nop);
+	else
+	  generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
 	if (target == IGNORE_TARGET || src_type == dst_type)
 	  break;
 	if (TREE_CODE (dst_type) == POINTER_TYPE)
Index: parse.y
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/parse.y,v
retrieving revision 1.231
diff -u -p -r1.231 parse.y
--- parse.y	2000/12/05 07:08:56	1.231
+++ parse.y	2000/12/06 18:29:18
@@ -102,6 +102,12 @@ static int process_imports PARAMS ((void
 static void read_import_dir PARAMS ((tree));
 static int find_in_imports_on_demand PARAMS ((tree));
 static void find_in_imports PARAMS ((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));
 static void register_package PARAMS ((tree));
@@ -287,6 +293,7 @@ static void java_parser_context_pop_init
 static tree reorder_static_initialized PARAMS ((tree));
 static void java_parser_context_suspend PARAMS ((void));
 static void java_parser_context_resume PARAMS ((void));
+static int pop_current_osb PARAMS ((struct parser_ctxt *));
 
 /* JDK 1.1 work. FIXME */
 
@@ -580,7 +587,7 @@ static tree currently_caught_type_list;
 			BOOLEAN_TK INTEGRAL_TK FP_TK
 
 /* Added or modified JDK 1.1 rule types  */
-%type	 <node>		type_literals array_type_literal
+%type	 <node>		type_literals
 
 %%
 /* 19.2 Production from 2.3: The Syntactic Grammar  */
@@ -652,19 +659,23 @@ interface_type:
 ;
 
 array_type:
-	primitive_type OSB_TK CSB_TK
+	primitive_type dims
 		{ 
-		  $$ = build_java_array_type ($1, -1);
-		  CLASS_LOADED_P ($$) = 1;
+		  int osb = pop_current_osb (ctxp);
+		  tree t = build_java_array_type (($1), -1);
+		  CLASS_LOADED_P (t) = 1;
+		  while (--osb)
+		    t = build_unresolved_array_type (t);
+		  $$ = t;
+		}
+|	name dims
+		{ 
+		  int osb = pop_current_osb (ctxp);
+		  tree t = $1;
+		  while (osb--)
+		    t = build_unresolved_array_type (t);
+		  $$ = t;
 		}
-|	name OSB_TK CSB_TK
-		{ $$ = build_unresolved_array_type ($1); }
-|	array_type OSB_TK CSB_TK
-		{ $$ = build_unresolved_array_type ($1); }
-|	primitive_type OSB_TK error
-		{RULE ("']' expected"); RECOVER;}
-|	array_type OSB_TK error
-		{RULE ("']' expected"); RECOVER;}
 ;
 
 /* 19.5 Productions from 6: Names  */
@@ -1935,28 +1946,10 @@ primary_no_new_array:
 		{yyerror ("'class' expected" ); RECOVER;}
 ;
 
-/* Added, JDK1.1 type literals. We can't use `type' directly, so we
-   broke the rule down a bit. */
-
-array_type_literal:
-	primitive_type OSB_TK CSB_TK
-		{ 
-		  $$ = build_java_array_type ($1, -1);
-		  CLASS_LOADED_P ($$) = 1;
-		}
-|	name OSB_TK CSB_TK
-		{ $$ = build_unresolved_array_type ($1); }
-/* This triggers two reduce/reduce conflict between array_type_literal and
-   dims. FIXME.
-|	array_type OSB_TK CSB_TK
-		{ $$ = build_unresolved_array_type ($1); }
-*/
-;
-
 type_literals:
 	name DOT_TK CLASS_TK
 		{ $$ = build_incomplete_class_ref ($2.location, $1); }
-|	array_type_literal DOT_TK CLASS_TK
+|	array_type DOT_TK CLASS_TK
 		{ $$ = build_incomplete_class_ref ($2.location, $1); }
 |	primitive_type DOT_TK CLASS_TK
 		{ $$ = build_class_ref ($1); }
@@ -2085,15 +2078,16 @@ array_creation_expression:
 |	NEW_TK class_or_interface_type dim_exprs
 		{ $$ = build_newarray_node ($2, $3, 0); }
 |	NEW_TK primitive_type dim_exprs dims
-		{ $$ = build_newarray_node ($2, $3, CURRENT_OSB (ctxp));}
+		{ $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));}
 |	NEW_TK class_or_interface_type dim_exprs dims
-		{ $$ = build_newarray_node ($2, $3, CURRENT_OSB (ctxp));}
+		{ $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));}
         /* Added, JDK1.1 anonymous array. Initial documentation rule
            modified */
 |	NEW_TK class_or_interface_type dims array_initializer
 		{
 		  char *sig;
-		  while (CURRENT_OSB (ctxp)--)
+		  int osb = pop_current_osb (ctxp);
+		  while (osb--)
 		    obstack_1grow (&temporary_obstack, '[');
 		  sig = obstack_finish (&temporary_obstack);
 		  $$ = build (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE,
@@ -2101,8 +2095,9 @@ array_creation_expression:
 		}
 |	NEW_TK primitive_type dims array_initializer
 		{ 
+		  int osb = pop_current_osb (ctxp);
 		  tree type = $2;
-		  while (CURRENT_OSB (ctxp)--)
+		  while (osb--)
 		    type = build_java_array_type (type, -1);
 		  $$ = build (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE, 
 			      build_pointer_type (type), NULL_TREE, $4);
@@ -2325,9 +2320,9 @@ cast_expression:		/* Error handling here
 	OP_TK primitive_type dims CP_TK unary_expression
 		{ 
 		  tree type = $2;
-		  while (CURRENT_OSB (ctxp)--)
+		  int osb = pop_current_osb (ctxp);
+		  while (osb--)
 		    type = build_java_array_type (type, -1);
-		  ctxp->osb_depth--;
 		  $$ = build_cast ($1.location, type, $5); 
 		}
 |	OP_TK primitive_type CP_TK unary_expression
@@ -2337,9 +2332,9 @@ cast_expression:		/* Error handling here
 |	OP_TK name dims CP_TK unary_expression_not_plus_minus
 		{ 
 		  const char *ptr;
-		  while (CURRENT_OSB (ctxp)--)
+		  int osb = pop_current_osb (ctxp); 
+		  while (osb--)
 		    obstack_1grow (&temporary_obstack, '[');
-		  ctxp->osb_depth--;
 		  obstack_grow0 (&temporary_obstack, 
 				 IDENTIFIER_POINTER (EXPR_WFL_NODE ($2)),
 				 IDENTIFIER_LENGTH (EXPR_WFL_NODE ($2)));
@@ -2593,6 +2588,25 @@ constant_expression:
 ;
 
 %%
+
+/* Helper function to retrieve an OSB count. Should be used when the
+   `dims:' rule is being used.  */
+
+static int
+pop_current_osb (ctxp)
+     struct parser_ctxt *ctxp;
+{
+  int to_return;
+
+  if (ctxp->osb_depth < 0)
+    fatal ("osb stack underflow");
+  
+  to_return = CURRENT_OSB (ctxp);
+  ctxp->osb_depth--;
+  
+  return to_return;
+}
+
 
 
 /* This section of the code deal with save/restoring parser contexts.
@@ -3952,7 +3966,7 @@ add_inner_class_fields (class_decl, fct_
 	  tree wfl, init, list;
 	  
 	  /* Avoid non final arguments. */
-	  if (!LOCAL_FINAL (decl))
+	  if (!LOCAL_FINAL_P (decl))
 	    continue;
 	  
 	  MANGLE_OUTER_LOCAL_VARIABLE_NAME (name, DECL_NAME (decl));
@@ -4185,11 +4199,29 @@ register_fields (flags, type, variable_l
       field_decl = add_field (class_type, current_name, real_type, flags);
       CHECK_DEPRECATED (field_decl);
 
-      /* If the couple initializer/initialized is marked ARG_FINAL_P, we
-	 mark the created field FIELD_LOCAL_ALIAS, so that we can 
-	 hide parameters to this inner class finit$ and constructors. */
+      /* 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
+	 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,
+	 we mark the created field FIELD_LOCAL_ALIAS, so that we can
+	 hide parameters to this inner class finit$ and
+	 constructors. It also means that the field isn't final per
+	 say. */
       if (ARG_FINAL_P (current))
-	FIELD_LOCAL_ALIAS (field_decl) = 1;
+	{
+	  FIELD_LOCAL_ALIAS (field_decl) = 1;
+	  FIELD_FINAL (field_decl) = 0;
+	}
       
       /* Check if we must chain. */
       if (must_chain)
@@ -5182,7 +5214,7 @@ craft_constructor (class_decl, args)
   fix_method_argument_names (parm, decl);
   /* Now, mark the artificial parameters. */
   DECL_FUNCTION_NAP (decl) = artificial;
-  DECL_CONSTRUCTOR_P (decl) = 1;
+  DECL_FUNCTION_SYNTHETIC_CTOR (decl) = DECL_CONSTRUCTOR_P (decl) = 1;
 }
 
 
@@ -7039,6 +7071,7 @@ declare_local_variables (modifier, type,
       /* Never layout this decl. This will be done when its scope
 	 will be entered */
       decl = build_decl (VAR_DECL, name, real_type);
+      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
       LOCAL_FINAL (decl) = final_p;
       BLOCK_CHAIN_DECL (decl);
       
@@ -7116,7 +7149,10 @@ source_start_java_method (fndecl)
       /* Remember if a local variable was declared final (via its
          TREE_LIST of type/name.) Set LOCAL_FINAL accordingly. */
       if (ARG_FINAL_P (tem))
-	LOCAL_FINAL (parm_decl) = 1;
+	{
+	  MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (parm_decl);
+	  LOCAL_FINAL (parm_decl) = 1;
+	}
 
       BLOCK_CHAIN_DECL (parm_decl);
     }
@@ -7164,7 +7200,7 @@ static void
 end_artificial_method_body (mdecl)
      tree mdecl;
 {
-  BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_block ();
+  BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_blcok ();
   exit_block ();
 }
 
@@ -7472,6 +7508,14 @@ 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 ();
 
@@ -7504,7 +7548,15 @@ 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);
@@ -7532,10 +7584,17 @@ 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 */
@@ -7550,6 +7609,15 @@ 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;
 }
@@ -7690,7 +7758,7 @@ maybe_yank_clinit (mdecl)
 	continue;
 
       /* Anything that isn't String or a basic type is ruled out -- or
-	 if we now how to deal with it (when doing things natively) we
+	 if we know how to deal with it (when doing things natively) we
 	 should generated an empty <clinit> so that SUID are computed
 	 correctly. */
       if (! JSTRING_TYPE_P (TREE_TYPE (current))
@@ -8045,14 +8113,11 @@ build_outer_field_access_methods (decl)
 {
   tree id, args, stmt, mdecl;
   
-  /* Check point, to be removed. FIXME */
-  if (FIELD_INNER_ACCESS (decl) 
-      && TREE_CODE (FIELD_INNER_ACCESS (decl)) != IDENTIFIER_NODE)
-    abort ();
-
-  if (FIELD_INNER_ACCESS (decl))
+  if (FIELD_INNER_ACCESS_P (decl))
     return FIELD_INNER_ACCESS (decl);
 
+  MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
+ 
   /* Create the identifier and a function named after it. */
   id = build_new_access_id ();
 
@@ -8070,17 +8135,21 @@ build_outer_field_access_methods (decl)
 					   TREE_TYPE (decl), id, args, stmt);
   DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
 
-  /* Create the write access method */
-  args = build_tree_list (inst_id, build_pointer_type (DECL_CONTEXT (decl)));
-  TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
-  TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
-  stmt = make_qualified_primary (build_wfl_node (inst_id),
-				 build_wfl_node (DECL_NAME (decl)), 0);
-  stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
-					    build_wfl_node (wpv_id)));
-
-  mdecl = build_outer_field_access_method (DECL_CONTEXT (decl), 
-					   TREE_TYPE (decl), id, args, stmt);
+  /* Create the write access method. No write access for final variable */
+  if (!FIELD_FINAL (decl))
+    {
+      args = build_tree_list (inst_id, 
+			      build_pointer_type (DECL_CONTEXT (decl)));
+      TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
+      TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
+      stmt = make_qualified_primary (build_wfl_node (inst_id),
+				     build_wfl_node (DECL_NAME (decl)), 0);
+      stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
+						build_wfl_node (wpv_id)));
+      mdecl = build_outer_field_access_method (DECL_CONTEXT (decl), 
+					       TREE_TYPE (decl), id, 
+					       args, stmt);
+    }
   DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
 
   /* Return the access name */
@@ -8986,7 +9055,7 @@ resolve_field_access (qual_wfl, field_de
       if (!type_found)
 	type_found = DECL_CONTEXT (decl);
       is_static = JDECL_P (decl) && FIELD_STATIC (decl);
-      if (FIELD_FINAL (decl) && FIELD_STATIC (decl)
+      if (CLASS_FINAL_VARIABLE_P (decl)
 	  && JPRIMITIVE_TYPE_P (TREE_TYPE (decl))
 	  && DECL_INITIAL (decl))
 	{
@@ -10587,7 +10656,7 @@ search_applicable_methods_list (lc, meth
       else if (!lc && (DECL_CONSTRUCTOR_P (method) 
 		       || (GET_METHOD_NAME (method) != name)))
 	continue;
-	  
+
       if (argument_types_convertible (method, arglist))
 	{
 	  /* Retain accessible methods only */
@@ -10996,7 +11065,7 @@ java_complete_tree (node)
      tree node;
 {
   node = java_complete_lhs (node);
-  if (JDECL_P (node) && FIELD_STATIC (node) && FIELD_FINAL (node) 
+  if (JDECL_P (node) && CLASS_FINAL_VARIABLE_P (node)
       && DECL_INITIAL (node) != NULL_TREE
       && !flag_emit_xref)
     {
@@ -11015,6 +11084,8 @@ java_complete_tree (node)
 	  else
 	    return value;
 	}
+      else
+        DECL_FIELD_FINAL_IUD (node) = 0;
     }
   return node;
 }
@@ -11505,6 +11576,8 @@ java_complete_lhs (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);
 
@@ -12062,6 +12135,214 @@ print_int_node (node)
   return buffer;
 }
 
+
+
+/* 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 be 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)
+	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)
+	  fatal ("Can't find FUNCTION_DECL in CALL_EXPR - check_final_variable_indirect_assignment");
+	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;
+
+  /* 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");
+	  }
+	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 natural ctor in which the field could have been
+	   initialized */
+	&& !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.  */
 
@@ -12069,27 +12350,52 @@ static int
 check_final_assignment (lvalue, wfl)
      tree lvalue, wfl;
 {
-  if (TREE_CODE (lvalue) == COMPOUND_EXPR 
+  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;
 
-  /* When generating class files, references to the `length' field
-     look a bit different.  */
-  if ((flag_emit_class_files
-       && TREE_CODE (lvalue) == COMPONENT_REF
-       && TYPE_ARRAY_P (TREE_TYPE (TREE_OPERAND (lvalue, 0)))
-       && FIELD_FINAL (TREE_OPERAND (lvalue, 1)))
-      || (TREE_CODE (lvalue) == FIELD_DECL
-	  && FIELD_FINAL (lvalue)
-	  && !DECL_CLINIT_P (current_function_decl)
-	  && !DECL_FINIT_P (current_function_decl)))
+  /* 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))
     {
-      parse_error_context 
-        (wfl, "Can't assign a value to the final variable `%s'",
-	 IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
-      return 1;
+      DECL_FIELD_FINAL_IUD (lvalue) = 1;
+      return 0;
     }
-  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;
 }
 
 /* Inline references to java.lang.PRIMTYPE.TYPE when accessed in
@@ -12297,7 +12603,7 @@ patch_assignment (node, wfl_op1, wfl_op2
   /* Final locals can be used as case values in switch
      statement. Prepare them for this eventuality. */
   if (TREE_CODE (lvalue) == VAR_DECL 
-      && LOCAL_FINAL (lvalue)
+      && LOCAL_FINAL_P (lvalue)
       && TREE_CONSTANT (new_rhs)
       && IDENTIFIER_LOCAL_VALUE (DECL_NAME (lvalue))
       && JINTEGRAL_TYPE_P (TREE_TYPE (lvalue))
@@ -14820,7 +15126,7 @@ patch_synchronized_statement (node, wfl_
   tree expr = java_complete_tree (TREE_OPERAND (node, 0));
   tree block = TREE_OPERAND (node, 1);
 
-  tree enter, exit, expr_decl, assignment;
+  tree tmp, enter, exit, expr_decl, assignment;
 
   if (expr == error_mark_node)
     {
@@ -14828,6 +15134,10 @@ patch_synchronized_statement (node, wfl_
       return expr;
     }
 
+  /* We might be trying to synchronize on a STRING_CST */
+  if ((tmp = patch_string (expr)))
+    expr = tmp;
+
   /* The TYPE of expr must be a reference type */
   if (!JREFERENCE_TYPE_P (TREE_TYPE (expr)))
     {
@@ -15265,6 +15575,8 @@ 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]