OSDN Git Service

* parse.y (check_static_final_variable_assignment_flag): Fix spelling.
[pf3gnuchains/gcc-fork.git] / gcc / java / parse.y
index a35e6dc..00a5544 100644 (file)
@@ -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_initialized_field PARAMS ((void));
 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 */
 
@@ -334,7 +341,7 @@ int java_warning_count;
 /* Tell when not to fold, when doing xrefs */
 int do_not_fold;
 /* Cyclic inheritance report, as it can be set by layout_class */
-char *cyclic_inheritance_report;
+const char *cyclic_inheritance_report;
  
 /* Tell when we're within an instance initializer */
 static int in_instance_initializer;
@@ -463,6 +470,7 @@ static tree currently_caught_type_list;
 %token   STATIC_TK       FINAL_TK           SYNCHRONIZED_TK
 %token   VOLATILE_TK     TRANSIENT_TK       NATIVE_TK
 %token   PAD_TK          ABSTRACT_TK        MODIFIER_TK
+%token   STRICT_TK
 
 /* Keep those two in order, too */
 %token   DECR_TK INCR_TK
@@ -579,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  */
@@ -600,7 +608,6 @@ goal:
                  ggc_add_tree_root (&package_list, 1);
                  ggc_add_tree_root (&current_this, 1);
                  ggc_add_tree_root (&currently_caught_type_list, 1);
-                 ggc_add_string_root (&cyclic_inheritance_report, 1);
                  ggc_add_root (&ctxp, 1, 
                                sizeof (struct parser_ctxt *),
                                mark_parser_ctxt);
@@ -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 is potentially weak */
        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 is potentially weak */
 |      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;
+}
+
 \f
 
 /* This section of the code deal with save/restoring parser contexts.
@@ -3952,7 +3966,7 @@ add_inner_class_fields (class_decl, fct_decl)
          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_list)
       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, vlist)
       /* 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);
     }
@@ -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))
@@ -7837,11 +7905,13 @@ build_outer_field_access (id, decl)
 {
   tree access = NULL_TREE;
   tree ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
+  tree decl_ctx = DECL_CONTEXT (decl);
 
-  /* If decl's class is the direct outer class of the current_class,
-     build the access as `this$<n>.<field>'. Note that we will break
-     the `private' barrier if we're not emitting bytecodes. */
-  if (ctx == DECL_CONTEXT (decl) 
+  /* If the immediate enclosing context of the current class is the
+     field decl's class or inherits from it; build the access as
+     `this$<n>.<field>'. Note that we will break the `private' barrier
+     if we're not emitting bytecodes. */
+  if ((ctx == decl_ctx || inherits_from_p (ctx, decl_ctx))
       && (!FIELD_PRIVATE (decl) || !flag_emit_class_files ))
     {
       tree thisn = build_current_thisn (current_class);
@@ -7857,14 +7927,14 @@ build_outer_field_access (id, decl)
       /* Now we chain the required number of calls to the access$0 to
         get a hold to the enclosing instance we need, and then we
         build the field access. */
-      access = build_access_to_thisn (current_class, DECL_CONTEXT (decl), lc);
+      access = build_access_to_thisn (current_class, decl_ctx, lc);
 
       /* If the field is private and we're generating bytecode, then
          we generate an access method */
       if (FIELD_PRIVATE (decl) && flag_emit_class_files )
        {
          tree name = build_outer_field_access_methods (decl);
-         access = build_outer_field_access_expr (lc, DECL_CONTEXT (decl),
+         access = build_outer_field_access_expr (lc, decl_ctx,
                                                  name, access, NULL_TREE);
        }
       /* Otherwise we use `access$(this$<j>). ... access$(this$<i>).<field>'.
@@ -7887,14 +7957,26 @@ outer_field_access_p (type, decl)
       || TREE_CODE (decl) != FIELD_DECL
       || DECL_CONTEXT (decl) == type)
     return 0;
+  
+  /* If the inner class extends the declaration context of the field
+     we're try to acces, then this isn't an outer field access */
+  if (inherits_from_p (type, DECL_CONTEXT (decl)))
+    return 0;
 
   for (type = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))); ;
        type = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))))
     {
       if (type == DECL_CONTEXT (decl))
        return 1;
+
       if (!DECL_CONTEXT (TYPE_NAME (type)))
-       break;
+       {
+         /* Before we give up, see whether the field is inherited from
+            the enclosing context we're considering. */
+         if (inherits_from_p (type, DECL_CONTEXT (decl)))
+           return 1;
+         break;
+       }
     }
 
   return 0;
@@ -8031,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 ();
 
@@ -8056,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 */
@@ -8216,8 +8299,13 @@ build_access_to_thisn (from, to, lc)
          access = build_method_invocation (access0_wfl, access);
          access = make_qualified_primary (cn, access, lc);
        }
-      
-      from = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (from)));
+
+      /* if FROM isn't an inter class, that's fine, we've done
+         enough. What we're looking for can be accessed from there. */
+      from = DECL_CONTEXT (TYPE_NAME (from));
+      if (!from)
+       break;
+      from = TREE_TYPE (from);
     }
   return access;
 }
@@ -8238,7 +8326,7 @@ maybe_build_thisn_access_method (type)
 
   /* If TYPE is a top-level class, no access method is required.
      If there already is such an access method, bail out. */
-  if (CLASS_ACCESS0_GENERATED_P (type) || !INNER_CLASS_TYPE_P (type))
+  if (CLASS_ACCESS0_GENERATED_P (type) || !PURE_INNER_CLASS_TYPE_P (type))
     return NULL_TREE;
 
   /* We generate the method. The method looks like:
@@ -8866,7 +8954,14 @@ resolve_expression_name (id, orig)
                 to access a field belonging to an outer class, build
                 the access to the field */
              if (!fs && outer_field_access_p (current_class, decl))
-               return build_outer_field_access (id, decl);
+               {
+                 if (CLASS_STATIC (TYPE_NAME (current_class)))
+                   {
+                     static_ref_err (id, DECL_NAME (decl), current_class);
+                     return error_mark_node;
+                   }
+                 return build_outer_field_access (id, decl);
+               }
 
              /* Otherwise build what it takes to access the field */
              access = build_field_ref ((fs ? NULL_TREE : current_this),
@@ -8960,7 +9055,7 @@ resolve_field_access (qual_wfl, field_decl, field_type)
       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))
        {
@@ -9971,7 +10066,33 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl)
 
       /* Secretly pass the current_this/primary as a second argument */
       if (primary || current_this)
-       args = tree_cons (NULL_TREE, (primary ? primary : current_this), args);
+       {
+         tree extra_arg;
+         tree this_type = (current_this ?
+                           TREE_TYPE (TREE_TYPE (current_this)) : NULL_TREE);
+         /* Method's (list) enclosing context */
+         tree mec = DECL_CONTEXT (TYPE_NAME (DECL_CONTEXT (list)));
+         /* If we have a primary, use it. */
+         if (primary)
+           extra_arg = primary;
+         /* The current `this' is an inner class but isn't a direct
+            enclosing context for the inner class we're trying to
+            create. Build an access to the proper enclosing context
+            and use it. */
+         else if (current_this && PURE_INNER_CLASS_TYPE_P (this_type)
+                  && this_type != TREE_TYPE (mec))
+           {
+
+             extra_arg = build_access_to_thisn (current_class,
+                                                TREE_TYPE (mec), 0);
+             extra_arg = java_complete_tree (extra_arg);
+           }
+         /* Otherwise, just use the current `this' as an enclosing
+             context. */
+         else
+           extra_arg = current_this;
+         args = tree_cons (NULL_TREE, extra_arg, args);
+       }
       else
        args = tree_cons (NULL_TREE, integer_zero_node, args);
     }
@@ -10535,7 +10656,7 @@ search_applicable_methods_list (lc, method, name, arglist, list, all_list)
       else if (!lc && (DECL_CONSTRUCTOR_P (method) 
                       || (GET_METHOD_NAME (method) != name)))
        continue;
-         
+
       if (argument_types_convertible (method, arglist))
        {
          /* Retain accessible methods only */
@@ -10944,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)
     {
@@ -10963,6 +11084,8 @@ java_complete_tree (node)
          else
            return value;
        }
+      else
+        DECL_FIELD_FINAL_IUD (node) = 0;
     }
   return node;
 }
@@ -11453,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);
 
@@ -11483,6 +11608,14 @@ java_complete_lhs (node)
          nn = java_complete_tree (build_cast (EXPR_WFL_LINECOL (wfl_op2), 
                                               TREE_TYPE (lvalue), nn));
 
+         /* If the assignment is compound and has reference type,
+            then ensure the LHS has type String and nothing else.  */
+         if (JREFERENCE_TYPE_P (TREE_TYPE (lvalue))
+             && ! JSTRING_TYPE_P (TREE_TYPE (lvalue)))
+           parse_error_context (wfl_op2,
+                                "Incompatible type for `+='. Can't convert `%s' to `java.lang.String'",
+                                lang_printable_name (TREE_TYPE (lvalue), 0));
+
          /* 15.25.2.b: Left hand is an array access. FIXME */
        }
 
@@ -12010,6 +12143,214 @@ print_int_node (node)
   return buffer;
 }
 
+\f
+
+/* 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)
+       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.  */
 
@@ -12017,27 +12358,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);
 
-  /* 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)))
+  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))
     {
-      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
@@ -12245,7 +12611,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))
@@ -14768,7 +15134,7 @@ patch_synchronized_statement (node, wfl_op1)
   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)
     {
@@ -14776,6 +15142,10 @@ patch_synchronized_statement (node, wfl_op1)
       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)))
     {
@@ -15213,6 +15583,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: