OSDN Git Service

* parse.y (check_static_final_variable_assignment_flag): Fix spelling.
[pf3gnuchains/gcc-fork.git] / gcc / java / parse.y
index bfb7242..00a5544 100644 (file)
@@ -65,6 +65,7 @@ definitions and other extensions.  */
 #include "function.h"
 #include "except.h"
 #include "defaults.h"
+#include "ggc.h"
 
 #ifndef DIR_SEPARATOR
 #define DIR_SEPARATOR '/'
@@ -81,7 +82,7 @@ static tree  find_field PARAMS ((tree, tree));
 static tree lookup_field_wrapper PARAMS ((tree, tree));
 static int   duplicate_declaration_error_p PARAMS ((tree, tree, tree));
 static void  register_fields PARAMS ((int, tree, tree));
-static tree parser_qualified_classname PARAMS ((int, tree));
+static tree parser_qualified_classname PARAMS ((tree));
 static int  parser_check_super PARAMS ((tree, tree, tree));
 static int  parser_check_super_interface PARAMS ((tree, tree, tree));
 static void check_modifiers_consistency PARAMS ((int));
@@ -92,15 +93,24 @@ static void fix_method_argument_names PARAMS ((tree ,tree));
 static tree method_declarator PARAMS ((tree, tree));
 static void parse_warning_context PARAMS ((tree cl, const char *msg, ...))
   ATTRIBUTE_PRINTF_2;
-static void issue_warning_error_from_context PARAMS ((tree, const char *msg, va_list));
+static void issue_warning_error_from_context PARAMS ((tree, const char *msg, va_list))
+  ATTRIBUTE_PRINTF (2, 0);
 static void parse_ctor_invocation_error PARAMS ((void));
 static tree parse_jdk1_1_error PARAMS ((const char *));
 static void complete_class_report_errors PARAMS ((jdep *));
 static int process_imports PARAMS ((void));
 static void read_import_dir PARAMS ((tree));
 static int find_in_imports_on_demand PARAMS ((tree));
-static int find_in_imports 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));
 static tree resolve_package PARAMS ((tree, tree *));
 static tree lookup_package_type PARAMS ((const char *, int));
 static tree lookup_package_type_and_set_next PARAMS ((const char *, int, tree *));
@@ -120,6 +130,7 @@ static tree patch_method_invocation PARAMS ((tree, tree, tree,
                                            int *, tree *));
 static int breakdown_qualified PARAMS ((tree *, tree *, tree));
 static tree resolve_and_layout PARAMS ((tree, tree));
+static tree qualify_and_find PARAMS ((tree, tree, tree));
 static tree resolve_no_layout PARAMS ((tree, tree));
 static int invocation_mode PARAMS ((tree, int));
 static tree find_applicable_accessible_methods_list PARAMS ((int, tree, 
@@ -136,6 +147,8 @@ static tree obtain_incomplete_type PARAMS ((tree));
 static tree java_complete_lhs PARAMS ((tree));
 static tree java_complete_tree PARAMS ((tree));
 static tree maybe_generate_pre_expand_clinit PARAMS ((tree));
+static int analyze_clinit_body PARAMS ((tree));
+static int maybe_yank_clinit PARAMS ((tree));
 static void java_complete_expand_method PARAMS ((tree));
 static int  unresolved_type_p PARAMS ((tree, tree *));
 static void create_jdep_list PARAMS ((struct parser_ctxt *));
@@ -179,7 +192,7 @@ static tree build_newarray_node PARAMS ((tree, tree, int));
 static tree patch_newarray PARAMS ((tree));
 static tree resolve_type_during_patch PARAMS ((tree));
 static tree build_this PARAMS ((int));
-static tree build_wfl_wrap PARAMS ((tree));
+static tree build_wfl_wrap PARAMS ((tree, int));
 static tree build_return PARAMS ((int, tree));
 static tree patch_return PARAMS ((tree));
 static tree maybe_access_field PARAMS ((tree, tree, tree));
@@ -272,7 +285,7 @@ static int java_decl_equiv PARAMS ((tree, tree));
 static int binop_compound_p PARAMS ((enum tree_code));
 static tree search_loop PARAMS ((tree));
 static int labeled_block_contains_loop_p PARAMS ((tree, tree));
-static void check_abstract_method_definitions PARAMS ((int, tree, tree));
+static int check_abstract_method_definitions PARAMS ((int, tree, tree));
 static void java_check_abstract_method_definitions PARAMS ((tree));
 static void java_debug_context_do PARAMS ((int));
 static void java_parser_context_push_initialized_field PARAMS ((void));
@@ -280,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 */
 
@@ -318,6 +332,7 @@ static void add_inner_class_fields PARAMS ((tree, tree));
 static tree build_dot_class_method PARAMS ((tree));
 static tree build_dot_class_method_invocation PARAMS ((tree));
 static void create_new_parser_context PARAMS ((int));
+static void mark_parser_ctxt PARAMS ((void *));
 
 /* Number of error found so far. */
 int java_error_count; 
@@ -326,8 +341,8 @@ 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;
 
@@ -351,17 +366,12 @@ static enum tree_code binop_lookup[19] =
     EQ_EXPR, NE_EXPR, GT_EXPR, GE_EXPR, LT_EXPR, LE_EXPR,
    };
 #define BINOP_LOOKUP(VALUE)                                            \
-  binop_lookup [((VALUE) - PLUS_TK)%                                   \
-               (sizeof (binop_lookup) / sizeof (binop_lookup[0]))]
+  binop_lookup [((VALUE) - PLUS_TK) % ARRAY_SIZE (binop_lookup)]
 
 /* This is the end index for binary operators that can also be used
    in compound assignements. */
 #define BINOP_COMPOUND_CANDIDATES 11
 
-/* Fake WFL used to report error message. It is initialized once if
-   needed and reused with it's location information is overriden.  */
-tree wfl_operator = NULL_TREE;
-
 /* The "$L" identifier we use to create labels.  */
 static tree label_id = NULL_TREE;
 
@@ -384,6 +394,9 @@ static tree inst_id = NULL_TREE;
 /* The "java.lang.Cloneable" qualified name.  */
 static tree java_lang_cloneable = NULL_TREE;
 
+/* The "java.io.Serializable" qualified name.  */
+static tree java_io_serializable = NULL_TREE; 
+
 /* Context and flag for static blocks */
 static tree current_static_block = NULL_TREE;
 
@@ -393,6 +406,13 @@ 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.  */
+static tree current_this;
+
+/* Hold a list of catch clauses list. The first element of this list is
+   the list of the catch clauses of the currently analysed try block. */
+static tree currently_caught_type_list;
+
 /* Check modifiers. If one doesn't fit, retrieve it in its declaration
    line and point it out.  */
 /* Should point out the one that don't fit. ASCII/unicode, going
@@ -450,6 +470,7 @@ static tree package_list = NULL_TREE;
 %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
@@ -566,11 +587,34 @@ static tree package_list = NULL_TREE;
                        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  */
 goal:
+                {
+                 /* Register static variables with the garbage
+                    collector.  */
+                 ggc_add_tree_root (&label_id, 1);
+                 ggc_add_tree_root (&wfl_string_buffer, 1);
+                 ggc_add_tree_root (&wfl_append, 1);
+                 ggc_add_tree_root (&wfl_to_string, 1);
+                 ggc_add_tree_root (&java_lang_id, 1);
+                 ggc_add_tree_root (&inst_id, 1);
+                 ggc_add_tree_root (&java_lang_cloneable, 1);
+                 ggc_add_tree_root (&java_io_serializable, 1);
+                 ggc_add_tree_root (&current_static_block, 1);
+                 ggc_add_tree_root (&wpv_id, 1);
+                 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_root (&ctxp, 1, 
+                               sizeof (struct parser_ctxt *),
+                               mark_parser_ctxt);
+                 ggc_add_root (&ctxp_for_generation, 1, 
+                               sizeof (struct parser_ctxt *),
+                               mark_parser_ctxt);
+               }
        compilation_unit
                {}
 ;
@@ -615,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  */
@@ -681,7 +729,7 @@ package_declaration:
        PACKAGE_TK name SC_TK
                { 
                  ctxp->package = EXPR_WFL_NODE ($2);
-                 package_list = tree_cons (ctxp->package, NULL, package_list);
+                 register_package (ctxp->package);
                }
 |      PACKAGE_TK error
                {yyerror ("Missing name"); RECOVER;}
@@ -697,7 +745,7 @@ import_declaration:
 single_type_import_declaration:
        IMPORT_TK name SC_TK
                {
-                 tree name = EXPR_WFL_NODE ($2), node, last_name;
+                 tree name = EXPR_WFL_NODE ($2), last_name;
                  int   i = IDENTIFIER_LENGTH (name)-1;
                  const char *last = &IDENTIFIER_POINTER (name)[i];
                  while (last != IDENTIFIER_POINTER (name))
@@ -716,7 +764,7 @@ single_type_import_declaration:
                           IDENTIFIER_POINTER (name), 
                           IDENTIFIER_POINTER (err));
                      else
-                       REGISTER_IMPORT ($2, last_name)
+                       REGISTER_IMPORT ($2, last_name);
                    }
                  else
                    REGISTER_IMPORT ($2, last_name);
@@ -734,10 +782,10 @@ type_import_on_demand_declaration:
                  /* Don't import java.lang.* twice. */
                  if (name != java_lang_id)
                    {
-                     tree node = build_tree_list ($2, NULL_TREE);
                      read_import_dir ($2);
-                     TREE_CHAIN (node) = ctxp->import_demand_list;
-                     ctxp->import_demand_list = node;
+                     ctxp->import_demand_list = 
+                       chainon (ctxp->import_demand_list,
+                                build_tree_list ($2, NULL_TREE));
                    }
                }
 |      IMPORT_TK name DOT_TK error
@@ -751,8 +799,7 @@ type_declaration:
                { end_class_declaration (0); }
 |      interface_declaration
                { end_class_declaration (0); }
-|      SC_TK
-               { $$ = NULL; }
+|      empty_statement
 |      error
                {
                  YYERROR_NOW;
@@ -876,13 +923,12 @@ class_body_declaration:
 
 class_member_declaration:
        field_declaration
-|      field_declaration SC_TK
-               { $$ = $1; }
 |      method_declaration
 |      class_declaration       /* Added, JDK1.1 inner classes */
                { end_class_declaration (1); }
 |      interface_declaration   /* Added, JDK1.1 inner interfaces */
                { end_class_declaration (1); }
+|      empty_statement
 ;
 
 /* 19.8.2 Productions from 8.3: Field Declarations  */
@@ -939,7 +985,15 @@ variable_declarator_id:
 |      identifier error
                {yyerror ("Invalid declaration"); DRECOVER(vdi);}
 |      variable_declarator_id OSB_TK error
-               {yyerror ("']' expected"); DRECOVER(vdi);}
+               { 
+                 tree node = java_lval.node;
+                 if (node && (TREE_CODE (node) == INTEGER_CST
+                              || TREE_CODE (node) == EXPR_WITH_FILE_LOCATION))
+                   yyerror ("Can't specify array dimension in a declaration");
+                 else
+                   yyerror ("']' expected");
+                 DRECOVER(vdi);
+               }
 |      variable_declarator_id CSB_TK error
                {yyerror ("Unbalanced ']'"); DRECOVER(vdi);}
 ;
@@ -1081,9 +1135,7 @@ class_type_list:
 
 method_body:
        block
-|      block SC_TK
-|      SC_TK
-               { $$ = NULL_TREE; } /* Probably not the right thing to do. */
+|      SC_TK { $$ = NULL_TREE; }
 ;
 
 /* 19.8.4 Productions from 8.5: Static Initializers  */
@@ -1092,11 +1144,7 @@ static_initializer:
                {
                  TREE_CHAIN ($2) = CPC_STATIC_INITIALIZER_STMT (ctxp);
                  SET_CPC_STATIC_INITIALIZER_STMT (ctxp, $2);
-               }
-|      static block SC_TK      /* Shouldn't be here. FIXME */
-               {
-                 TREE_CHAIN ($2) = CPC_STATIC_INITIALIZER_STMT (ctxp);
-                 SET_CPC_STATIC_INITIALIZER_STMT (ctxp, $2);
+                 current_static_block = NULL_TREE;
                }
 ;
 
@@ -1162,7 +1210,7 @@ constructor_body:
 
 constructor_block_end:
        block_end
-|      block_end SC_TK
+;
 
 /* Error recovery for that rule moved down expression_statement: rule.  */
 explicit_constructor_invocation:
@@ -1326,6 +1374,8 @@ block_end:
                    DECL_END_SOURCE_LINE (current_function_decl) = 
                      EXPR_WFL_ADD_COL ($1.location, 1);                  
                  $$ = exit_block ();
+                 if (!BLOCK_SUBBLOCKS ($$))
+                   BLOCK_SUBBLOCKS ($$) = empty_stmt_node;
                }
 ;
 
@@ -1391,7 +1441,14 @@ statement_without_trailing_substatement:
 
 empty_statement:
        SC_TK
-               { $$ = empty_stmt_node; }
+               { 
+                 if (flag_extraneous_semicolon)
+                   {
+                     EXPR_WFL_SET_LINECOL (wfl_operator, lineno, -1);
+                     parse_warning_context (wfl_operator, "An empty declaration is a deprecated feature that should not be used");
+                   }
+                 $$ = empty_stmt_node;
+               }
 ;
 
 label_decl:
@@ -1431,20 +1488,17 @@ expression_statement:
                }
 |      error SC_TK 
                {
-                 if (ctxp->prevent_ese != lineno)
-                   yyerror ("Invalid expression statement");
+                 YYNOT_TWICE yyerror ("Invalid expression statement");
                  DRECOVER (expr_stmt);
                }
 |      error OCB_TK
                {
-                 if (ctxp->prevent_ese != lineno)
-                   yyerror ("Invalid expression statement");
+                 YYNOT_TWICE yyerror ("Invalid expression statement");
                  DRECOVER (expr_stmt);
                }
 |      error CCB_TK
                {
-                 if (ctxp->prevent_ese != lineno)
-                   yyerror ("Invalid expression statement");
+                 YYNOT_TWICE yyerror ("Invalid expression statement");
                  DRECOVER (expr_stmt);
                }
 |       this_or_super OP_TK error
@@ -1626,7 +1680,11 @@ do_statement:
 
 for_statement:
        for_begin SC_TK expression SC_TK for_update CP_TK statement
-               { $$ = finish_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7); }
+               {
+                 if (TREE_CODE_CLASS (TREE_CODE ($3)) == 'c')
+                   $3 = build_wfl_node ($3);
+                 $$ = finish_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7);
+               }
 |      for_begin SC_TK SC_TK for_update CP_TK statement
                { 
                  $$ = finish_for_loop (0, NULL_TREE, $4, $6);
@@ -1888,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); }
@@ -2038,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,
@@ -2054,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);
@@ -2076,6 +2118,11 @@ dim_exprs:
 dim_expr:
        OSB_TK expression CSB_TK
                { 
+                 if (JNUMERIC_TYPE_P (TREE_TYPE ($2)))
+                   {
+                     $2 = build_wfl_node ($2);
+                     TREE_TYPE ($2) = NULL_TREE;
+                   }
                  EXPR_WFL_LINECOL ($2) = $1.location;
                  $$ = $2;
                }
@@ -2129,8 +2176,7 @@ field_access:
                { $$ = build_binop (COMPONENT_REF, $2.location, $1, $3); } */
 |      SUPER_TK DOT_TK identifier
                {
-                 tree super_wfl = 
-                   build_wfl_node (super_identifier_node);
+                 tree super_wfl = build_wfl_node (super_identifier_node);
                  EXPR_WFL_LINECOL (super_wfl) = $1.location;
                  $$ = make_qualified_name (super_wfl, $3, $2.location);
                }
@@ -2274,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
@@ -2286,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)));
@@ -2300,8 +2346,7 @@ cast_expression:          /* Error handling here is potentially weak */
                {yyerror ("']' expected, invalid type expression");}
 |       OP_TK error
                {
-                 if (ctxp->prevent_ese != lineno)
-                   yyerror ("Invalid type expression"); RECOVER;
+                 YYNOT_TWICE yyerror ("Invalid type expression"); RECOVER;
                  RECOVER;
                }
 |      OP_TK primitive_type dims CP_TK error
@@ -2518,8 +2563,7 @@ assignment:
                { $$ = build_assignment ($2.token, $2.location, $1, $3); }
 |      left_hand_side assignment_operator error
                {
-                 if (ctxp->prevent_ese != lineno)
-                   yyerror ("Missing term");
+                 YYNOT_TWICE yyerror ("Missing term");
                  DRECOVER (assign);
                }
 ;
@@ -2544,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.
@@ -2567,7 +2630,7 @@ create_new_parser_context (copy_from_previous)
       new->saved_data_ctx = 1;
     }
   else
-    bzero ((PTR) new, sizeof (struct parser_ctxt));
+    memset ((PTR) new, 0, sizeof (struct parser_ctxt));
       
   new->next = ctxp;
   ctxp = new;
@@ -2603,10 +2666,13 @@ java_pop_parser_context (generate)
       next->incomplete_class = ctxp->incomplete_class;
       next->gclass_list = ctxp->gclass_list;
       lineno = ctxp->lineno;
-      finput = ctxp->finput;
-      current_class = ctxp->current_class;
+      current_class = ctxp->class_type;
     }
 
+  /* If the old and new lexers differ, then free the old one.  */
+  if (ctxp->lexer && next && ctxp->lexer != next->lexer)
+    java_destroy_lexer (ctxp->lexer);
+
   /* Set the single import class file flag to 0 for the current list
      of imported things */
   for (current = ctxp->import_list; current; current = TREE_CHAIN (current))
@@ -2646,11 +2712,10 @@ java_parser_context_save_global ()
   else if (ctxp->saved_data)
     create_new_parser_context (1);
 
-  ctxp->finput = finput;
   ctxp->lineno = lineno;
-  ctxp->current_class = current_class;
+  ctxp->class_type = current_class;
   ctxp->filename = input_filename;
-  ctxp->current_function_decl = current_function_decl;
+  ctxp->function_decl = current_function_decl;
   ctxp->saved_data = 1;
 }
 
@@ -2660,11 +2725,16 @@ java_parser_context_save_global ()
 void
 java_parser_context_restore_global ()
 {
-  finput = ctxp->finput;
   lineno = ctxp->lineno;
-  current_class = ctxp->current_class;
+  current_class = ctxp->class_type;
   input_filename = ctxp->filename;
-  current_function_decl = ctxp->current_function_decl;
+  if (wfl_operator)
+    {
+      tree s;
+      BUILD_FILENAME_IDENTIFIER_NODE (s, input_filename);
+      EXPR_WFL_FILENAME_NODE (wfl_operator) = s;
+    }
+  current_function_decl = ctxp->function_decl;
   ctxp->saved_data = 0;
   if (ctxp->saved_data_ctx)
     java_pop_parser_context (0);
@@ -2678,13 +2748,13 @@ static void
 java_parser_context_suspend ()
 {
   /* This makes debugging through java_debug_context easier */
-  static char *name = "<inner buffer context>";
+  static const char *name = "<inner buffer context>";
 
   /* Duplicate the previous context, use it to save the globals we're
      interested in */
   create_new_parser_context (1);
-  ctxp->current_function_decl = current_function_decl;
-  ctxp->current_class = current_class;
+  ctxp->function_decl = current_function_decl;
+  ctxp->class_type = current_class;
 
   /* Then create a new context which inherits all data from the
      previous one. This will be the new current context  */
@@ -2714,8 +2784,8 @@ java_parser_context_resume ()
   restored->class_list = old->class_list;
 
   /* Restore the current class and function from the saver */
-  current_class = saver->current_class;
-  current_function_decl = saver->current_function_decl;
+  current_class = saver->class_type;
+  current_function_decl = saver->function_decl;
 
   /* Retrive the restored context */
   ctxp = restored;
@@ -2752,7 +2822,7 @@ java_parser_context_push_initialized_field ()
 }
 
 /* Pop the lists of initialized field. If this lists aren't empty,
-   remember them so we can use it to create and populate the $finit$
+   remember them so we can use it to create and populate the finit$
    or <clinit> functions. */
 
 static void
@@ -2932,7 +3002,7 @@ yyerror (msg)
   else
     java_error_count++;
   
-  if (elc.col == 0 && msg[1] == ';')
+  if (elc.col == 0 && msg && msg[1] == ';')
     {
       elc.col  = ctxp->p_line->char_col-1;
       elc.line = ctxp->p_line->lineno;
@@ -2965,7 +3035,7 @@ issue_warning_error_from_context (cl, msg, ap)
      const char *msg;
      va_list ap;
 {
-  char *saved, *saved_input_filename;
+  const char *saved, *saved_input_filename;
   char buffer [4096];
   vsprintf (buffer, msg, ap);
   force_error = 1;
@@ -3250,10 +3320,8 @@ build_unresolved_array_type (type_or_wfl)
                 IDENTIFIER_POINTER (EXPR_WFL_NODE (type_or_wfl)),
                 IDENTIFIER_LENGTH (EXPR_WFL_NODE (type_or_wfl)));
   ptr = obstack_finish (&temporary_obstack);
-  return build_expr_wfl (get_identifier (ptr),
-                        EXPR_WFL_FILENAME (type_or_wfl),
-                        EXPR_WFL_LINENO (type_or_wfl),
-                        EXPR_WFL_COLNO (type_or_wfl));
+  EXPR_WFL_NODE (type_or_wfl) = get_identifier (ptr);
+  return type_or_wfl;
 }
 
 static void
@@ -3288,7 +3356,8 @@ check_class_interface_creation (is_interface, flags, raw_name, qualified_name, d
        - Can't be imported by a single type import
        - Can't already exists in the package */
   if (IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (raw_name)
-      && (node = find_name_in_single_imports (raw_name)))
+      && (node = find_name_in_single_imports (raw_name))
+      && !CPC_INNER_P ())
     {
       parse_error_context 
        (cl, "%s name `%s' clashes with imported type `%s'",
@@ -3348,7 +3417,7 @@ check_class_interface_creation (is_interface, flags, raw_name, qualified_name, d
        sca = (GET_CPC_LIST () ? ACC_STATIC : 0);
     }
 
-  /* Inner classes and interfaces can be declared private or protected
+  /* Inner classes can be declared private or protected
      within their enclosing classes. */
   if (CPC_INNER_P ())
     {
@@ -3364,11 +3433,20 @@ check_class_interface_creation (is_interface, flags, raw_name, qualified_name, d
        }
     }
 
-  if (is_interface)
-    check_modifiers ("Illegal modifier `%s' for interface declaration",
-                    flags, INTERFACE_MODIFIERS);
+  if (is_interface) 
+    {
+      if (CPC_INNER_P ())
+       uaaf = INTERFACE_INNER_MODIFIERS;
+      else
+       uaaf = INTERFACE_MODIFIERS;
+      
+      check_modifiers ("Illegal modifier `%s' for interface declaration", 
+                      flags, uaaf);
+    }
   else
-    check_modifiers ("Illegal modifier `%s' for class declaration",
+    check_modifiers ((current_function_decl ?
+                     "Illegal modifier `%s' for local class declaration" :
+                     "Illegal modifier `%s' for class declaration"),
                     flags, uaaf|sca|icaf);
   return 0;
 }
@@ -3447,8 +3525,8 @@ find_as_inner_class (enclosing, name, cl)
     {
       tree acc = NULL_TREE, decl = NULL_TREE, ptr;
 
-      for(qual = EXPR_WFL_QUALIFICATION (cl); qual && !decl; 
-         qual = TREE_CHAIN (qual))
+      for (qual = EXPR_WFL_QUALIFICATION (cl); qual && !decl; 
+          qual = TREE_CHAIN (qual))
        {
          acc = merge_qualified_name (acc, 
                                      EXPR_WFL_NODE (TREE_PURPOSE (qual)));
@@ -3539,9 +3617,9 @@ maybe_make_nested_class_name (name)
   if (CPC_INNER_P ())
     {
       make_nested_class_name (GET_CPC_LIST ());
-      obstack_grow (&temporary_obstack,
-                   IDENTIFIER_POINTER (name), 
-                   IDENTIFIER_LENGTH (name));
+      obstack_grow0 (&temporary_obstack,
+                    IDENTIFIER_POINTER (name), 
+                    IDENTIFIER_LENGTH (name));
       id = get_identifier (obstack_finish (&temporary_obstack));
       if (ctxp->package)
        QUALIFIED_P (id) = 1;
@@ -3625,7 +3703,7 @@ create_interface (flags, id, super)
      tree id, super;
 {
   tree raw_name = EXPR_WFL_NODE (id);
-  tree q_name = parser_qualified_classname (flags & ACC_STATIC, raw_name);
+  tree q_name = parser_qualified_classname (raw_name);
   tree decl = IDENTIFIER_CLASS_VALUE (q_name);
 
   EXPR_WFL_NODE (id) = q_name; /* Keep source location, even if refined. */
@@ -3748,7 +3826,7 @@ create_anonymous_class (location, type_name)
   return class;
 }
 
-/* Create an class in pass1 and return its decl. Return class
+/* Create a class in pass1 and return its decl. Return class
    interface's decl in pass 2.  */
 
 static tree
@@ -3760,7 +3838,7 @@ create_class (flags, id, super, interfaces)
   tree class_id, decl;
   tree super_decl_type;
 
-  class_id = parser_qualified_classname (0, raw_name);
+  class_id = parser_qualified_classname (raw_name);
   decl = IDENTIFIER_CLASS_VALUE (class_id);
   EXPR_WFL_NODE (id) = class_id;
 
@@ -3816,13 +3894,6 @@ create_class (flags, id, super, interfaces)
   CLASS_COMPLETE_P (decl) = 1;
   add_superinterfaces (decl, interfaces);
 
-  /* If the class is a top level inner class, install an alias. */
-  if (INNER_CLASS_DECL_P (decl) && CLASS_STATIC (decl))
-    {
-      tree alias = parser_qualified_classname (1, raw_name);
-      IDENTIFIER_GLOBAL_VALUE (alias) = decl;
-    }
-
   /* Add the private this$<n> field, Replicate final locals still in
      scope as private final fields mangled like val$<local_name>.
      This doesn't not occur for top level (static) inner classes. */
@@ -3845,7 +3916,7 @@ create_class (flags, id, super, interfaces)
 }
 
 /* End a class declaration: register the statements used to create
-   $finit$ and <clinit>, pop the current class and resume the prior
+   finit$ and <clinit>, pop the current class and resume the prior
    parser context if necessary.  */
 
 static void
@@ -3860,6 +3931,13 @@ end_class_declaration (resume)
   POP_CPC ();
   if (resume && no_error_occured)
     java_parser_context_resume ();
+
+  /* We're ending a class declaration, this is a good time to reset
+     the interface cout. Note that might have been already done in
+     create_interface, but if at that time an inner class was being
+     dealt with, the interface count was reset in a context created
+     for the sake of handling inner classes declaration. */
+  ctxp->interface_number = 0;
 }
 
 static void
@@ -3884,21 +3962,21 @@ add_inner_class_fields (class_decl, fct_decl)
       tree decl;
       for (decl = BLOCK_EXPR_DECLS (block); decl; decl = TREE_CHAIN (decl))
        {
-         char *name, *pname;
+         tree name, pname;
          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));
          MANGLE_ALIAS_INITIALIZER_PARAMETER_NAME_ID (pname, DECL_NAME (decl));
-         wfl = build_wfl_node (get_identifier (name));
-         init = build_wfl_node (get_identifier (pname));
+         wfl = build_wfl_node (name);
+         init = build_wfl_node (pname);
          /* Build an initialization for the field: it will be
-            initialized by a parameter added to $finit$, bearing a
+            initialized by a parameter added to finit$, bearing a
             mangled name of the field itself (param$<n>.) The
-            parameter is provided to $finit$ by the constructor
+            parameter is provided to finit$ by the constructor
             invoking it (hence the constructor will also feature a
             hidden parameter, set to the value of the outer context
             local at the time the inner class is created.)
@@ -3907,7 +3985,7 @@ add_inner_class_fields (class_decl, fct_decl)
             be accessed by the inner class. It's actually not trivial
             to minimize these aliases down to the ones really
             used. One way to do that would be to expand all regular
-            methods first, then $finit$ to get a picture of what's
+            methods first, then finit$ to get a picture of what's
             used.  It works with the exception that we would have to
             go back on all constructor invoked in regular methods to
             have their invokation reworked (to include the right amount
@@ -3919,7 +3997,7 @@ add_inner_class_fields (class_decl, fct_decl)
             use.
             
             On the other hand, it only affect local inner classes,
-            whose constructors (and $finit$ call) will be featuring
+            whose constructors (and finit$ call) will be featuring
             unecessary arguments. It's easy for a developper to keep
             this number of parameter down by using the `final'
             keyword only when necessary. For the time being, we can
@@ -3974,9 +4052,26 @@ lookup_field_wrapper (class, name)
      tree class, name;
 {
   tree type = class;
-  tree decl;
+  tree decl = NULL_TREE;
   java_parser_context_save_global ();
-  decl = lookup_field (&type, name);
+
+  /* Last chance: if we're within the context of an inner class, we
+     might be trying to access a local variable defined in an outer
+     context. We try to look for it now. */
+  if (INNER_CLASS_TYPE_P (class))
+    {
+      tree new_name;
+      MANGLE_OUTER_LOCAL_VARIABLE_NAME (new_name, name);
+      decl = lookup_field (&type, new_name);
+      if (decl && decl != error_mark_node)
+       FIELD_LOCAL_ALIAS_USED (decl) = 1;
+    }
+  if (!decl || decl == error_mark_node)
+    {
+      type = class;
+      decl = lookup_field (&type, name);
+    }
+
   java_parser_context_restore_global ();
   return decl == error_mark_node ? NULL : decl;
 }
@@ -4068,11 +4163,11 @@ register_fields (flags, type, variable_list)
       tree init = TREE_VALUE (current);
       tree current_name = EXPR_WFL_NODE (cl);
 
-      /* Can't declare static fields in inner classes */
+      /* Can't declare non-final static fields in inner classes */
       if ((flags & ACC_STATIC) && !TOPLEVEL_CLASS_TYPE_P (class_type)
-         && !CLASS_INTERFACE (TYPE_NAME (class_type)))
+          && !(flags & ACC_FINAL))
        parse_error_context 
-         (cl, "Field `%s' can't be static in innerclass `%s'. Only members of interfaces and top-level classes can be static",
+          (cl, "Field `%s' can't be static in inner class `%s' unless it is final",
           IDENTIFIER_POINTER (EXPR_WFL_NODE (cl)),
           lang_printable_name (class_type, 0));
 
@@ -4104,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)
@@ -4147,8 +4260,8 @@ register_fields (flags, type, variable_list)
   lineno = saved_lineno;
 }
 
-/* Generate $finit$, using the list of initialized fields to populate
-   its body. $finit$'s parameter(s) list is adjusted to include the
+/* Generate finit$, using the list of initialized fields to populate
+   its body. finit$'s parameter(s) list is adjusted to include the
    one(s) used to initialized the field(s) caching outer context
    local(s). */
 
@@ -4217,14 +4330,18 @@ method_header (flags, type, mdecl, throws)
      int flags;
      tree type, mdecl, throws;
 {
-  tree meth = TREE_VALUE (mdecl);
-  tree id = TREE_PURPOSE (mdecl);
   tree type_wfl = NULL_TREE;
   tree meth_name = NULL_TREE;
   tree current, orig_arg, this_class = NULL;
+  tree id, meth;
   int saved_lineno;
   int constructor_ok = 0, must_chain;
   int count;
+
+  if (mdecl == error_mark_node)
+    return error_mark_node;
+  meth = TREE_VALUE (mdecl);
+  id = TREE_PURPOSE (mdecl);
   
   check_modifiers_consistency (flags);
 
@@ -4247,7 +4364,7 @@ method_header (flags, type, mdecl, throws)
          && !CLASS_INTERFACE (TYPE_NAME (this_class)))
        parse_error_context 
          (id, "Class `%s' must be declared abstract to define abstract method `%s'", 
-          IDENTIFIER_POINTER (DECL_NAME (ctxp->current_parsed_class)),
+          IDENTIFIER_POINTER (DECL_NAME (GET_CPC ())),
           IDENTIFIER_POINTER (EXPR_WFL_NODE (id)));
     }
 
@@ -4482,7 +4599,7 @@ finish_method_declaration (method_body)
       && TREE_TYPE (current_function_decl) 
       && TREE_TYPE (TREE_TYPE (current_function_decl)) == void_type_node)
     method_body = build1 (RETURN_EXPR, void_type_node, NULL);
-    
+
   BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (current_function_decl)) = method_body;
   maybe_absorb_scoping_blocks ();
   /* Exit function's body */
@@ -4523,7 +4640,17 @@ verify_constructor_circularity (meth, current)
      tree meth, current;
 {
   static tree list = NULL_TREE;
+  static int initialized_p;
   tree c;
+
+  /* If we haven't already registered LIST with the garbage collector,
+     do so now.  */
+  if (!initialized_p)
+    {
+      ggc_add_tree_root (&list, 1);
+      initialized_p = 1;
+    }
+
   for (c = DECL_CONSTRUCTOR_CALLS (current); c; c = TREE_CHAIN (c))
     {
       if (TREE_VALUE (c) == meth)
@@ -4570,12 +4697,20 @@ check_modifiers_consistency (flags)
   int acc_count = 0;
   tree cl = NULL_TREE;
 
-  THIS_MODIFIER_ONLY (flags, ACC_PUBLIC, 0, acc_count, cl);
-  THIS_MODIFIER_ONLY (flags, ACC_PRIVATE, 1, acc_count, cl);
-  THIS_MODIFIER_ONLY (flags, ACC_PROTECTED, 2, acc_count, cl);
+  THIS_MODIFIER_ONLY (flags, ACC_PUBLIC, PUBLIC_TK, acc_count, cl);
+  THIS_MODIFIER_ONLY (flags, ACC_PRIVATE, PRIVATE_TK, acc_count, cl);
+  THIS_MODIFIER_ONLY (flags, ACC_PROTECTED, PROTECTED_TK, acc_count, cl);
   if (acc_count > 1)
     parse_error_context
-      (cl, "Inconsistent member declaration. At most one of `public', `private', or `protected' may be specified");
+      (cl, "Inconsistent member declaration.  At most one of `public', `private', or `protected' may be specified");
+
+  acc_count = 0;
+  cl = NULL_TREE;
+  THIS_MODIFIER_ONLY (flags, ACC_FINAL, FINAL_TK, acc_count, cl);
+  THIS_MODIFIER_ONLY (flags, ACC_VOLATILE, VOLATILE_TK, acc_count, cl);
+  if (acc_count > 1)
+    parse_error_context (cl,
+                        "Inconsistent member declaration.  At most one of `final' or `volatile' may be specified");
 }
 
 /* Check the methode header METH for abstract specifics features */
@@ -4614,6 +4749,9 @@ method_declarator (id, list)
 
   patch_stage = JDEP_NO_PATCH;
 
+  if (GET_CPC () == error_mark_node)
+    return error_mark_node;
+
   /* If we're dealing with an inner class constructor, we hide the
      this$<n> decl in the name field of its parameter declaration.  We
      also might have to hide the outer context local alias
@@ -4631,7 +4769,7 @@ method_declarator (id, list)
 
       /* Then this$<n> */
       type = TREE_TYPE (DECL_CONTEXT (GET_CPC ()));
-      thisn = build_current_thisn (TYPE_NAME (GET_CPC ()));
+      thisn = build_current_thisn (TREE_TYPE (GET_CPC ()));
       list = tree_cons (build_wfl_node (thisn), build_pointer_type (type),
                        list);
     }
@@ -4728,14 +4866,12 @@ unresolved_type_p (wfl, returned)
    qualification from the current package definition. */
 
 static tree
-parser_qualified_classname (is_static, name)
-     int is_static;
+parser_qualified_classname (name)
      tree name;
 {
   tree nested_class_name;
 
-  if (!is_static 
-      && (nested_class_name = maybe_make_nested_class_name (name)))
+  if ((nested_class_name = maybe_make_nested_class_name (name)))
     return nested_class_name;
 
   if (ctxp->package)
@@ -4863,10 +4999,8 @@ obtain_incomplete_type (type_name)
 
   if (!ptr)
     {
-      push_obstacks (&permanent_obstack, &permanent_obstack);
       BUILD_PTR_FROM_NAME (ptr, name);
       layout_type (ptr);
-      pop_obstacks ();
       TREE_CHAIN (ptr) = ctxp->incomplete_class;
       ctxp->incomplete_class = ptr;
     }
@@ -4895,7 +5029,10 @@ register_incomplete_type (kind, wfl, decl, ptr)
   JDEP_WFL (new) = wfl;
   JDEP_CHAIN (new) = NULL;
   JDEP_MISC (new) = NULL_TREE;
-  if ((kind == JDEP_SUPER || kind == JDEP_INTERFACE)
+  /* For some dependencies, set the enclosing class of the current
+     class to be the enclosing context */
+  if ((kind == JDEP_SUPER || kind == JDEP_INTERFACE 
+       || kind == JDEP_ANONYMOUS || kind == JDEP_FIELD)
       && GET_ENCLOSING_CPC ())
     JDEP_ENCLOSING (new) = TREE_VALUE (GET_ENCLOSING_CPC ());
   else
@@ -4946,7 +5083,7 @@ java_check_circular_reference ()
    count is kept of the number of crafted parameters. MODE governs
    what eventually gets created: something suitable for a function
    creation or a function invocation, either the constructor or
-   $finit$.  */
+   finit$.  */
 
 static tree
 build_alias_initializer_parameter_list (mode, class_type, parm, artificial)
@@ -4955,17 +5092,21 @@ build_alias_initializer_parameter_list (mode, class_type, parm, artificial)
     int *artificial;
 {
   tree field;
+  tree additional_parms = NULL_TREE;
+
   for (field = TYPE_FIELDS (class_type); field; field = TREE_CHAIN (field))
     if (FIELD_LOCAL_ALIAS (field))
       {
-       char *buffer = IDENTIFIER_POINTER (DECL_NAME (field));
+       const char *buffer = IDENTIFIER_POINTER (DECL_NAME (field));
        tree purpose = NULL_TREE, value = NULL_TREE, name = NULL_TREE;
+       tree mangled_id;
 
        switch (mode)
          {
          case AIPL_FUNCTION_DECLARATION:
-           MANGLE_ALIAS_INITIALIZER_PARAMETER_NAME_STR (buffer, &buffer [4]);
-           purpose = build_wfl_node (get_identifier (buffer));
+           MANGLE_ALIAS_INITIALIZER_PARAMETER_NAME_STR (mangled_id, 
+                                                        &buffer [4]);
+           purpose = build_wfl_node (mangled_id);
            if (TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE)
              value = build_wfl_node (TYPE_NAME (TREE_TYPE (field)));
            else
@@ -4973,13 +5114,14 @@ build_alias_initializer_parameter_list (mode, class_type, parm, artificial)
            break;
 
          case AIPL_FUNCTION_CREATION:
-           MANGLE_ALIAS_INITIALIZER_PARAMETER_NAME_STR (buffer, &buffer [4]);
-           purpose = get_identifier (buffer);
+           MANGLE_ALIAS_INITIALIZER_PARAMETER_NAME_STR (purpose,
+                                                        &buffer [4]);
            value = TREE_TYPE (field);
            break;
 
          case AIPL_FUNCTION_FINIT_INVOCATION:
-           MANGLE_ALIAS_INITIALIZER_PARAMETER_NAME_STR (buffer, &buffer [4]);
+           MANGLE_ALIAS_INITIALIZER_PARAMETER_NAME_STR (mangled_id, 
+                                                        &buffer [4]);
            /* Now, this is wrong. purpose should always be the NAME
               of something and value its matching value (decl, type,
               etc...) FIXME -- but there is a lot to fix. */
@@ -4987,7 +5129,7 @@ build_alias_initializer_parameter_list (mode, class_type, parm, artificial)
            /* When invoked for this kind of operation, we already
               know whether a field is used or not. */
            purpose = TREE_TYPE (field);
-           value = build_wfl_node (get_identifier (buffer));
+           value = build_wfl_node (mangled_id);
            break;
 
          case AIPL_FUNCTION_CTOR_INVOCATION:
@@ -5005,11 +5147,19 @@ build_alias_initializer_parameter_list (mode, class_type, parm, artificial)
              }
            break;
          }
-       parm = tree_cons (purpose, value, parm);
+       additional_parms = tree_cons (purpose, value, additional_parms);
        if (artificial)
          *artificial +=1;
       }
-  return parm;
+  if (additional_parms)
+    {
+      if (ANONYMOUS_CLASS_P (class_type) 
+          && mode == AIPL_FUNCTION_CTOR_INVOCATION)
+        additional_parms = nreverse (additional_parms);
+      parm = chainon (additional_parms, parm);
+    }
+
+   return parm;
 }
 
 /* Craft a constructor for CLASS_DECL -- what we should do when none
@@ -5028,8 +5178,6 @@ craft_constructor (class_decl, args)
   tree decl, ctor_name;
   char buffer [80];
   
-  push_obstacks (&permanent_obstack, &permanent_obstack);
-
   /* The constructor name is <init> unless we're dealing with an
      anonymous class, in which case the name will be fixed after having
      be expanded. */
@@ -5066,9 +5214,7 @@ craft_constructor (class_decl, args)
   fix_method_argument_names (parm, decl);
   /* Now, mark the artificial parameters. */
   DECL_FUNCTION_NAP (decl) = artificial;
-
-  pop_obstacks ();
-  DECL_CONSTRUCTOR_P (decl) = 1;
+  DECL_FUNCTION_SYNTHETIC_CTOR (decl) = DECL_CONSTRUCTOR_P (decl) = 1;
 }
 
 
@@ -5116,13 +5262,10 @@ safe_layout_class (class)
      tree class;
 {
   tree save_current_class = current_class;
-  char *save_input_filename = input_filename;
+  const char *save_input_filename = input_filename;
   int save_lineno = lineno;
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
-
   layout_class (class);
-  pop_obstacks ();
 
   current_class = save_current_class;
   input_filename = save_input_filename;
@@ -5147,7 +5290,8 @@ jdep_resolve_class (dep)
     
   if (!decl)
     complete_class_report_errors (dep);
-
+  else if (PURE_INNER_CLASS_DECL_P (decl))
+    check_inner_class_access (decl, JDEP_ENCLOSING (dep), JDEP_WFL (dep));
   return decl;
 }
 
@@ -5161,12 +5305,8 @@ java_complete_class ()
   int error_found;
   tree type;
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
-
-  /* Process imports and reverse the import on demand list */
+  /* Process imports */
   process_imports ();
-  if (ctxp->import_demand_list)
-    ctxp->import_demand_list = nreverse (ctxp->import_demand_list);
 
   /* Rever things so we have the right order */
   ctxp->class_list = nreverse (ctxp->class_list);
@@ -5199,12 +5339,11 @@ java_complete_class ()
                /* We do part of the job done in add_field */
                tree field_decl = JDEP_DECL (dep);
                tree field_type = TREE_TYPE (decl);
-               push_obstacks (&permanent_obstack, &permanent_obstack);
                if (TREE_CODE (field_type) == RECORD_TYPE)
                  field_type = promote_type (field_type);
-               pop_obstacks ();
                TREE_TYPE (field_decl) = field_type;
                DECL_ALIGN (field_decl) = 0;
+               DECL_USER_ALIGN (field_decl) = 0;
                layout_decl (field_decl, 0);
                SOURCE_FRONTEND_DEBUG 
                  (("Completed field/var decl `%s' with `%s'",
@@ -5242,7 +5381,6 @@ java_complete_class ()
              if (!error_found)
                {
                  tree mdecl = JDEP_DECL (dep), signature;
-                 push_obstacks (&permanent_obstack, &permanent_obstack);
                  /* Recompute and reset the signature, check first that
                     all types are now defined. If they're not,
                     dont build the signature. */
@@ -5251,7 +5389,6 @@ java_complete_class ()
                      signature = build_java_signature (TREE_TYPE (mdecl));
                      set_java_signature (TREE_TYPE (mdecl), signature);
                    }
-                 pop_obstacks ();
                }
              else
                continue;
@@ -5296,7 +5433,6 @@ java_complete_class ()
            }
        }
     }
-  pop_obstacks ();
   return;
 }
 
@@ -5330,7 +5466,10 @@ resolve_class (enclosing, class_type, decl, cl)
   while (name[0] == '[')
     name++;
   if (base != name)
-    TYPE_NAME (class_type) = get_identifier (name);
+    {
+      TYPE_NAME (class_type) = get_identifier (name);
+      WFL_STRIP_BRACKET (cl, cl);
+    }
 
   /* 2- Resolve the bare type */
   if (!(resolved_type_decl = do_resolve_class (enclosing, class_type, 
@@ -5370,25 +5509,57 @@ do_resolve_class (enclosing, class_type, decl, cl)
      tree enclosing, class_type, decl, cl;
 {
   tree new_class_decl;
-  tree original_name = NULL_TREE;
 
   /* Do not try to replace TYPE_NAME (class_type) by a variable, since
-     its is changed by find_in_imports{_on_demand} */
+     it is changed by find_in_imports{_on_demand} and (but it doesn't
+     really matter) qualify_and_find */
 
   /* 0- Search in the current class as an inner class */
 
   /* Maybe some code here should be added to load the class or
      something, at least if the class isn't an inner class and ended
      being loaded from class file. FIXME. */
-  if ((new_class_decl = find_as_inner_class (enclosing, class_type, cl)))
-    return new_class_decl;
+  while (enclosing)
+    {
+      tree name;
+      tree intermediate;
 
-  /* 1- Check for the type in single imports */
-  if (find_in_imports (class_type))
-    return NULL_TREE;
+      if ((new_class_decl = find_as_inner_class (enclosing, class_type, cl)))
+        return new_class_decl;
+
+      intermediate = enclosing;
+      /* Explore enclosing contexts. */
+      while (INNER_CLASS_DECL_P (intermediate))
+       {
+         intermediate = DECL_CONTEXT (intermediate);
+         if ((new_class_decl = find_as_inner_class (intermediate, 
+                                                    class_type, cl)))
+           return new_class_decl;
+       }
+
+      /* Now go to the upper classes, bail out if necessary. */
+      enclosing = CLASSTYPE_SUPER (TREE_TYPE (enclosing));
+      if (!enclosing || enclosing == object_type_node)
+       break;
+      
+      if (TREE_CODE (enclosing) == RECORD_TYPE)
+       {
+         enclosing = TYPE_NAME (enclosing);
+         continue;
+       }
+
+      if (TREE_CODE (enclosing) == IDENTIFIER_NODE)
+       BUILD_PTR_FROM_NAME (name, enclosing);
+      else
+       name = enclosing;
+      enclosing = do_resolve_class (NULL, name, NULL, NULL);
+    }
+
+  /* 1- Check for the type in single imports. This will change
+     TYPE_NAME() if something relevant is found */
+  find_in_imports (class_type);
 
-  /* 2- And check for the type in the current compilation unit. If it fails,
-     try with a name qualified with the package name we've seen so far */
+  /* 2- And check for the type in the current compilation unit */
   if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type))))
     {
       if (!CLASS_LOADED_P (TREE_TYPE (new_class_decl)) &&
@@ -5397,41 +5568,13 @@ do_resolve_class (enclosing, class_type, decl, cl)
       return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
     }
 
-  original_name = TYPE_NAME (class_type);
+  /* 3- Search according to the current package definition */
   if (!QUALIFIED_P (TYPE_NAME (class_type)))
     {
-      tree package;
-      for (package = package_list; package; package = TREE_CHAIN (package))
-       {
-         tree new_qualified;
-         
-         new_qualified = merge_qualified_name (TREE_PURPOSE (package),
-                                               original_name);
-         TYPE_NAME (class_type) = new_qualified;
-         new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
-         if (!new_class_decl)
-           load_class (TYPE_NAME (class_type), 0);
-         new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
-         if (new_class_decl)
-           {
-             if (!CLASS_LOADED_P (TREE_TYPE (new_class_decl)) &&
-                 !CLASS_FROM_SOURCE_P (TREE_TYPE (new_class_decl)))
-               load_class (TYPE_NAME (class_type), 0);
-             return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
-           }
-       }
-    }
-
-  TYPE_NAME (class_type) = original_name;
-
-  /* 3- Check an other compilation unit that bears the name of type */
-  load_class (TYPE_NAME (class_type), 0);
-  if (check_pkg_class_access (TYPE_NAME (class_type), 
-                             (cl ? cl : lookup_cl (decl))))
-    return NULL_TREE;
-
-  if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type))))
-    return new_class_decl;
+      if ((new_class_decl = qualify_and_find (class_type, ctxp->package,
+                                            TYPE_NAME (class_type))))
+       return new_class_decl;
+    }
 
   /* 4- Check the import on demands. Don't allow bar.baz to be
      imported from foo.* */
@@ -5439,10 +5582,57 @@ do_resolve_class (enclosing, class_type, decl, cl)
     if (find_in_imports_on_demand (class_type))
       return NULL_TREE;
 
-  /* 5- Last call for a resolution */
+  /* If found in find_in_imports_on_demant, the type has already been
+     loaded. */
+  if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type))))
+    return new_class_decl;
+
+  /* 5- Try with a name qualified with the package name we've seen so far */
+  if (!QUALIFIED_P (TYPE_NAME (class_type)))
+    {
+      tree package;
+
+      /* If there is a current package (ctxp->package), it's the first
+        element of package_list and we can skip it. */
+      for (package = (ctxp->package ? 
+                     TREE_CHAIN (package_list) : package_list);
+          package; package = TREE_CHAIN (package))
+       if ((new_class_decl = qualify_and_find (class_type,
+                                              TREE_PURPOSE (package), 
+                                              TYPE_NAME (class_type))))
+         return new_class_decl;
+    }
+
+  /* 5- Check an other compilation unit that bears the name of type */
+  load_class (TYPE_NAME (class_type), 0);
+  if (check_pkg_class_access (TYPE_NAME (class_type), 
+                             (cl ? cl : lookup_cl (decl))))
+    return NULL_TREE;
+
+  /* 6- Last call for a resolution */
   return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
 }
 
+static tree
+qualify_and_find (class_type, package, name)
+     tree class_type, package, name;
+{
+  tree new_qualified = merge_qualified_name (package, name);
+  tree new_class_decl;
+
+  if (!IDENTIFIER_CLASS_VALUE (new_qualified))
+    load_class (new_qualified, 0);
+  if ((new_class_decl = IDENTIFIER_CLASS_VALUE (new_qualified)))
+    {
+      if (!CLASS_LOADED_P (TREE_TYPE (new_class_decl)) &&
+         !CLASS_FROM_SOURCE_P (TREE_TYPE (new_class_decl)))
+       load_class (new_qualified, 0);
+      TYPE_NAME (class_type) = new_qualified;
+      return IDENTIFIER_CLASS_VALUE (new_qualified);
+    }
+  return NULL_TREE;
+}
+
 /* Resolve NAME and lay it out (if not done and if not the current
    parsed class). Return a decl node. This function is meant to be
    called when type resolution is necessary during the walk pass.  */
@@ -5452,7 +5642,7 @@ resolve_and_layout (something, cl)
      tree something;
      tree cl;
 {
-  tree decl;
+  tree decl, decl_type;
 
   /* Don't do that on the current class */
   if (something == current_class)
@@ -5495,13 +5685,14 @@ resolve_and_layout (something, cl)
     return NULL_TREE;
 
   /* Resolve and layout if necessary */
-  layout_class_methods (TREE_TYPE (decl));
-  /* Check methods, but only once */
-  if (CLASS_FROM_SOURCE_P (TREE_TYPE (decl)) 
-      && !CLASS_LOADED_P (TREE_TYPE (decl)))
-    CHECK_METHODS (decl);
-  if (TREE_TYPE (decl) != current_class && !CLASS_LOADED_P (TREE_TYPE (decl)))
-    safe_layout_class (TREE_TYPE (decl));
+  decl_type = TREE_TYPE (decl);
+  layout_class_methods (decl_type);
+  /* Check methods */
+  if (CLASS_FROM_SOURCE_P (decl_type))
+    java_check_methods (decl);
+  /* Layout the type if necessary */ 
+  if (decl_type != current_class && !CLASS_LOADED_P (decl_type))
+    safe_layout_class (decl_type);
 
   return decl;
 }
@@ -5678,7 +5869,7 @@ check_method_redefinition (class, method)
   tree redef, name;
   tree cl = DECL_NAME (method);
   tree sig = TYPE_ARGUMENT_SIGNATURE (TREE_TYPE (method));
-  /* decl name of artificial <clinit> and $finit$ doesn't need to be
+  /* decl name of artificial <clinit> and finit$ doesn't need to be
      fixed and checked */
 
   /* Reset the method name before running the check. If it returns 1,
@@ -5705,13 +5896,15 @@ check_method_redefinition (class, method)
   return 0;
 }
 
-static void
+/* Return 1 if check went ok, 0 otherwise.  */
+static int
 check_abstract_method_definitions (do_interface, class_decl, type)
      int do_interface;
      tree class_decl, type;
 {
   tree class = TREE_TYPE (class_decl);
   tree method, end_type;
+  int ok = 1;
 
   end_type = (do_interface ? object_type_node : type);
   for (method = TYPE_METHODS (type); method; method = TREE_CHAIN (method))
@@ -5748,7 +5941,9 @@ check_abstract_method_definitions (do_interface, class_decl, type)
              other_name = EXPR_WFL_NODE (other_name);
            if (!DECL_CLINIT_P (other_method)
                && !DECL_CONSTRUCTOR_P (other_method)
-               && method_name == other_name && method_sig == s)
+               && method_name == other_name
+               && method_sig == s
+               && !METHOD_ABSTRACT (other_method))
              {
                found = 1;
                break;
@@ -5782,13 +5977,27 @@ check_abstract_method_definitions (do_interface, class_decl, type)
             IDENTIFIER_POINTER (ccn),
             (CLASS_INTERFACE (class_decl) ? "interface" : "class"),
             IDENTIFIER_POINTER (DECL_NAME (class_decl)));
-         
+         ok = 0;
          free (t);
-         
+
          if (saved_wfl)
            DECL_NAME (method) = saved_wfl;
        }
     }
+
+  if (ok && do_interface)
+    {
+      /* Check for implemented interfaces. */
+      int i;
+      tree vector = TYPE_BINFO_BASETYPES (type);
+      for (i = 1; ok && vector && i < TREE_VEC_LENGTH (vector); i++)
+       {
+         tree super = BINFO_TYPE (TREE_VEC_ELT (vector, i));
+         ok = check_abstract_method_definitions (1, class_decl, super);
+       }
+    }
+
+  return ok;
 }
 
 /* Check that CLASS_DECL somehow implements all inherited abstract
@@ -5845,6 +6054,23 @@ check_method_types_complete (decl)
   return 1;
 }
 
+/* Visible interface to check methods contained in CLASS_DECL */
+
+void
+java_check_methods (class_decl)
+     tree class_decl;
+{
+  if (CLASS_METHOD_CHECKED_P (TREE_TYPE (class_decl)))
+    return;
+
+  if (CLASS_INTERFACE (class_decl))
+    java_check_abstract_methods (class_decl);
+  else
+    java_check_regular_methods (class_decl);
+  
+  CLASS_METHOD_CHECKED_P (TREE_TYPE (class_decl)) = 1;
+}
+
 /* Check all the methods of CLASS_DECL. Methods are first completed
    then checked according to regular method existance rules.  If no
    constructor for CLASS_DECL were encountered, then build its
@@ -6253,12 +6479,15 @@ lookup_cl (decl)
     return NULL_TREE;
 
   if (cl == NULL_TREE)
-    cl = build_expr_wfl (NULL_TREE, NULL, 0, 0);
+    {
+      cl = build_expr_wfl (NULL_TREE, NULL, 0, 0);
+      ggc_add_tree_root (&cl, 1);
+    }
 
   EXPR_WFL_FILENAME_NODE (cl) = get_identifier (DECL_SOURCE_FILE (decl));
   EXPR_WFL_SET_LINECOL (cl, DECL_SOURCE_LINE_FIRST (decl), -1);
 
-  line = java_get_line_col (IDENTIFIER_POINTER (EXPR_WFL_FILENAME_NODE (cl)),
+  line = java_get_line_col (EXPR_WFL_FILENAME (cl), 
                            EXPR_WFL_LINENO (cl), EXPR_WFL_COLNO (cl));
 
   found = strstr ((const char *)line, 
@@ -6299,10 +6528,29 @@ process_imports ()
       /* Don't load twice something already defined. */
       if (IDENTIFIER_CLASS_VALUE (to_be_found))
        continue;
-      QUALIFIED_P (to_be_found) = 1;
-      load_class (to_be_found, 0);
-      error_found =
-       check_pkg_class_access (to_be_found, TREE_PURPOSE (import));
+      
+      while (1)
+       {
+         tree left;
+
+         QUALIFIED_P (to_be_found) = 1;
+         load_class (to_be_found, 0);
+         error_found =
+           check_pkg_class_access (to_be_found, TREE_PURPOSE (import));
+         
+         /* We found it, we can bail out */
+         if (IDENTIFIER_CLASS_VALUE (to_be_found))
+           break;
+
+         /* We haven't found it. Maybe we're trying to access an
+            inner class.  The only way for us to know is to try again
+            after having dropped a qualifier. If we can't break it further,
+            we have an error. */
+         if (breakdown_qualified (&left, NULL, to_be_found))
+           break;
+
+         to_be_found = left;
+       }
       if (!IDENTIFIER_CLASS_VALUE (to_be_found))
        {
          parse_error_context (TREE_PURPOSE (import),
@@ -6316,10 +6564,10 @@ process_imports ()
   return 0;
 }
 
-/* Possibly find a class imported by a single-type import statement. Return
-   1 if an error occured, 0 otherwise. */
+/* Possibly find and mark a class imported by a single-type import
+   statement.  */
 
-static int
+static void
 find_in_imports (class_type)
      tree class_type;
 {
@@ -6331,7 +6579,6 @@ find_in_imports (class_type)
        TYPE_NAME (class_type) = EXPR_WFL_NODE (TREE_PURPOSE (import));
        QUALIFIED_P (TYPE_NAME (class_type)) = 1;
       }
-  return 0;
 }
 
 static int
@@ -6512,7 +6759,8 @@ find_in_imports_on_demand (class_type)
            {
              seen_once++;
              parse_error_context 
-               (import, "Type `%s' also potentially defined in package `%s'",
+               (TREE_PURPOSE (import), 
+                "Type `%s' also potentially defined in package `%s'",
                 IDENTIFIER_POINTER (TYPE_NAME (class_type)),
                 IDENTIFIER_POINTER (EXPR_WFL_NODE (TREE_PURPOSE (import))));
            }
@@ -6541,6 +6789,30 @@ find_in_imports_on_demand (class_type)
     return (seen_once < 0 ? 0 : seen_once); /* It's ok not to have found */
 }
 
+/* Add package NAME to the list of package encountered so far. To
+   speed up class lookup in do_resolve_class, we make sure a
+   particular package is added only once.  */
+
+static void
+register_package (name)
+     tree name;
+{
+  static struct hash_table _pht, *pht = NULL;
+
+  if (!pht)
+    {
+      hash_table_init (&_pht, hash_newfunc, 
+                      java_hash_hash_tree_node, java_hash_compare_tree_node);
+      pht = &_pht;
+    }
+  
+  if (!hash_lookup (pht, (const hash_table_key) name, FALSE, NULL))
+    {
+      package_list = chainon (package_list, build_tree_list (name, NULL));
+      hash_lookup (pht, (const hash_table_key) name, TRUE, NULL);
+    }
+}
+
 static tree
 resolve_package (pkg, next)
      tree pkg, *next;
@@ -6610,7 +6882,10 @@ resolve_package (pkg, next)
        if ((type_name = resolve_no_layout (acc, NULL_TREE)))
          {
            type_name = acc;
-           *next = TREE_CHAIN (current);
+           /* resolve_package should be used in a loop, hence we
+              point at this one to naturally process the next one at
+              the next iteration. */
+           *next = current;
            break;
          }
       }
@@ -6652,6 +6927,42 @@ lookup_package_type (name, from)
   return get_identifier (subname);
 }
 
+static void
+check_inner_class_access (decl, enclosing_decl, cl)
+     tree decl, enclosing_decl, cl;
+{
+  int access = 0;
+
+  /* We don't issue an error message when CL is null. CL can be null
+     as a result of processing a JDEP crafted by source_start_java_method
+     for the purpose of patching its parm decl. But the error would
+     have been already trapped when fixing the method's signature.
+     DECL can also be NULL in case of earlier errors. */
+  if (!decl || !cl)
+    return;
+
+  /* We grant access to private and protected inner classes if the
+     location from where we're trying to access DECL is an enclosing
+     context for DECL or if both have a common enclosing context. */
+  if (CLASS_PRIVATE (decl))
+    access = 1;
+  if (CLASS_PROTECTED (decl))
+    access = 2;
+  if (!access)
+    return;
+      
+  if (common_enclosing_context_p (TREE_TYPE (enclosing_decl),
+                                 TREE_TYPE (decl))
+      || enclosing_context_p (TREE_TYPE (enclosing_decl),
+                             TREE_TYPE (decl)))
+    return;
+
+  parse_error_context (cl, "Can't access %s nested %s %s. Only public classes and interfaces in other packages can be accessed",
+                      (access == 1 ? "private" : "protected"),
+                      (CLASS_INTERFACE (decl) ? "interface" : "class"),
+                      lang_printable_name (decl, 0));
+}
+
 /* Check that CLASS_NAME refers to a PUBLIC class. Return 0 if no
    access violations were found, 1 otherwise.  */
 
@@ -6760,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);
       
@@ -6804,10 +7116,6 @@ source_start_java_method (fndecl)
   tree tem;
   tree parm_decl;
   int i;
-#if 0
-  int flag_inner = DECL_CONSTRUCTOR_P (fndecl)
-      && (INNER_CLASS_TYPE_P (DECL_CONTEXT (fndecl)) ? 1 : 0);
-#endif
 
   if (!fndecl)
     return;
@@ -6841,32 +7149,12 @@ 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;
-
-      BLOCK_CHAIN_DECL (parm_decl);
-
-#if 0
-      /* If this is a constructor of a inner class, hide the extra
-         this$<n> parameter */
-      if (i == 0 && flag_inner)
-       {
-         tree link = TREE_CHAIN (tem);
-         tree type = DECL_CONTEXT (TYPE_NAME (DECL_CONTEXT (fndecl)));
-
-         type = build_pointer_type (TREE_TYPE (type));
-         parm_decl = build_decl (PARM_DECL,
-                                 build_current_thisn (current_class), type);
-         BLOCK_CHAIN_DECL (parm_decl);
-         /* We hide the this$<n> decl in the name field of its
-            parameter declaration. */
-         parm_decl = build_tree_list (DECL_NAME (parm_decl), type);
-         TREE_CHAIN (tem) = parm_decl;
-         TREE_CHAIN (parm_decl) = link;
-         tem = parm_decl;
-         i++;
+       {
+         MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (parm_decl);
+         LOCAL_FINAL (parm_decl) = 1;
        }
-#endif
 
+      BLOCK_CHAIN_DECL (parm_decl);
     }
   tem = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl));
   BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)) =
@@ -7010,7 +7298,6 @@ source_end_java_method ()
     }
 
   current_function_decl = NULL_TREE;
-  permanent_allocation (1);
   java_parser_context_restore_global ();
   asynchronous_exceptions = flag_asynchronous_exceptions;
 }
@@ -7057,9 +7344,6 @@ add_stmt_to_compound (existing, type, stmt)
     return stmt;
 }
 
-/* Hold THIS for the scope of the current public method decl.  */
-static tree current_this;
-
 void java_layout_seen_class_methods ()
 {
   tree previous_list = all_class_list;
@@ -7086,8 +7370,16 @@ void
 java_reorder_fields ()
 {
   static tree stop_reordering = NULL_TREE;
-
+  static int initialized_p;
   tree current;
+
+  /* Register STOP_REORDERING with the garbage collector.  */
+  if (!initialized_p)
+    {
+      ggc_add_tree_root (&stop_reordering, 1);
+      initialized_p = 1;
+    }
+
   for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current))
     {
       current_class = TREE_TYPE (TREE_VALUE (current));
@@ -7140,7 +7432,7 @@ java_layout_classes ()
   /* Then check the methods of all parsed classes */
   for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current))
     if (CLASS_FROM_SOURCE_P (TREE_TYPE (TREE_VALUE (current))))
-      CHECK_METHODS (TREE_VALUE (current));
+      java_check_methods (TREE_VALUE (current));
   java_parse_abort_on_error ();
 
   for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current))
@@ -7205,7 +7497,7 @@ java_complete_expand_class (outer)
    we expand regular methods first. This allows us get an estimate on
    how outer context local alias fields are really used so we can add
    to the constructor just enough code to initialize them properly (it
-   also lets us generate $finit$ correctly.) Then we expand the
+   also lets us generate finit$ correctly.) Then we expand the
    constructors and then <clinit>.  */
 
 static void
@@ -7216,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 ();
 
@@ -7226,7 +7526,7 @@ java_complete_expand_methods (class_decl)
   first_decl = TYPE_METHODS (current_class);
   clinit = maybe_generate_pre_expand_clinit (current_class);
 
-  /* Then generate $finit$ (if we need to) because constructor will
+  /* Then generate finit$ (if we need to) because constructor will
    try to use it.*/
   if (TYPE_FINIT_STMT_LIST (current_class))
     {
@@ -7248,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);
@@ -7257,20 +7565,36 @@ java_complete_expand_methods (class_decl)
   /* First, do the ordinary methods. */
   for (decl = first_decl; decl; decl = TREE_CHAIN (decl))
     {
-      /* Skip abstract or native methods */
-      if (METHOD_ABSTRACT (decl) || METHOD_NATIVE (decl) 
+      /* Skip abstract or native methods -- but do handle native
+        methods when generating JNI stubs.  */
+      if (METHOD_ABSTRACT (decl)
+         || (! flag_jni && METHOD_NATIVE (decl))
          || DECL_CONSTRUCTOR_P (decl) || DECL_CLINIT_P (decl))
        continue;
+
+      if (METHOD_NATIVE (decl))
+       {
+         tree body = build_jni_stub (decl);
+         BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (decl)) = body;
+       }
+
       java_complete_expand_method (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 */
@@ -7285,14 +7609,19 @@ 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;
 }
 
-/* Hold a list of catch clauses list. The first element of this list is
-   the list of the catch clauses of the currently analysed try block. */
-static tree currently_caught_type_list;
-
 /* Attempt to create <clinit>. Pre-expand static fields so they can be
    safely used in some other methods/constructors.  */
 
@@ -7324,26 +7653,28 @@ maybe_generate_pre_expand_clinit (class_type)
   for (current = TYPE_CLINIT_STMT_LIST (class_type); current;
        current = TREE_CHAIN (current))
     {
+      tree stmt = current;
       /* We build the assignment expression that will initialize the
         field to its value. There are strict rules on static
         initializers (8.5). FIXME */
-      tree stmt = build_debugable_stmt (EXPR_WFL_LINECOL (current), current);
+      if (TREE_CODE (stmt) != BLOCK && stmt != empty_stmt_node)
+       stmt = build_debugable_stmt (EXPR_WFL_LINECOL (stmt), stmt);
       java_method_add_stmt (mdecl, stmt);
     }
 
   end_artificial_method_body (mdecl);
 
-  /* Now we want to place <clinit> as the last method for interface so
-     that it doesn't interfere with the dispatch table based
-     lookup. */
-  if (CLASS_INTERFACE (TYPE_NAME (class_type))
-      && TREE_CHAIN (TYPE_METHODS (class_type)))
+  /* Now we want to place <clinit> as the last method (because we need
+     it at least for interface so that it doesn't interfere with the
+     dispatch table based lookup. */
+  if (TREE_CHAIN (TYPE_METHODS (class_type)))
     {
-      tree current = 
-       TYPE_METHODS (class_type) = TREE_CHAIN (TYPE_METHODS (class_type));
+      current = TREE_CHAIN (TYPE_METHODS (class_type));
+      TYPE_METHODS (class_type) = current;
 
       while (TREE_CHAIN (current))
        current = TREE_CHAIN (current);
+
       TREE_CHAIN (current) = mdecl;
       TREE_CHAIN (mdecl) = NULL_TREE;
     }
@@ -7351,18 +7682,143 @@ maybe_generate_pre_expand_clinit (class_type)
   return mdecl;
 }
 
-/* Complete and expand a method.  */
+/* Analyzes a method body and look for something that isn't a
+   MODIFY_EXPR. */
 
-static void
-java_complete_expand_method (mdecl)
-     tree mdecl;
+static int
+analyze_clinit_body (bbody)
+     tree bbody;
 {
-  current_function_decl = mdecl;
-  /* Fix constructors before expanding them */
-  if (DECL_CONSTRUCTOR_P (mdecl))
-    fix_constructors (mdecl);
-  
-  /* Expand functions that have a body */
+  while (bbody)
+    switch (TREE_CODE (bbody))
+      {
+      case BLOCK:
+       bbody = BLOCK_EXPR_BODY (bbody);
+       break;
+       
+      case EXPR_WITH_FILE_LOCATION:
+       bbody = EXPR_WFL_NODE (bbody);
+       break;
+       
+      case COMPOUND_EXPR:
+       if (analyze_clinit_body (TREE_OPERAND (bbody, 0)))
+         return 1;
+       bbody = TREE_OPERAND (bbody, 1);
+       break;
+       
+      case MODIFY_EXPR:
+       bbody = NULL_TREE;
+       break;
+
+      default:
+       bbody = NULL_TREE;
+       return 1;
+      }
+  return 0;
+}
+
+
+/* See whether we could get rid of <clinit>. Criteria are: all static
+   final fields have constant initial values and the body of <clinit>
+   is empty. Return 1 if <clinit> was discarded, 0 otherwise. */
+
+static int
+maybe_yank_clinit (mdecl)
+     tree mdecl;
+{
+  tree type, current;
+  tree fbody, bbody;
+  int found = 0;
+  
+  if (!DECL_CLINIT_P (mdecl))
+    return 0;
+
+  /* If the body isn't empty, then we keep <clinit>. Note that if
+     we're emitting classfiles, this isn't enough not to rule it
+     out. */
+  fbody = DECL_FUNCTION_BODY (mdecl);
+  bbody = BLOCK_EXPR_BODY (fbody);
+  if (bbody && bbody != error_mark_node)
+    bbody = BLOCK_EXPR_BODY (bbody);
+  else
+    return 0;
+  if (bbody && ! flag_emit_class_files && bbody != empty_stmt_node)
+    return 0;
+  
+  type = DECL_CONTEXT (mdecl);
+  current = TYPE_FIELDS (type);
+
+  for (current = (current ? TREE_CHAIN (current) : current); 
+       current; current = TREE_CHAIN (current))
+    {
+      tree f_init;
+
+      /* We're not interested in non static field */
+      if (!FIELD_STATIC (current))
+       continue;
+
+      /* Anything that isn't String or a basic type is ruled out -- or
+        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))
+         && ! JNUMERIC_TYPE_P (TREE_TYPE (current)))
+       break;
+         
+      f_init = DECL_INITIAL (current);
+      /* If we're emitting native code, we want static final fields to
+        have constant initializers. If we don't meet these
+        conditions, we keep <clinit> */
+      if (!flag_emit_class_files
+         && !(FIELD_FINAL (current) && f_init && TREE_CONSTANT (f_init)))
+       break;
+      /* If we're emitting bytecode, we want static fields to have
+        constant initializers or no initializer. If we don't meet
+        these conditions, we keep <clinit> */
+      if (flag_emit_class_files && f_init && !TREE_CONSTANT (f_init))
+       break;
+    }
+
+  /* Now we analyze the method body and look for something that
+     isn't a MODIFY_EXPR */
+  if (bbody == empty_stmt_node)
+    found = 0;
+  else
+    found = analyze_clinit_body (bbody);
+
+  if (current || found)
+    return 0;
+
+  /* Get rid of <clinit> in the class' list of methods */
+  if (TYPE_METHODS (type) == mdecl)
+    TYPE_METHODS (type) = TREE_CHAIN (mdecl);
+  else
+    for (current = TYPE_METHODS (type); current; 
+        current = TREE_CHAIN (current))
+      if (TREE_CHAIN (current) == mdecl)
+       {
+         TREE_CHAIN (current) = TREE_CHAIN (mdecl);
+         break;
+       }
+
+  return 1;
+}
+
+
+/* Complete and expand a method.  */
+
+static void
+java_complete_expand_method (mdecl)
+     tree mdecl;
+{
+  int yank_clinit = 0;
+
+  current_function_decl = mdecl;
+  /* Fix constructors before expanding them */
+  if (DECL_CONSTRUCTOR_P (mdecl))
+    fix_constructors (mdecl);
+  
+  /* Expand functions that have a body */
   if (DECL_FUNCTION_BODY (mdecl))
     {
       tree fbody = DECL_FUNCTION_BODY (mdecl);
@@ -7390,10 +7846,11 @@ java_complete_expand_method (mdecl)
        {
          block_body = java_complete_tree (block_body);
 
-         if (!flag_emit_xref)
+         if (! flag_emit_xref && ! METHOD_NATIVE (mdecl))
            check_for_initialization (block_body);
          ctxp->explicit_constructor_p = 0;
        }
+
       BLOCK_EXPR_BODY (fbody) = block_body;
 
       /* If we saw a return but couldn't evaluate it properly, we'll
@@ -7404,15 +7861,19 @@ java_complete_expand_method (mdecl)
          && !flag_emit_xref)
        missing_return_error (current_function_decl);
 
-      complete_start_java_method (mdecl); 
-
+      /* Check wether we could just get rid of clinit, now the picture
+         is complete. */
+      if (!(yank_clinit = maybe_yank_clinit (mdecl)))
+       complete_start_java_method (mdecl); 
+      
       /* Don't go any further if we've found error(s) during the
-         expansion */
-      if (!java_error_count)
+        expansion */
+      if (!java_error_count && !yank_clinit)
        source_end_java_method ();
       else
        {
-         pushdecl_force_head (DECL_ARGUMENTS (mdecl));
+         if (java_error_count)
+           pushdecl_force_head (DECL_ARGUMENTS (mdecl));
          poplevel (1, 0, 1);
        }
 
@@ -7444,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>'. Not 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);
@@ -7462,16 +7925,16 @@ build_outer_field_access (id, decl)
       int lc = EXPR_WFL_LINECOL (id);
 
       /* Now we chain the required number of calls to the access$0 to
-        get a hold to the enclosing instance we need, and the we
+        get a hold to the enclosing instance we need, and then we
         build the field access. */
-      access = build_access_to_thisn (ctx, 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>'.
@@ -7494,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;
@@ -7638,16 +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);
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
-
+  MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
   /* Create the identifier and a function named after it. */
   id = build_new_access_id ();
 
@@ -7665,19 +8135,22 @@ 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;
-  pop_obstacks ();
 
   /* Return the access name */
   return FIELD_INNER_ACCESS (decl) = id;
@@ -7734,8 +8207,6 @@ build_outer_method_access_method (decl)
   id = build_new_access_id ();
   OUTER_FIELD_ACCESS_IDENTIFIER_P (id) = 1;
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
-
   carg = TYPE_ARG_TYPES (TREE_TYPE (decl));
   /* Create the arguments, as much as the original */
   for (; carg && carg != end_params_node; 
@@ -7782,7 +8253,6 @@ build_outer_method_access_method (decl)
   java_method_add_stmt (mdecl,body);
   end_artificial_method_body (mdecl);
   current_function_decl = saved_current_function_decl;
-  pop_obstacks ();
 
   /* Back tag the access function so it know what it accesses */
   DECL_FUNCTION_ACCESS_DECL (decl) = mdecl;
@@ -7797,9 +8267,11 @@ build_outer_method_access_method (decl)
    kept in a generated field called this$<n>, with <n> being the
    inner class nesting level (starting from 0.)  */
     
-/* Build an access to a given this$<n>, possibly by chaining access
-   call to others. Access methods to this$<n> are build on the fly if
-   necessary */
+/* Build an access to a given this$<n>, always chaining access call to
+   others. Access methods to this$<n> are build on the fly if
+   necessary. This CAN'T be used to solely access this$<n-1> from
+   this$<n> (which alway yield to special cases and optimization, see
+   for example build_outer_field_access).  */
 
 static tree
 build_access_to_thisn (from, to, lc)
@@ -7810,30 +8282,37 @@ build_access_to_thisn (from, to, lc)
 
   while (from != to)
     {
-      tree access0_wfl, cn;
-
-      maybe_build_thisn_access_method (from);
-      access0_wfl = build_wfl_node (access0_identifier_node);
-      cn = build_wfl_node (DECL_NAME (TYPE_NAME (from)));
-      EXPR_WFL_LINECOL (access0_wfl) = lc;
-      
       if (!access)
+        {
+          access = build_current_thisn (from);
+          access = build_wfl_node (access);
+        }
+      else
        {
-         access = build_current_thisn (current_class);
-         access = build_wfl_node (access);
+         tree access0_wfl, cn;
+
+         maybe_build_thisn_access_method (from);
+         access0_wfl = build_wfl_node (access0_identifier_node);
+         cn = build_wfl_node (DECL_NAME (TYPE_NAME (from)));
+         EXPR_WFL_LINECOL (access0_wfl) = lc;
+         access = build_tree_list (NULL_TREE, access);
+         access = build_method_invocation (access0_wfl, access);
+         access = make_qualified_primary (cn, access, lc);
        }
-      access = build_tree_list (NULL_TREE, access);
-      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;
 }
 
 /* Build an access function to the this$<n> local to TYPE. NULL_TREE
    is returned if nothing needs to be generated. Otherwise, the method
-   generated, fully walked and a method decl is returned.  
+   generated and a method decl is returned.  
 
    NOTE: These generated methods should be declared in a class file
    attribute so that they can't be referred to directly.  */
@@ -7847,13 +8326,12 @@ 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:
      static <outer_of_type> access$0 (<type> inst$) { return inst$.this$<n>; }
   */
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   args = build_tree_list (inst_id, build_pointer_type (type));
   TREE_CHAIN (args) = end_params_node;
   rtype = build_pointer_type (TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))));
@@ -7871,7 +8349,6 @@ maybe_build_thisn_access_method (type)
   java_method_add_stmt (mdecl, stmt);
   end_artificial_method_body (mdecl);
   current_function_decl = saved_current_function_decl;
-  pop_obstacks ();
 
   CLASS_ACCESS0_GENERATED_P (type) = 1;
 
@@ -7889,16 +8366,23 @@ build_current_thisn (type)
 {
   static int saved_i = -1;
   static tree saved_thisn = NULL_TREE;
-
+  static tree saved_type = NULL_TREE;
+  static int saved_type_i = 0;
+  static int initialized_p;
   tree decl;
   char buffer [80];
   int i = 0;
 
-  if (type)
+  /* Register SAVED_THISN and SAVED_TYPE with the garbage collector.  */
+  if (!initialized_p)
     {
-      static tree saved_type = NULL_TREE;
-      static int saved_type_i = 0;
+      ggc_add_tree_root (&saved_thisn, 1);
+      ggc_add_tree_root (&saved_type, 1);
+      initialized_p = 1;
+    }
 
+  if (type)
+    {
       if (type == saved_type)
        i = saved_type_i;
       else
@@ -7970,6 +8454,8 @@ build_dot_class_method (class)
     {
       get_message_wfl = build_wfl_node (get_identifier ("getMessage"));
       type_parm_wfl = build_wfl_node (get_identifier ("type$"));
+      ggc_add_tree_root (&get_message_wfl, 1);
+      ggc_add_tree_root (&type_parm_wfl, 1);
     }
 
   /* Build the arguments */
@@ -8054,14 +8540,18 @@ build_dot_class_method (class)
 }
 
 static tree
-build_dot_class_method_invocation (name)
-     tree name;
+build_dot_class_method_invocation (type)
+     tree type;
 {
-  tree s = make_node (STRING_CST);
-  TREE_STRING_LENGTH (s) = IDENTIFIER_LENGTH (name);
-  TREE_STRING_POINTER (s) = obstack_alloc (expression_obstack,
-                                          TREE_STRING_LENGTH (s)+1);
-  strcpy (TREE_STRING_POINTER (s), IDENTIFIER_POINTER (name));
+  tree sig_id, s;
+
+  if (TYPE_ARRAY_P (type))
+    sig_id = build_java_signature (type);
+  else
+    sig_id = DECL_NAME (TYPE_NAME (type));
+
+  s = build_string (IDENTIFIER_LENGTH (sig_id), 
+                   IDENTIFIER_POINTER (sig_id));
   return build_method_invocation (build_wfl_node (get_identifier ("class$")),
                                  build_tree_list (NULL_TREE, s));
 }
@@ -8103,6 +8593,11 @@ fix_constructors (mdecl)
         CLASSNAME() constructor */
       start_artificial_method_body (mdecl);
       
+      /* Insert an assignment to the this$<n> hidden field, if
+         necessary */
+      if ((thisn_assign = build_thisn_assign ()))
+       java_method_add_stmt (mdecl, thisn_assign);
+
       /* We don't generate a super constructor invocation if we're
         compiling java.lang.Object. build_super_invocation takes care
         of that. */
@@ -8112,11 +8607,6 @@ fix_constructors (mdecl)
          super invocation. */
       add_instance_initializer (mdecl);
 
-      /* Insert an assignment to the this$<n> hidden field, if
-         necessary */
-      if ((thisn_assign = build_thisn_assign ()))
-       java_method_add_stmt (mdecl, thisn_assign);
-
       end_artificial_method_body (mdecl);
     }
   /* Search for an explicit constructor invocation */
@@ -8148,14 +8638,14 @@ fix_constructors (mdecl)
        compound = add_stmt_to_compound (compound, NULL_TREE,
                                          build_super_invocation (mdecl));
       
-      /* Insert the instance initializer block right here, after the
-         super invocation. */
-      add_instance_initializer (mdecl);
-
       /* Generate the assignment to this$<n>, if necessary */
       if ((thisn_assign = build_thisn_assign ()))
         compound = add_stmt_to_compound (compound, NULL_TREE, thisn_assign);
 
+      /* Insert the instance initializer block right here, after the
+         super invocation. */
+      add_instance_initializer (mdecl);
+
       /* Fix the constructor main block if we're adding extra stmts */
       if (compound)
        {
@@ -8176,6 +8666,7 @@ verify_constructor_super (mdecl)
      tree mdecl;
 {
   tree class = CLASSTYPE_SUPER (current_class);
+  int super_inner = PURE_INNER_CLASS_TYPE_P (class);
   tree sdecl;
 
   if (!class)
@@ -8188,17 +8679,19 @@ verify_constructor_super (mdecl)
       for (sdecl = TYPE_METHODS (class); sdecl; sdecl = TREE_CHAIN (sdecl))
        if (DECL_CONSTRUCTOR_P (sdecl))
          {
-           tree arg_type;
-           for (arg_type = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (sdecl)));
-                arg_type != end_params_node && 
-                  mdecl_arg_type != end_params_node;
+           tree m_arg_type;
+           tree arg_type = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (sdecl)));
+           if (super_inner)
+             arg_type = TREE_CHAIN (arg_type);
+           for (m_arg_type = mdecl_arg_type; 
+                (arg_type != end_params_node 
+                 && m_arg_type != end_params_node);
                 arg_type = TREE_CHAIN (arg_type), 
-                mdecl_arg_type = TREE_CHAIN (mdecl_arg_type))
-             if (TREE_VALUE (arg_type) != TREE_VALUE (mdecl_arg_type))
+                  m_arg_type = TREE_CHAIN (m_arg_type))
+             if (TREE_VALUE (arg_type) != TREE_VALUE (m_arg_type))
                break;
 
-           if (arg_type == end_params_node && 
-               mdecl_arg_type == end_params_node)
+           if (arg_type == end_params_node && m_arg_type == end_params_node)
              return 0;
          }
     }
@@ -8206,9 +8699,10 @@ verify_constructor_super (mdecl)
     {
       for (sdecl = TYPE_METHODS (class); sdecl; sdecl = TREE_CHAIN (sdecl))
        {
-         if (DECL_CONSTRUCTOR_P (sdecl)
-             && TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (sdecl))) 
-                == end_params_node)
+         tree arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (sdecl)));
+         if (super_inner)
+           arg = TREE_CHAIN (arg);
+         if (DECL_CONSTRUCTOR_P (sdecl) && arg == end_params_node)
            return 0;
        }
     }
@@ -8307,7 +8801,7 @@ make_qualified_primary (primary, right, location)
   tree wfl;
 
   if (TREE_CODE (primary) != EXPR_WITH_FILE_LOCATION)
-    wfl = build_wfl_wrap (primary);
+    wfl = build_wfl_wrap (primary, location);
   else
     {
       wfl = primary;
@@ -8428,25 +8922,17 @@ resolve_expression_name (id, orig)
       else 
         {
          decl = lookup_field_wrapper (current_class, name);
-
-         /* Last chance: if we're within the context of an inner
-            class, we might be trying to access a local variable
-            defined in an outer context. We try to look for it
-            now. */
-         if (!decl && INNER_CLASS_TYPE_P (current_class))
-           {
-             char *alias_buffer;
-             MANGLE_OUTER_LOCAL_VARIABLE_NAME (alias_buffer, name);
-             name = get_identifier (alias_buffer);
-             decl = lookup_field_wrapper (current_class, name);
-             if (decl)
-               FIELD_LOCAL_ALIAS_USED (decl) = 1;
-           }
-
          if (decl)
            {
              tree access = NULL_TREE;
              int fs = FIELD_STATIC (decl);
+
+             /* If we're accessing an outer scope local alias, make
+                sure we change the name of the field we're going to
+                build access to. */
+             if (FIELD_LOCAL_ALIAS_USED (decl))
+               name = DECL_NAME (decl);
+
              /* Instance variable (8.3.1.1) can't appear within
                 static method, static initializer or initializer for
                 a static variable. */
@@ -8468,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),
@@ -8532,12 +9025,25 @@ resolve_field_access (qual_wfl, field_decl, field_type)
     return error_mark_node;
 
   /* Resolve the LENGTH field of an array here */
-  if (DECL_NAME (decl) == length_identifier_node && TYPE_ARRAY_P (type_found)
+  if (DECL_P (decl) && DECL_NAME (decl) == length_identifier_node 
+      && type_found && TYPE_ARRAY_P (type_found) 
       && ! flag_emit_class_files && ! flag_emit_xref)
     {
       tree length = build_java_array_length_access (where_found);
       field_ref =
        build_java_arraynull_check (type_found, length, int_type_node);
+
+      /* In case we're dealing with a static array, we need to
+        initialize its class before the array length can be fetched.
+        It's also a good time to create a DECL_RTL for the field if
+        none already exists, otherwise if the field was declared in a
+        class found in an external file and hasn't been (and won't
+        be) accessed for its value, none will be created. */
+      if (TREE_CODE (where_found) == VAR_DECL && FIELD_STATIC (where_found))
+       {
+         build_static_field_ref (where_found);
+         field_ref = build_class_init (DECL_CONTEXT (where_found), field_ref);
+       }
     }
   /* We might have been trying to resolve field.method(). In which
      case, the resolution is over and decl is the answer */
@@ -8549,12 +9055,14 @@ 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) 
+      if (CLASS_FINAL_VARIABLE_P (decl)
          && JPRIMITIVE_TYPE_P (TREE_TYPE (decl))
-         && DECL_LANG_SPECIFIC (decl)
          && DECL_INITIAL (decl))
        {
-         field_ref = DECL_INITIAL (decl);
+         /* When called on a FIELD_DECL of the right (primitive)
+            type, java_complete_tree will try to substitue the decl
+            for it's initial value. */
+         field_ref = java_complete_tree (decl);
          static_final_found = 1;
        }
       else
@@ -8565,7 +9073,7 @@ resolve_field_access (qual_wfl, field_decl, field_type)
        return error_mark_node;
       if (is_static && !static_final_found 
          && !flag_emit_class_files && !flag_emit_xref)
-       field_ref = build_class_init (type_found, field_ref);
+       field_ref = build_class_init (DECL_CONTEXT (decl), field_ref);
     }
   else
     field_ref = decl;
@@ -8654,10 +9162,21 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
             saved and restored shortly after */
          saved_current = current_class;
          saved_this = current_this;
-         if (decl && TREE_CODE (qual_wfl) == NEW_CLASS_EXPR)
+         if (decl 
+             && (TREE_CODE (qual_wfl) == NEW_CLASS_EXPR
+                 || from_qualified_this))
            {
+             /* If we still have `from_qualified_this', we have the form
+                <T>.this.f() and we need to build <T>.this */
+             if (from_qualified_this)
+               {
+                 decl = build_access_to_thisn (current_class, type, 0);
+                 decl = java_complete_tree (decl);
+                 type = TREE_TYPE (TREE_TYPE (decl));
+               }
              current_class = type;
              current_this = decl;
+             from_qualified_this = 0;
            }
 
          if (from_super && TREE_CODE (qual_wfl) == CALL_EXPR)
@@ -8691,8 +9210,10 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
             instantiation using a primary qualified by a `new' */
          RESTORE_THIS_AND_CURRENT_CLASS;
 
-         /* EH check */
-         if (location)
+         /* EH check. No check on access$<n> functions */
+         if (location 
+             && !OUTER_FIELD_ACCESS_IDENTIFIER_P 
+                   (DECL_NAME (current_function_decl)))
            check_thrown_exceptions (location, ret_decl);
 
          /* If the previous call was static and this one is too,
@@ -8799,11 +9320,30 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
              *where_found = decl = current_this;
              *type_found = type = QUAL_DECL_TYPE (decl);
            }
-         /* We're trying to access the this from somewhere else... */
+         /* We're trying to access the this from somewhere else. Make sure
+            it's allowed before doing so. */
          else
            {
-             *where_found = decl = build_current_thisn (type);
+             if (!enclosing_context_p (type, current_class))
+               {
+                 char *p  = xstrdup (lang_printable_name (type, 0));
+                 parse_error_context (qual_wfl, "Can't use variable `%s.this': type `%s' isn't an outer type of type `%s'", 
+                                      p, p, 
+                                      lang_printable_name (current_class, 0));
+                 free (p);
+                 return 1;
+               }
              from_qualified_this = 1;
+             /* If there's nothing else after that, we need to
+                 produce something now, otherwise, the section of the
+                 code that needs to produce <T>.this will generate
+                 what is necessary. */
+             if (!TREE_CHAIN (q))
+               {
+                 decl = build_access_to_thisn (current_class, type, 0);
+                 *where_found = decl = java_complete_tree (decl);
+                 *type_found = type = TREE_TYPE (decl);
+               }
            }
 
          from_type = 0;
@@ -8843,7 +9383,7 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
            {
              tree list;
              *where_found = decl = resolve_no_layout (name, qual_wfl);
-             /* We wan't to be absolutely that the class is laid
+             /* We want to be absolutely sure that the class is laid
                  out. We're going to search something inside it. */
              *type_found = type = TREE_TYPE (decl);
              layout_class (type);
@@ -8934,6 +9474,8 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
                                          current_class);
                          return 1;
                        }
+                      if (outer_field_access_p (current_class, decl))
+                        decl = build_outer_field_access (qual_wfl, decl);
                    }
                  else
                    {
@@ -8967,6 +9509,24 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
              
              field_decl = lookup_field_wrapper (type,
                                                 EXPR_WFL_NODE (qual_wfl));
+
+             /* Maybe what we're trying to access an inner class. */
+             if (!field_decl)
+               {
+                 tree ptr, inner_decl;
+
+                 BUILD_PTR_FROM_NAME (ptr, EXPR_WFL_NODE (qual_wfl));
+                 inner_decl = resolve_class (decl, ptr, NULL_TREE, qual_wfl);
+                 if (inner_decl)
+                   {
+                     check_inner_class_access (inner_decl, decl, qual_wfl); 
+                     type = TREE_TYPE (inner_decl);
+                     decl = inner_decl;
+                     from_type = 1;
+                     continue;
+                   }
+               }
+
              if (field_decl == NULL_TREE)
                {
                  parse_error_context 
@@ -9081,7 +9641,8 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
 }
 
 /* 6.6 Qualified name and access control. Returns 1 if MEMBER (a decl)
-   can't be accessed from REFERENCE (a record type). */
+   can't be accessed from REFERENCE (a record type). This should be
+   used when decl is a field or a method.*/
 
 static int
 not_accessible_p (reference, member, from_super)
@@ -9090,6 +9651,10 @@ not_accessible_p (reference, member, from_super)
 {
   int access_flag = get_access_flags_from_decl (member);
 
+  /* Inner classes are processed by check_inner_class_access */
+  if (INNER_CLASS_TYPE_P (reference))
+    return 0;
+
   /* Access always granted for members declared public */
   if (access_flag & ACC_PUBLIC)
     return 0;
@@ -9108,16 +9673,25 @@ not_accessible_p (reference, member, from_super)
        return 0;
 
       /* Otherwise, access is granted if occuring from the class where
-        member is declared or a subclass of it */
-      if (inherits_from_p (reference, current_class))
+        member is declared or a subclass of it. Find the right
+        context to perform the check */
+      if (PURE_INNER_CLASS_TYPE_P (reference))
+        {
+          while (INNER_CLASS_TYPE_P (reference))
+            {
+              if (inherits_from_p (reference, DECL_CONTEXT (member)))
+                return 0;
+              reference = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (reference)));
+            }
+        }
+      if (inherits_from_p (reference, DECL_CONTEXT (member)))
        return 0;
       return 1;
     }
 
   /* Check access on private members. Access is granted only if it
-     occurs from within the class in witch it is declared. Exceptions
-     are access from inner-classes. This section is probably not
-     complete. FIXME */
+     occurs from within the class in which it is declared. Exceptions
+     are accesses from inner-classes. */
   if (access_flag & ACC_PRIVATE)
     return (current_class == DECL_CONTEXT (member) ? 0 : 
            (INNER_CLASS_TYPE_P (current_class) ? 0 : 1));
@@ -9127,7 +9701,7 @@ not_accessible_p (reference, member, from_super)
      REFERENCE is defined in the current package */
   if (ctxp->package)
     return !class_in_current_package (reference);
-  
+
   /* Otherwise, access is granted */
   return 0;
 }
@@ -9197,6 +9771,14 @@ class_in_current_package (class)
   breakdown_qualified (&left, NULL, DECL_NAME (TYPE_NAME (class)));
   if (ctxp->package == left)
     {
+      static int initialized_p;
+      /* Register CACHE with the garbage collector.  */
+      if (!initialized_p)
+       {
+         ggc_add_tree_root (&cache, 1);
+         initialized_p = 1;
+       }
+
       cache = class;
       return 1;
     }
@@ -9269,6 +9851,16 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl)
 
       type = GET_SKIP_TYPE (resolved);
       resolve_and_layout (type, NULL_TREE);
+      
+      if (JPRIMITIVE_TYPE_P (type))
+        {
+         parse_error_context
+           (identifier_wfl,
+            "Can't invoke a method on primitive type `%s'",
+            IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
+         PATCH_METHOD_RETURN_ERROR ();         
+       }
+
       list = lookup_method_invoke (0, identifier_wfl, type, identifier, args);
       args = nreverse (args);
 
@@ -9430,11 +10022,14 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl)
             access$0(access$0(...(this$0))). 
             
             maybe_use_access_method returns a non zero value if the
-            this_arg has to be deplaced into the (then generated)
-            stub argument list. In the mean time, the selected
-            function might have be replaced by a generated stub. */
+            this_arg has to be moved into the (then generated) stub
+            argument list. In the meantime, the selected function
+            might have be replaced by a generated stub. */
          if (maybe_use_access_method (is_super_init, &list, &this_arg))
-           args = tree_cons (NULL_TREE, this_arg, args);
+           {
+             args = tree_cons (NULL_TREE, this_arg, args);
+             this_arg = NULL_TREE; /* So it doesn't get chained twice */
+           }
        }
     }
 
@@ -9469,19 +10064,65 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl)
       args = build_alias_initializer_parameter_list
        (AIPL_FUNCTION_CTOR_INVOCATION, DECL_CONTEXT (list), args, NULL);
 
-      /* We have to reverse things. Find out why. FIXME */
-      if (ANONYMOUS_CLASS_P (DECL_CONTEXT (list)))
-       args = nreverse (args);
-      
-      /* Secretely pass the current_this/primary as a second argument */
+      /* 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);
     }
 
+  /* This handles the situation where a constructor invocation needs
+     to have an enclosing context passed as a second parameter (the
+     constructor is one of an inner class. We extract it from the
+     current function.  */
+  if (is_super_init && PURE_INNER_CLASS_TYPE_P (DECL_CONTEXT (list)))
+    {
+      tree enclosing_decl = DECL_CONTEXT (TYPE_NAME (current_class));
+      tree extra_arg;
+
+      if (ANONYMOUS_CLASS_P (current_class) || !DECL_CONTEXT (enclosing_decl))
+       {
+         extra_arg = DECL_FUNCTION_BODY (current_function_decl);
+         extra_arg = TREE_CHAIN (BLOCK_EXPR_DECLS (extra_arg));
+       }
+      else
+       {
+         tree dest = TREE_TYPE (DECL_CONTEXT (enclosing_decl));
+         extra_arg = 
+           build_access_to_thisn (TREE_TYPE (enclosing_decl), dest, 0);
+         extra_arg = java_complete_tree (extra_arg);
+       }
+      args = tree_cons (NULL_TREE, extra_arg, args);
+    }
+
   is_static_flag = METHOD_STATIC (list);
-  if (! METHOD_STATIC (list) && this_arg != NULL_TREE)
+  if (! is_static_flag && this_arg != NULL_TREE)
     args = tree_cons (NULL_TREE, this_arg, args);
 
   /* In the context of an explicit constructor invocation, we can't
@@ -9508,7 +10149,7 @@ patch_method_invocation (patch, primary, where, is_static, ret_decl)
     {
       tree finit_parms, finit_call;
       
-      /* Prepare to pass hidden parameters to $finit$, if any. */
+      /* Prepare to pass hidden parameters to finit$, if any. */
       finit_parms = build_alias_initializer_parameter_list 
        (AIPL_FUNCTION_FINIT_INVOCATION, current_class, NULL_TREE, NULL);
 
@@ -9570,12 +10211,13 @@ maybe_use_access_method (is_super_init, mdecl, this_arg)
   
   /* If we're calling a method found in an enclosing class, generate
      what it takes to retrieve the right this. Don't do that if we're
-     invoking a static method. */
+     invoking a static method. Note that if MD's type is unrelated to
+     CURRENT_CLASS, then the current this can be used. */
 
-  if (non_static_context)
+  if (non_static_context && DECL_CONTEXT (md) != object_type_node)
     {
       ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
-      if (ctx == DECL_CONTEXT (md))
+      if (inherits_from_p (ctx, DECL_CONTEXT (md)))
        {
          ta = build_current_thisn (current_class);
          ta = build_wfl_node (ta);
@@ -9586,7 +10228,7 @@ maybe_use_access_method (is_super_init, mdecl, this_arg)
          while (type)
            {
              maybe_build_thisn_access_method (type);
-             if (type == DECL_CONTEXT (md))
+             if (inherits_from_p (type, DECL_CONTEXT (md)))
                {
                  ta = build_access_to_thisn (ctx, type, 0);
                  break;
@@ -9626,10 +10268,11 @@ patch_invoke (patch, method, args)
 {
   tree dtable, func;
   tree original_call, t, ta;
+  tree cond = NULL_TREE;
 
   /* Last step for args: convert build-in types. If we're dealing with
      a new TYPE() type call, the first argument to the constructor
-     isn't found in the incomming argument list, but delivered by
+     isn't found in the incoming argument list, but delivered by
      `new' */
   t = TYPE_ARG_TYPES (TREE_TYPE (method));
   if (TREE_CODE (patch) == NEW_CLASS_EXPR)
@@ -9657,6 +10300,22 @@ patch_invoke (patch, method, args)
          func = build_invokevirtual (dtable, method);
          break;
 
+       case INVOKE_NONVIRTUAL:
+         /* If the object for the method call is null, we throw an
+            exception.  We don't do this if the object is the current
+            method's `this'.  In other cases we just rely on an
+            optimization pass to eliminate redundant checks.  */
+         if (TREE_VALUE (args) != current_this)
+           {
+             /* We use a SAVE_EXPR here to make sure we only evaluate
+                the new `self' expression once.  */
+             tree save_arg = save_expr (TREE_VALUE (args));
+             TREE_VALUE (args) = save_arg;
+             cond = build (EQ_EXPR, boolean_type_node, save_arg,
+                           null_pointer_node);
+           }
+         /* Fall through.  */
+
        case INVOKE_SUPER:
        case INVOKE_STATIC:
          func = build_known_method_ref (method, TREE_TYPE (method),
@@ -9682,7 +10341,7 @@ patch_invoke (patch, method, args)
   TREE_OPERAND (patch, 1) = args;
   original_call = patch;
 
-  /* We're processing a `new TYPE ()' form. New is called an its
+  /* We're processing a `new TYPE ()' form. New is called and its
      returned value is the first argument to the constructor. We build
      a COMPOUND_EXPR and use saved expression so that the overall NEW
      expression value is a pointer to a newly created and initialized
@@ -9712,6 +10371,26 @@ patch_invoke (patch, method, args)
       TREE_SET_CODE (original_call, CALL_EXPR);
       patch = build (COMPOUND_EXPR, TREE_TYPE (new), patch, saved_new);
     }
+
+  /* If COND is set, then we are building a check to see if the object
+     is NULL.  */
+  if (cond != NULL_TREE)
+    {
+      /* We have to make the `then' branch a compound expression to
+        make the types turn out right.  This seems bizarre.  */
+      patch = build (COND_EXPR, TREE_TYPE (patch), cond,
+                    build (COMPOUND_EXPR, TREE_TYPE (patch),
+                           build (CALL_EXPR, void_type_node,
+                                  build_address_of (soft_nullpointer_node),
+                                  NULL_TREE, NULL_TREE),
+                           (FLOAT_TYPE_P (TREE_TYPE (patch))
+                            ? build_real (TREE_TYPE (patch), dconst0)
+                            : build1 (CONVERT_EXPR, TREE_TYPE (patch),
+                                      integer_zero_node))),
+                    patch);
+      TREE_SIDE_EFFECTS (patch) = 1;
+    }
+
   return patch;
 }
 
@@ -9725,17 +10404,22 @@ invocation_mode (method, super)
   if (super)
     return INVOKE_SUPER;
 
-  if (access & ACC_STATIC || access & ACC_FINAL || access & ACC_PRIVATE)
+  if (access & ACC_STATIC)
     return INVOKE_STATIC;
 
-  if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method))))
+  /* We have to look for a constructor before we handle nonvirtual
+     calls; otherwise the constructor will look nonvirtual.  */
+  if (DECL_CONSTRUCTOR_P (method))
     return INVOKE_STATIC;
-  
+
+  if (access & ACC_FINAL || access & ACC_PRIVATE)
+    return INVOKE_NONVIRTUAL;
+
+  if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method))))
+    return INVOKE_NONVIRTUAL;
+
   if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
     return INVOKE_INTERFACE;
-  
-  if (DECL_CONSTRUCTOR_P (method))
-    return INVOKE_STATIC;
 
   return INVOKE_VIRTUAL;
 }
@@ -9827,9 +10511,29 @@ find_applicable_accessible_methods_list (lc, class, name, arglist)
      int lc;
      tree class, name, arglist;
 {
-  static int object_done = 0;
+  static struct hash_table t, *searched_classes = NULL;
+  static int search_not_done = 0;
   tree list = NULL_TREE, all_list = NULL_TREE;
 
+  /* Check the hash table to determine if this class has been searched 
+     already. */
+  if (searched_classes)
+    {
+      if (hash_lookup (searched_classes, 
+                      (const hash_table_key) class, FALSE, NULL))
+       return NULL;
+    }
+  else
+    {
+      hash_table_init (&t, hash_newfunc, java_hash_hash_tree_node,
+                      java_hash_compare_tree_node);
+      searched_classes = &t;
+    }
+    
+  search_not_done++;
+  hash_lookup (searched_classes, 
+              (const hash_table_key) class, TRUE, NULL);
+
   if (!CLASS_LOADED_P (class) && !CLASS_FROM_SOURCE_P (class))
     {
       load_class (class, 1);
@@ -9837,32 +10541,11 @@ find_applicable_accessible_methods_list (lc, class, name, arglist)
     }
 
   /* Search interfaces */
-  if (CLASS_INTERFACE (TYPE_NAME (class)))
+  if (TREE_CODE (TYPE_NAME (class)) == TYPE_DECL 
+      && CLASS_INTERFACE (TYPE_NAME (class)))
     {
-      static struct hash_table t, *searched_interfaces = NULL;
-      static int search_not_done = 0;
       int i, n;
       tree basetype_vec = TYPE_BINFO_BASETYPES (class);
-
-      /* Search in the hash table, otherwise create a new one if
-         necessary and insert the new entry. */
-
-      if (searched_interfaces)
-       {
-         if (hash_lookup (searched_interfaces, 
-                          (const hash_table_key) class, FALSE, NULL))
-           return NULL;
-       }
-      else
-       {
-         hash_table_init (&t, hash_newfunc, java_hash_hash_tree_node,
-                          java_hash_compare_tree_node);
-         searched_interfaces = &t;
-       }
-
-      hash_lookup (searched_interfaces, 
-                  (const hash_table_key) class, TRUE, NULL);
-
       search_applicable_methods_list (lc, TYPE_METHODS (class), 
                                      name, arglist, &list, &all_list);
       n = TREE_VEC_LENGTH (basetype_vec);
@@ -9871,23 +10554,9 @@ find_applicable_accessible_methods_list (lc, class, name, arglist)
          tree t = BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i));
          tree rlist;
 
-         search_not_done++;
          rlist = find_applicable_accessible_methods_list (lc,  t, name, 
                                                           arglist);
          list = chainon (rlist, list);
-         search_not_done--;
-       }
-
-      /* We're done. Reset the searched interfaces list and finally search
-         java.lang.Object */
-      if (!search_not_done)
-       {  
-         if (!object_done)
-           search_applicable_methods_list (lc, 
-                                           TYPE_METHODS (object_type_node),
-                                           name, arglist, &list, &all_list);
-         hash_table_free (searched_interfaces);
-         searched_interfaces = NULL;  
        }
     }
   /* Search classes */
@@ -9903,17 +10572,17 @@ find_applicable_accessible_methods_list (lc, class, name, arglist)
       {
        tree basetype_vec = TYPE_BINFO_BASETYPES (sc);
        int n = TREE_VEC_LENGTH (basetype_vec), i;
-       object_done = 1;
        for (i = 1; i < n; i++)
          {
            tree t = BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i));
-           tree rlist;
            if (t != object_type_node)
-             rlist = find_applicable_accessible_methods_list (lc, t,
-                                                              name, arglist);
-           list = chainon (rlist, list);
+             {
+               tree rlist
+                 = find_applicable_accessible_methods_list (lc, t,
+                                                            name, arglist);
+               list = chainon (rlist, list);
+             }
          }
-       object_done = 0;
       }
 
       /* Search enclosing context of inner classes before looking
@@ -9934,10 +10603,35 @@ find_applicable_accessible_methods_list (lc, class, name, arglist)
       else
        class = sc;
 
-      for (class = (lc ? NULL_TREE : CLASSTYPE_SUPER (class)); 
-        class; class = CLASSTYPE_SUPER (class))
-       search_applicable_methods_list (lc, TYPE_METHODS (class), 
-                                       name, arglist, &list, &all_list);
+      /* Search superclass */
+      if (!lc && CLASSTYPE_SUPER (class) != NULL_TREE)
+       {
+          tree rlist;
+          class = CLASSTYPE_SUPER (class);
+          rlist = find_applicable_accessible_methods_list (lc, class, 
+                                                           name, arglist);
+          list = chainon (rlist, list);
+        }
+    }
+
+  search_not_done--;
+
+  /* We're done. Reset the searched classes list and finally search
+     java.lang.Object if it wasn't searched already. */
+  if (!search_not_done)
+    {
+      if (!lc
+         && TYPE_METHODS (object_type_node)
+         && !hash_lookup (searched_classes, 
+                           (const hash_table_key) object_type_node, 
+                           FALSE, NULL))
+       {
+          search_applicable_methods_list (lc, 
+                                          TYPE_METHODS (object_type_node),
+                                          name, arglist, &list, &all_list);
+        }
+      hash_table_free (searched_classes);
+      searched_classes = NULL;
     }
 
   /* Either return the list obtained or all selected (but
@@ -9945,7 +10639,7 @@ find_applicable_accessible_methods_list (lc, class, name, arglist)
   return (!list ? all_list : list);
 }
 
-/* Effectively search for the approriate method in method */
+/* Effectively search for the appropriate method in method */
 
 static void 
 search_applicable_methods_list (lc, method, name, arglist, list, all_list)
@@ -9962,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 */
@@ -9974,7 +10668,7 @@ search_applicable_methods_list (lc, method, name, arglist, list, all_list)
            *all_list = tree_cons (NULL_TREE, method, *list);
        }
     }
-}    
+}
 
 /* 15.11.2.2 Choose the Most Specific Method */
 
@@ -9983,6 +10677,7 @@ find_most_specific_methods_list (list)
      tree list;
 {
   int max = 0;
+  int abstract, candidates;
   tree current, new_list = NULL_TREE;
   for (current = list; current; current = TREE_CHAIN (current))
     {
@@ -9991,42 +10686,59 @@ find_most_specific_methods_list (list)
 
       for (method = list; method; method = TREE_CHAIN (method))
        {
+         tree method_v, current_v;
          /* Don't test a method against itself */
          if (method == current)
            continue;
 
-         /* Compare arguments and location where method where declared */
-         if (argument_types_convertible (TREE_VALUE (method), 
-                                         TREE_VALUE (current))
-             && valid_method_invocation_conversion_p 
-                  (DECL_CONTEXT (TREE_VALUE (method)), 
-                   DECL_CONTEXT (TREE_VALUE (current))))
+         method_v = TREE_VALUE (method);
+         current_v = TREE_VALUE (current);
+
+         /* Compare arguments and location where methods where declared */
+         if (argument_types_convertible (method_v, current_v))
            {
-             int v = ++DECL_SPECIFIC_COUNT (TREE_VALUE (current));
-             max = (v > max ? v : max);
+             if (valid_method_invocation_conversion_p 
+                 (DECL_CONTEXT (method_v), DECL_CONTEXT (current_v))
+                 || (INNER_CLASS_TYPE_P (DECL_CONTEXT (current_v))
+                     && enclosing_context_p (DECL_CONTEXT (method_v),
+                                             DECL_CONTEXT (current_v))))
+               {
+                 int v = (DECL_SPECIFIC_COUNT (current_v) += 
+                   (INNER_CLASS_TYPE_P (DECL_CONTEXT (current_v)) ? 2 : 1));
+                 max = (v > max ? v : max);
+               }
            }
        }
     }
 
   /* Review the list and select the maximally specific methods */
-  for (current = list; current; current = TREE_CHAIN (current))
+  for (current = list, abstract = -1, candidates = -1;
+       current; current = TREE_CHAIN (current))
     if (DECL_SPECIFIC_COUNT (TREE_VALUE (current)) == max)
-      new_list = tree_cons (NULL_TREE, TREE_VALUE (current), new_list);
+      {
+       new_list = tree_cons (NULL_TREE, TREE_VALUE (current), new_list);
+       abstract += (METHOD_ABSTRACT (TREE_VALUE (current)) ? 1 : 0);
+       candidates++;
+      }
 
   /* If we have several and they're all abstract, just pick the
      closest one. */
+  if (candidates > 0 && (candidates == abstract))
+    {
+      new_list = nreverse (new_list);
+      TREE_CHAIN (new_list) = NULL_TREE;
+    }
 
-  if (new_list && TREE_CHAIN (new_list))
+  /* We have several (we couldn't find a most specific), all but one
+     are abstract, we pick the only non abstract one. */
+  if (candidates > 0 && (candidates == abstract+1))
     {
-      tree c;
-      for (c = new_list; c && METHOD_ABSTRACT (TREE_VALUE (c)); 
-          c = TREE_CHAIN (c))
-        ;
-      if (!c)
-       {
-         new_list = nreverse (new_list);
-         TREE_CHAIN (new_list) = NULL_TREE;
-       }
+      for (current = new_list; current; current = TREE_CHAIN (current))
+       if (!METHOD_ABSTRACT (TREE_VALUE (current)))
+         {
+           TREE_CHAIN (current) = NULL_TREE;
+           new_list = current;
+         }
     }
 
   /* If we can't find one, lower expectations and try to gather multiple
@@ -10054,9 +10766,19 @@ argument_types_convertible (m1, m2_or_arglist)
 {
   static tree m2_arg_value = NULL_TREE;
   static tree m2_arg_cache = NULL_TREE;
+  static int initialized_p;
 
   register tree m1_arg, m2_arg;
 
+  /* Register M2_ARG_VALUE and M2_ARG_CACHE with the garbage
+     collector.  */
+  if (!initialized_p)
+    {
+      ggc_add_tree_root (&m2_arg_value, 1);
+      ggc_add_tree_root (&m2_arg_cache, 1);
+      initialized_p = 1;
+    }
+
   SKIP_THIS_AND_ARTIFICIAL_PARMS (m1_arg, m1)
 
   if (m2_arg_value == m2_or_arglist)
@@ -10132,8 +10854,9 @@ qualify_ambiguous_name (id)
        qual = TREE_CHAIN (qual);
        again = new_array_found = 1;
        continue;
-      case NEW_CLASS_EXPR:
       case CONVERT_EXPR:
+       break;
+      case NEW_CLASS_EXPR:
        qual_wfl = TREE_OPERAND (qual_wfl, 0);
        break;
       case ARRAY_REF:
@@ -10192,6 +10915,17 @@ qualify_ambiguous_name (id)
     /* If we have a THIS (from a primary), we set the context accordingly */
     if (name == this_identifier_node)
       {
+       /* This isn't really elegant. One more added irregularity
+          before I start using COMPONENT_REF (hopefully very soon.)  */
+       if (TREE_CODE (TREE_PURPOSE (qual)) == ARRAY_REF
+           && TREE_CODE (TREE_OPERAND (TREE_PURPOSE (qual), 0)) ==
+              EXPR_WITH_FILE_LOCATION
+           && EXPR_WFL_NODE (TREE_OPERAND (TREE_PURPOSE (qual), 0)) == 
+              this_identifier_node)
+           {
+             qual = TREE_OPERAND (TREE_PURPOSE (qual), 0);
+             qual = EXPR_WFL_QUALIFICATION (qual);
+           }
        qual = TREE_CHAIN (qual);
        qual_wfl = QUAL_WFL (qual);
        if (TREE_CODE (qual_wfl) == CALL_EXPR)
@@ -10218,10 +10952,10 @@ qualify_ambiguous_name (id)
       }
   } while (again);
   
-  /* If name appears within the scope of a location variable
-     declaration or parameter declaration, then it is an expression
-     name. We don't carry this test out if we're in the context of the
-     use of SUPER or THIS */
+  /* If name appears within the scope of a local variable declaration
+     or parameter declaration, then it is an expression name. We don't
+     carry this test out if we're in the context of the use of SUPER
+     or THIS */
   if (!this_found && !super_found 
       && TREE_CODE (name) != STRING_CST && TREE_CODE (name) != INTEGER_CST
       && (decl = IDENTIFIER_LOCAL_VALUE (name)))
@@ -10257,7 +10991,7 @@ qualify_ambiguous_name (id)
       QUAL_RESOLUTION (qual) = decl;
     }
 
-  /* Method call are expression name */
+  /* Method call, array references and cast are expression name */
   else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR
           || TREE_CODE (QUAL_WFL (qual)) == ARRAY_REF
           || TREE_CODE (QUAL_WFL (qual)) == CONVERT_EXPR)
@@ -10299,12 +11033,14 @@ static int
 breakdown_qualified (left, right, source)
     tree *left, *right, source;
 {
-  char *p = IDENTIFIER_POINTER (source), *base;
+  char *p, *base;
   int   l = IDENTIFIER_LENGTH (source);
 
+  base = alloca (l + 1);
+  memcpy (base, IDENTIFIER_POINTER (source), l + 1);
+
   /* Breakdown NAME into REMAINDER . IDENTIFIER */
-  base = p;
-  p += (l-1);
+  p = base + l - 1;
   while (*p != '.' && p != base)
     p--;
 
@@ -10315,8 +11051,7 @@ breakdown_qualified (left, right, source)
   *p = '\0';
   if (right)
     *right = get_identifier (p+1);
-  *left = get_identifier (IDENTIFIER_POINTER (source));
-  *p = '.';
+  *left = get_identifier (base);
   
   return 0;
 }
@@ -10330,15 +11065,13 @@ java_complete_tree (node)
      tree node;
 {
   node = java_complete_lhs (node);
-  if (TREE_CODE (node) == VAR_DECL && FIELD_STATIC (node)
-      && FIELD_FINAL (node) && DECL_INITIAL (node) != NULL_TREE
+  if (JDECL_P (node) && CLASS_FINAL_VARIABLE_P (node)
+      && DECL_INITIAL (node) != NULL_TREE
       && !flag_emit_xref)
     {
       tree value = DECL_INITIAL (node);
       DECL_INITIAL (node) = NULL_TREE;
-      push_obstacks (&permanent_obstack, &permanent_obstack);
       value = fold_constant_for_init (value, node);
-      pop_obstacks ();
       DECL_INITIAL (node) = value;
       if (value != NULL_TREE)
        {
@@ -10351,6 +11084,8 @@ java_complete_tree (node)
          else
            return value;
        }
+      else
+        DECL_FIELD_FINAL_IUD (node) = 0;
     }
   return node;
 }
@@ -10551,10 +11286,8 @@ java_complete_lhs (node)
          && FIELD_FINAL (TREE_OPERAND (cn, 1))
          && DECL_INITIAL (TREE_OPERAND (cn, 1)))
        {
-         push_obstacks (&permanent_obstack, &permanent_obstack);
          cn = fold_constant_for_init (DECL_INITIAL (TREE_OPERAND (cn, 1)),
                                       TREE_OPERAND (cn, 1));
-         pop_obstacks ();
        }
 
       if (!TREE_CONSTANT (cn) && !flag_emit_xref)
@@ -10583,6 +11316,8 @@ java_complete_lhs (node)
       /* Multiple instance of a case label bearing the same
         value is checked during code generation. The case
         expression is allright so far. */
+      if (TREE_CODE (cn) == VAR_DECL)
+       cn = DECL_INITIAL (cn);
       TREE_OPERAND (node, 0) = cn;
       TREE_TYPE (node) = void_type_node;
       CAN_COMPLETE_NORMALLY (node) = 1;
@@ -10621,7 +11356,7 @@ java_complete_lhs (node)
       else
        node = patch_switch_statement (node);
 
-      if (TREE_OPERAND (node, 0) == error_mark_node)
+      if (node == error_mark_node || TREE_OPERAND (node, 0) == error_mark_node)
        nn = error_mark_node;
       else
        {
@@ -10830,9 +11565,7 @@ java_complete_lhs (node)
        {
          tree value;
          
-         push_obstacks (&permanent_obstack, &permanent_obstack);
          value = fold_constant_for_init (nn, nn);
-         pop_obstacks ();
 
          if (value != NULL_TREE)
            {
@@ -10841,7 +11574,10 @@ java_complete_lhs (node)
                  (type == string_ptr_type_node && ! flag_emit_class_files))
                return empty_stmt_node;
            }
-         DECL_INITIAL (nn) = NULL_TREE;
+         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);
 
@@ -10872,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 */
        }
 
@@ -10953,8 +11697,7 @@ java_complete_lhs (node)
           nn = java_complete_tree (wfl_op1);
           if (nn == error_mark_node)
             return error_mark_node;
-          if ((cn = patch_string (nn)))
-            nn = cn;
+
           TREE_OPERAND (node, 0) = nn;
         }
       if (TREE_CODE (node) != PLUS_EXPR || !JSTRING_P (wfl_op2))
@@ -10962,8 +11705,7 @@ java_complete_lhs (node)
           nn = java_complete_tree (wfl_op2);
           if (nn == error_mark_node)
             return error_mark_node;
-          if ((cn = patch_string (nn)))
-            nn = cn;
+
           TREE_OPERAND (node, 1) = nn;
         }
       return force_evaluation_order (patch_binop (node, wfl_op1, wfl_op2));
@@ -11266,8 +12008,9 @@ maybe_absorb_scoping_blocks ()
 
 /* Wrap a non WFL node around a WFL.  */
 static tree
-build_wfl_wrap (node)
+build_wfl_wrap (node, location)
     tree node;
+    int location;
 {
   tree wfl, node_to_insert = node;
   
@@ -11279,7 +12022,7 @@ build_wfl_wrap (node)
   else
     wfl = build_expr_wfl (NULL_TREE, ctxp->filename, 0, 0);
 
-  EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (node);
+  EXPR_WFL_LINECOL (wfl) = location;
   EXPR_WFL_QUALIFICATION (wfl) = build_tree_list (node_to_insert, NULL_TREE);
   return wfl;
 }
@@ -11400,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.  */
 
@@ -11407,21 +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);
 
-  if (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
@@ -11439,7 +12421,8 @@ maybe_build_primttype_type_ref (rhs, wfl)
       tree n = TREE_OPERAND (rhs, 1);
       if (TREE_CODE (n) == VAR_DECL 
          && DECL_NAME (n) == TYPE_identifier_node
-         && rhs_type == class_ptr_type)
+         && rhs_type == class_ptr_type
+         && TREE_CODE (EXPR_WFL_NODE (wfl)) == IDENTIFIER_NODE)
        {
          const char *self_name = IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl));
          if (!strncmp (self_name, "java.lang.", 10))
@@ -11625,6 +12608,19 @@ 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_P (lvalue)
+      && TREE_CONSTANT (new_rhs)
+      && IDENTIFIER_LOCAL_VALUE (DECL_NAME (lvalue))
+      && JINTEGRAL_TYPE_P (TREE_TYPE (lvalue))
+      )
+    {
+      TREE_CONSTANT (lvalue) = 1;
+      DECL_INITIAL (lvalue) = new_rhs;
+    }
+
   TREE_OPERAND (node, 0) = lvalue;
   TREE_OPERAND (node, 1) = new_rhs;
   TREE_TYPE (node) = lhs_type;
@@ -11670,8 +12666,17 @@ try_builtin_assignconv (wfl_op1, lhs_type, rhs)
   tree new_rhs = NULL_TREE;
   tree rhs_type = TREE_TYPE (rhs);
 
+  /* Handle boolean specially.  */
+  if (TREE_CODE (rhs_type) == BOOLEAN_TYPE
+      || TREE_CODE (lhs_type) == BOOLEAN_TYPE)
+    {
+      if (TREE_CODE (rhs_type) == BOOLEAN_TYPE
+         && TREE_CODE (lhs_type) == BOOLEAN_TYPE)
+       new_rhs = rhs;
+    }
+
   /* Zero accepted everywhere */
-  if (TREE_CODE (rhs) == INTEGER_CST 
+  else if (TREE_CODE (rhs) == INTEGER_CST 
       && TREE_INT_CST_HIGH (rhs) == 0 && TREE_INT_CST_LOW (rhs) == 0
       && JPRIMITIVE_TYPE_P (rhs_type))
     new_rhs = convert (lhs_type, rhs);
@@ -11694,7 +12699,7 @@ try_builtin_assignconv (wfl_op1, lhs_type, rhs)
         new_rhs = convert (lhs_type, rhs);
       else if (wfl_op1)                /* Might be called with a NULL */
        parse_warning_context 
-         (wfl_op1, "Constant expression `%s' to wide for narrowing primitive conversion to `%s'", 
+         (wfl_op1, "Constant expression `%s' too wide for narrowing primitive conversion to `%s'", 
           print_int_node (rhs), lang_printable_name (lhs_type, 0));
       /* Reported a warning that will turn into an error further
         down, so we don't return */
@@ -11704,7 +12709,7 @@ try_builtin_assignconv (wfl_op1, lhs_type, rhs)
 }
 
 /* Return 1 if RHS_TYPE can be converted to LHS_TYPE by identity
-   conversion (5.1.1) or widening primitve conversion (5.1.2).  Return
+   conversion (5.1.1) or widening primitive conversion (5.1.2).  Return
    0 is the conversion test fails.  This implements parts the method
    invocation convertion (5.3).  */
 
@@ -11716,8 +12721,8 @@ valid_builtin_assignconv_identity_widening_p (lhs_type, rhs_type)
   if (lhs_type == rhs_type)
     return 1;
 
-  /* Reject non primitive types */
-  if (!JPRIMITIVE_TYPE_P (lhs_type) || !JPRIMITIVE_TYPE_P (rhs_type))
+  /* Reject non primitive types and boolean conversions.  */
+  if (!JNUMERIC_TYPE_P (lhs_type) || !JNUMERIC_TYPE_P (rhs_type))
     return 0;
 
   /* 5.1.2: widening primitive conversion. byte, even if it's smaller
@@ -11775,7 +12780,6 @@ valid_ref_assignconv_cast_p (source, dest, cast)
       if (TYPE_CLASS_P (dest))
        return  (source == dest 
                 || inherits_from_p (source, dest)
-                || enclosing_context_p (dest, source /*source, dest*/)
                 || (cast && inherits_from_p (dest, source)));
       if (TYPE_INTERFACE_P (dest))
        {
@@ -11835,18 +12839,24 @@ valid_ref_assignconv_cast_p (source, dest, cast)
          else
            return source == dest || interface_of_p (dest, source);
        }
-      else                     /* Array */
-       return (cast ? 
-               (DECL_NAME (TYPE_NAME (source)) == java_lang_cloneable) : 0);
+      else
+       {
+         /* Array */
+         return (cast
+                 && (DECL_NAME (TYPE_NAME (source)) == java_lang_cloneable
+                     || (DECL_NAME (TYPE_NAME (source))
+                         == java_io_serializable)));
+       }
     }
   if (TYPE_ARRAY_P (source))
     {
       if (TYPE_CLASS_P (dest))
        return dest == object_type_node;
       /* Can't cast an array to an interface unless the interface is
-        java.lang.Cloneable */
+        java.lang.Cloneable or java.io.Serializable.  */
       if (TYPE_INTERFACE_P (dest))
-       return (DECL_NAME (TYPE_NAME (dest)) == java_lang_cloneable ? 1 : 0);
+       return (DECL_NAME (TYPE_NAME (dest)) == java_lang_cloneable
+               || DECL_NAME (TYPE_NAME (dest)) == java_io_serializable);
       else                     /* Arrays */
        {
          tree source_element_type = TYPE_ARRAY_ELEMENT (source);
@@ -11881,20 +12891,20 @@ valid_cast_to_p (source, dest)
   else if (JNUMERIC_TYPE_P (source) && JNUMERIC_TYPE_P (dest))
     return 1;
 
+  else if (TREE_CODE (source) == BOOLEAN_TYPE
+          && TREE_CODE (dest) == BOOLEAN_TYPE)
+    return 1;
+
   return 0;
 }
 
-/* Method invocation conversion test. Return 1 if type SOURCE can be
-   converted to type DEST through the methond invocation conversion
-   process (5.3) */
-
 static tree
 do_unary_numeric_promotion (arg)
      tree arg;
 {
   tree type = TREE_TYPE (arg);
-  if (TREE_CODE (type) == INTEGER_TYPE ? TYPE_PRECISION (type) < 32
-      : TREE_CODE (type) == CHAR_TYPE)
+  if ((TREE_CODE (type) == INTEGER_TYPE && TYPE_PRECISION (type) < 32)
+      || TREE_CODE (type) == CHAR_TYPE)
     arg = convert (int_type_node, arg);
   return arg;
 }
@@ -12073,7 +13083,7 @@ patch_binop (node, wfl_op1, wfl_op2)
   tree op2 = TREE_OPERAND (node, 1);
   tree op1_type = TREE_TYPE (op1);
   tree op2_type = TREE_TYPE (op2);
-  tree prom_type = NULL_TREE;
+  tree prom_type = NULL_TREE, cn;
   int code = TREE_CODE (node);
 
   /* If 1, tell the routine that we have to return error_mark_node
@@ -12089,11 +13099,11 @@ patch_binop (node, wfl_op1, wfl_op2)
     case RDIV_EXPR:            /* 15.16.2 Division Operator / */
     case TRUNC_DIV_EXPR:       /* 15.16.2 Integral type Division Operator / */
     case TRUNC_MOD_EXPR:       /* 15.16.3 Remainder operator % */
-      if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type))
+      if (!JNUMERIC_TYPE_P (op1_type) || !JNUMERIC_TYPE_P (op2_type))
        {
-         if (!JPRIMITIVE_TYPE_P (op1_type))
+         if (!JNUMERIC_TYPE_P (op1_type))
            ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type);
-         if (!JPRIMITIVE_TYPE_P (op2_type) && (op1_type != op2_type))
+         if (!JNUMERIC_TYPE_P (op2_type) && (op1_type != op2_type))
            ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type);
          TREE_TYPE (node) = error_mark_node;
          error_found = 1;
@@ -12141,11 +13151,11 @@ patch_binop (node, wfl_op1, wfl_op2)
 
     case MINUS_EXPR:           /* 15.17.2 Additive Operators (+ and -) for
                                   Numeric Types */
-      if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type))
+      if (!JNUMERIC_TYPE_P (op1_type) || !JNUMERIC_TYPE_P (op2_type))
        {
-         if (!JPRIMITIVE_TYPE_P (op1_type))
+         if (!JNUMERIC_TYPE_P (op1_type))
            ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type);
-         if (!JPRIMITIVE_TYPE_P (op2_type) && (op1_type != op2_type))
+         if (!JNUMERIC_TYPE_P (op2_type) && (op1_type != op2_type))
            ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type);
          TREE_TYPE (node) = error_mark_node;
          error_found = 1;
@@ -12164,7 +13174,7 @@ patch_binop (node, wfl_op1, wfl_op2)
            ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op1_type);
          else
            {
-             if (JPRIMITIVE_TYPE_P (op2_type))
+             if (JNUMERIC_TYPE_P (op2_type))
                parse_error_context (wfl_operator,
                                     "Incompatible type for `%s'. Explicit cast needed to convert shift distance from `%s' to integral",
                                     operator_string (node),
@@ -12251,18 +13261,7 @@ patch_binop (node, wfl_op1, wfl_op2)
            }
          /* Otherwise we have to invoke instance of to figure it out */
          else
-           {
-             tree call =
-               build (CALL_EXPR, boolean_type_node,
-                      build_address_of (soft_instanceof_node),
-                      tree_cons 
-                      (NULL_TREE, op1,
-                       build_tree_list (NULL_TREE,
-                                        build_class_ref (op2_type))),
-                      NULL_TREE);
-             TREE_SIDE_EFFECTS (call) = TREE_SIDE_EFFECTS (op1);
-             return call;
-           }
+           return build_instanceof (op1, op2_type);
        }
       /* There is no way the expression operand can be an instance of
         the type operand. This is a compile time error. */
@@ -12351,6 +13350,18 @@ patch_binop (node, wfl_op1, wfl_op2)
       /* 15.20 Equality Operator */
     case EQ_EXPR:
     case NE_EXPR:
+      /* It's time for us to patch the strings. */
+      if ((cn = patch_string (op1))) 
+       {
+         op1 = cn;
+         op1_type = TREE_TYPE (op1);
+       }
+      if ((cn = patch_string (op2))) 
+       {
+         op2 = cn;
+         op2_type = TREE_TYPE (op2);
+       }
+      
       /* 15.20.1 Numerical Equality Operators == and != */
       /* Binary numeric promotion is performed on the operands */
       if (JNUMERIC_TYPE_P (op1_type) && JNUMERIC_TYPE_P (op2_type))
@@ -12422,21 +13433,23 @@ do_merge_string_cste (cste, string, string_len, after)
      const char *string;
      int string_len, after;
 {
-  int len = TREE_STRING_LENGTH (cste) + string_len;
   const char *old = TREE_STRING_POINTER (cste);
-  TREE_STRING_LENGTH (cste) = len;
-  TREE_STRING_POINTER (cste) = obstack_alloc (expression_obstack, len+1);
+  int old_len = TREE_STRING_LENGTH (cste);
+  int len = old_len + string_len;
+  char *new = alloca (len+1);
+
   if (after)
     {
-      strcpy (TREE_STRING_POINTER (cste), string);
-      strcat (TREE_STRING_POINTER (cste), old);
+      memcpy (new, string, string_len);
+      memcpy (&new [string_len], old, old_len);
     }
   else
     {
-      strcpy (TREE_STRING_POINTER (cste), old);
-      strcat (TREE_STRING_POINTER (cste), string);
+      memcpy (new, old, old_len);
+      memcpy (&new [old_len], string, string_len);
     }
-  return cste;
+  new [len] = '\0';
+  return build_string (len, new);
 }
 
 /* Tries to merge OP1 (a STRING_CST) and OP2 (if suitable). Return a
@@ -12628,11 +13641,9 @@ patch_string_cst (node)
   int location;
   if (! flag_emit_class_files)
     {
-      push_obstacks (&permanent_obstack, &permanent_obstack);
       node = get_identifier (TREE_STRING_POINTER (node));
       location = alloc_name_constant (CONSTANT_String, node);
       node = build_ref_from_constant_pool (location);
-      pop_obstacks ();
     }
   TREE_TYPE (node) = string_ptr_type_node;
   TREE_CONSTANT (node) = 1;
@@ -12728,15 +13739,17 @@ patch_incomplete_class_ref (node)
     return error_mark_node;
 
   if (!flag_emit_class_files || JPRIMITIVE_TYPE_P (ref_type))
-    return build_class_ref (ref_type);
+    {
+      /* A class referenced by `foo.class' is initialized.  */
+      return build_class_init (ref_type, build_class_ref (ref_type));
+    }
 
   /* If we're emitting class files and we have to deal with non
      primitive types, we invoke (and consider generating) the
      synthetic static method `class$'. */
   if (!TYPE_DOT_CLASS (current_class))
       build_dot_class_method (current_class);
-  ref_type = 
-    build_dot_class_method_invocation (DECL_NAME (TYPE_NAME (ref_type)));
+  ref_type = build_dot_class_method_invocation (ref_type);
   return java_complete_tree (ref_type);
 }
 
@@ -12951,7 +13964,7 @@ resolve_type_during_patch (type)
 {
   if (unresolved_type_p (type, NULL))
     {
-      tree type_decl = resolve_no_layout (EXPR_WFL_NODE (type), NULL_TREE);
+      tree type_decl = resolve_no_layout (EXPR_WFL_NODE (type), type);
       if (!type_decl)
        {
          parse_error_context (type, 
@@ -12971,9 +13984,9 @@ resolve_type_during_patch (type)
    found. Otherwise NODE or something meant to replace it is returned.  */
 
 static tree
-patch_cast (node, wfl_operator)
+patch_cast (node, wfl_op)
      tree node;
-     tree wfl_operator;
+     tree wfl_op;
 {
   tree op = TREE_OPERAND (node, 0);
   tree op_type = TREE_TYPE (op);
@@ -13042,7 +14055,7 @@ patch_cast (node, wfl_operator)
 
   /* Any other casts are proven incorrect at compile time */
   t1 = xstrdup (lang_printable_name (op_type, 0));
-  parse_error_context (wfl_operator, "Invalid cast from `%s' to `%s'",
+  parse_error_context (wfl_op, "Invalid cast from `%s' to `%s'",
                       t1, lang_printable_name (cast_type, 0));
   free (t1);
   return error_mark_node;
@@ -13174,7 +14187,7 @@ patch_newarray (node)
       tree dim = TREE_VALUE (cdim);
 
       /* Dim might have been saved during its evaluation */
-      dim = (TREE_CODE (dim) == SAVE_EXPR ? dim = TREE_OPERAND (dim, 0) : dim);
+      dim = (TREE_CODE (dim) == SAVE_EXPR ? TREE_OPERAND (dim, 0) : dim);
 
       /* The type of each specified dimension must be an integral type. */
       if (!JINTEGRAL_TYPE_P (TREE_TYPE (dim)))
@@ -13330,7 +14343,8 @@ patch_new_array_init (type, node)
          TREE_PURPOSE (current) = NULL_TREE;
          all_constant = 0;
        }
-      if (elt && TREE_VALUE (elt) == error_mark_node)
+      if (elt && TREE_CODE (elt) == TREE_LIST 
+         && TREE_VALUE (elt) == error_mark_node)
        error_seen = 1;
     }
 
@@ -13363,7 +14377,6 @@ array_constructor_check_entry (type, entry)
   new_value = NULL_TREE;
   wfl_value = TREE_VALUE (entry);
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   value = java_complete_tree (TREE_VALUE (entry));
   /* patch_string return error_mark_node if arg is error_mark_node */
   if ((patched = patch_string (value)))
@@ -13380,7 +14393,6 @@ array_constructor_check_entry (type, entry)
   if (!new_value && (new_value = try_reference_assignconv (type, value)))
     type_value = promote_type (type);
 
-  pop_obstacks ();
   /* Check and report errors */
   if (!new_value)
     {
@@ -13396,7 +14408,7 @@ array_constructor_check_entry (type, entry)
   
   if (new_value)
     {
-      new_value = maybe_build_primttype_type_ref (new_value, wfl_operator);
+      new_value = maybe_build_primttype_type_ref (new_value, wfl_value);
       TREE_VALUE (entry) = new_value;
     }
 
@@ -13954,7 +14966,7 @@ patch_switch_statement (node)
   se_type = TREE_TYPE (se);
   /* The type of the switch expression must be char, byte, short or
      int */
-  if (!JINTEGRAL_TYPE_P (se_type))
+  if (! JINTEGRAL_TYPE_P (se_type) || se_type == long_type_node)
     {
       EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
       parse_error_context (wfl_operator,
@@ -14122,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)
     {
@@ -14130,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)))
     {
@@ -14492,14 +15508,9 @@ fold_constant_for_init (node, context)
   tree op0, op1, val;
   enum tree_code code = TREE_CODE (node);
 
-  if (code == STRING_CST)
+  if (code == STRING_CST || code == INTEGER_CST || code == REAL_CST)
     return node;
 
-  if (code == INTEGER_CST || code == REAL_CST)
-    return convert (TREE_TYPE (context), node);
-  if (TREE_TYPE (node) != NULL_TREE && code != VAR_DECL && code != FIELD_DECL)
-    return NULL_TREE;
-
   switch (code)
     {
     case PLUS_EXPR:
@@ -14572,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:
@@ -14640,3 +15653,39 @@ resolve_qualified_name (name, context)
 {
 }
 #endif
+
+/* Mark P, which is really a `struct parser_ctxt **' for GC.  */
+
+static void
+mark_parser_ctxt (p)
+     void *p;
+{
+  struct parser_ctxt *pc = *((struct parser_ctxt **) p);
+  int i;
+
+  if (!pc)
+    return;
+
+#ifndef JC1_LITE
+  for (i = 0; i < 11; ++i)
+    ggc_mark_tree (pc->modifier_ctx[i]);
+  ggc_mark_tree (pc->class_type);
+  ggc_mark_tree (pc->function_decl);
+  ggc_mark_tree (pc->package);
+  ggc_mark_tree (pc->incomplete_class);
+  ggc_mark_tree (pc->gclass_list);
+  ggc_mark_tree (pc->class_list);
+  ggc_mark_tree (pc->current_parsed_class);
+  ggc_mark_tree (pc->current_parsed_class_un);
+  ggc_mark_tree (pc->non_static_initialized);
+  ggc_mark_tree (pc->static_initialized);
+  ggc_mark_tree (pc->instance_initializers);
+  ggc_mark_tree (pc->import_list);
+  ggc_mark_tree (pc->import_demand_list);
+  ggc_mark_tree (pc->current_loop);
+  ggc_mark_tree (pc->current_labeled_block);
+#endif /* JC1_LITE */
+
+  if (pc->next)
+    mark_parser_ctxt (&pc->next);
+}