Merge from Cygnus internal source tree.
authorPer Bothner <bothner@gcc.gnu.org>
Mon, 12 Oct 1998 12:43:51 +0000 (05:43 -0700)
committerPer Bothner <bothner@gcc.gnu.org>
Mon, 12 Oct 1998 12:43:51 +0000 (05:43 -0700)
From-SVN: r23023

gcc/java/parse.y

index 50a467962fc2fb25eb30e59e095917a3b9202a5e..9dd9e587ed2d6e01099c042d70c087aa4c46ef06 100644 (file)
@@ -98,7 +98,16 @@ static enum tree_code binop_lookup[19] =
 static tree wfl_operator = NULL_TREE;
 
 /* The "$L" identifier we use to create labels.  */
-static tree label_id;
+static tree label_id = NULL_TREE;
+
+/* The "StringBuffer" identifier used for the String `+' operator. */
+static tree wfl_string_buffer = NULL_TREE; 
+
+/* The "append" identifier used for String `+' operator.  */
+static tree wfl_append = NULL_TREE;
+
+/* The "toString" identifier used for String `+' operator. */
+static tree wfl_to_string = NULL_TREE;
 %}
 
 %union {
@@ -219,6 +228,12 @@ static tree label_id;
                        conditional_expression assignment_expression
                        left_hand_side assignment for_header for_begin
                        constant_expression do_statement_begin empty_statement
+                       switch_statement synchronized_statement throw_statement
+                       try_statement switch_expression switch_block
+                       switch_block_statement_groups switch_labels
+                       switch_block_statement_group switch_label
+                       group_of_labels catches catch_clause 
+                       catch_clause_parameter finally
 %type    <node>         return_statement break_statement continue_statement
 
 %type    <operator>     ASSIGN_TK      MULT_ASSIGN_TK  DIV_ASSIGN_TK  
@@ -231,7 +246,7 @@ static tree label_id;
 %token   <operator>     DECR_TK MINUS_TK MULT_TK DIV_TK XOR_TK REM_TK NEQ_TK
 %token   <operator>     NEG_TK REL_QM_TK REL_CL_TK NOT_TK LT_TK
 %token   <operator>     OP_TK OSB_TK DOT_TK
-%type    <operator>    THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK
+%type    <operator>    THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK CASE_TK%type    <operator>     DEFAULT_TK TRY_TK CATCH_TK
 
 %type   <node>         method_body 
        
@@ -539,13 +554,16 @@ class_body_declaration:
 |      static_initializer
 |      constructor_declaration
 |      block                   /* Added, JDK1.1, instance initializer */
+               { $$ = parse_jdk1_1_error ("instance initializer"); }
 ;
 
 class_member_declaration:
        field_declaration
 |      method_declaration
 |      class_declaration       /* Added, JDK1.1 inner classes */
+               { $$ = parse_jdk1_1_error ("inner classe declaration"); }
 |      interface_declaration   /* Added, JDK1.1 inner classes */
+               { $$ = parse_jdk1_1_error ("inner interface declaration"); }
 ;
 
 /* 19.8.2 Productions from 8.3: Field Declarations  */
@@ -701,10 +719,7 @@ formal_parameter:
                  $$ = build_tree_list ($2, $1);
                }
 |      modifiers type variable_declarator_id /* Added, JDK1.1 final locals */
-               {
-                 SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1));
-                 $$ = NULL;    /* FIXME */
-               }
+               { $$ = parse_jdk1_1_error ("final local"); }
 |      type error
                {yyerror ("Missing identifier"); RECOVER;}
 |      modifiers type error
@@ -802,20 +817,23 @@ explicit_constructor_invocation:
         /* Added, JDK1.1 inner classes. Modified because the rule
           'primary' couldn't work.  */
 |      name DOT_TK SUPER_TK OP_TK argument_list CP_TK SC_TK
+               {$$ = parse_jdk1_1_error ("explicit constructor invocation"); }
 |      name DOT_TK SUPER_TK OP_TK CP_TK SC_TK
-               {RULE ("explicit_constructor_invocation (X.super)");}
+               {$$ = parse_jdk1_1_error ("explicit constructor invocation"); }
 ;
 
 this_or_super:                 /* Added, simplifies error diagnostics */
        THIS_TK
                {
-                 tree wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0);
+                 tree wfl = build_wfl_node (this_identifier_node, 
+                                            input_filename, 0, 0);
                  EXPR_WFL_LINECOL (wfl) = $1.location;
                  $$ = wfl;
                }
 |      SUPER_TK
                {
-                 tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0);
+                 tree wfl = build_wfl_node (super_identifier_node,
+                                            input_filename, 0, 0);
                  EXPR_WFL_LINECOL (wfl) = $1.location;
                  $$ = wfl;
                }
@@ -887,7 +905,9 @@ interface_member_declaration:
        constant_declaration
 |      abstract_method_declaration
 |      class_declaration       /* Added, JDK1.1 inner classes */
+               { $$ = parse_jdk1_1_error ("inner class declaration"); }
 |      interface_declaration   /* Added, JDK1.1 inner classes */
+               { $$ = parse_jdk1_1_error ("inner interface declaration"); }
 ;
 
 constant_declaration:
@@ -955,6 +975,7 @@ block_statement:
 |      statement
                { $$ = java_method_add_stmt (current_function_decl, $1); }
 |      class_declaration       /* Added, JDK1.1 inner classes */
+               { $$ = parse_jdk1_1_error ("inner class declaration"); }
 ;
 
 local_variable_declaration_statement:
@@ -971,13 +992,9 @@ local_variable_declaration:
 statement:
        statement_without_trailing_substatement
 |      labeled_statement
-               { RULE ("STATEMENT (labeled)"); }
 |      if_then_statement
-               { RULE ("STATEMENT (if-then)"); }
 |      if_then_else_statement
-               { RULE ("STATEMENT (if-then-else)"); }
 |      while_statement
-               { RULE ("STATEMENT (while)"); }
 |      for_statement
                { 
                  /* If the for loop is unlabeled, we must return the
@@ -991,37 +1008,23 @@ statement:
 statement_nsi:
        statement_without_trailing_substatement
 |      labeled_statement_nsi
-               { RULE ("NSI STATEMENT (labeled)"); }
 |      if_then_else_statement_nsi
-               { RULE ("NSI STATEMENT (if-then-else)"); }
 |      while_statement_nsi
-               { RULE ("NSI STATEMENT (while)"); }
 |      for_statement_nsi
-               { RULE ("NSI STATEMENT (for)"); }
 ;
 
 statement_without_trailing_substatement:
        block
-               { RULE ("STATEMENT (block)"); }
 |      empty_statement
-               { RULE ("STATEMENT (empty)"); }
 |      expression_statement
-               { RULE ("STATEMENT (expression)"); }
 |      switch_statement
-               { RULE ("STATEMENT (switch)"); }
 |      do_statement
-               { RULE ("STATEMENT (do)"); }
 |      break_statement
-               { RULE ("STATEMENT (break)"); }
 |      continue_statement
-               { RULE ("STATEMENT (continue)"); }
 |      return_statement
 |      synchronized_statement
-               { RULE ("STATEMENT (synchronized)"); }
 |      throw_statement
-               { RULE ("STATEMENT (throw)"); }
 |      try_statement
-               { RULE ("STATEMENT (try)"); }
 ;
 
 empty_statement:
@@ -1113,26 +1116,11 @@ expression_statement:
 statement_expression: 
        assignment
 |      pre_increment_expression
-               {
-                 RULE ("++INCREMENT");
-               }
 |      pre_decrement_expression
-               {
-                 RULE ("--DECREMENT");
-               }
 |      post_increment_expression
-               {
-                 RULE ("INCREMENT++");
-               }
 |      post_decrement_expression
-               {
-                 RULE ("DECREMENT--");
-               }
 |      method_invocation
 |      class_instance_creation_expression
-               {
-                 RULE ("INSTANCE CREATION");
-               }
 ;
 
 if_then_statement:
@@ -1157,7 +1145,19 @@ if_then_else_statement_nsi:
 ;
 
 switch_statement:
-       SWITCH_TK OP_TK expression CP_TK switch_block
+       switch_expression switch_block
+               { 
+                 TREE_OPERAND ($1, 1) = $2;
+                 $$ = build_debugable_stmt (EXPR_WFL_LINECOL ($1), $1);
+               }
+;
+
+switch_expression:
+       SWITCH_TK OP_TK expression CP_TK
+               { 
+                 $$ = build (SWITCH_EXPR, NULL_TREE, $3, NULL_TREE);
+                 EXPR_WFL_LINECOL ($$) = $2.location;
+               }
 |      SWITCH_TK error
                {yyerror ("'(' expected"); RECOVER;}
 |      SWITCH_TK OP_TK error
@@ -1168,29 +1168,63 @@ switch_statement:
 
 switch_block:
        OCB_TK CCB_TK
+               { $$ = NULL_TREE; }
 |      OCB_TK switch_labels CCB_TK
+               { $$ = build_tree_list ($2, NULL_TREE); }
 |      OCB_TK switch_block_statement_groups CCB_TK
+               { $$ = $2; }
 |      OCB_TK switch_block_statement_groups switch_labels CCB_TK
+               { 
+                 /* Switch labels alone are empty switch statements */
+                 tree sl = build_tree_list ($3, NULL_TREE);
+                 TREE_CHAIN (sl) = $2;
+                 $$ = sl;
+               }
 ;
 
 switch_block_statement_groups: 
        switch_block_statement_group
 |      switch_block_statement_groups switch_block_statement_group
+               { 
+                 TREE_CHAIN ($2) = $1;
+                 $$ = $2;
+               }
 ;
 
 switch_block_statement_group:
-       switch_labels block_statements
+       group_of_labels block_statements
+               { $$ = build_tree_list ($1, exit_block ()); }
 ;
 
+group_of_labels:
+       switch_labels
+               { 
+                 /* All statements attached to this group of cases
+                    will be stored in a block */
+                 enter_block ();
+                 $$ = $1;
+               }
 
 switch_labels:
        switch_label
 |      switch_labels switch_label
+               {
+                 TREE_CHAIN ($2) = $1;
+                 $$ = $2;
+               }
 ;
 
 switch_label:
        CASE_TK constant_expression REL_CL_TK
+               { 
+                 $$ = build1 (CASE_EXPR, NULL_TREE, $2);
+                 EXPR_WFL_LINECOL ($$) = $1.location;
+               }
 |      DEFAULT_TK REL_CL_TK
+               { 
+                 $$ = build1 (DEFAULT_EXPR, NULL_TREE, NULL_TREE);
+                 EXPR_WFL_LINECOL ($$) = $1.location;
+               }
 |      CASE_TK error
                {yyerror ("Missing or invalid constant expression"); RECOVER;}
 |      CASE_TK constant_expression error
@@ -1361,6 +1395,7 @@ return_statement:
 
 throw_statement:
        THROW_TK expression SC_TK
+               { $$ = NULL_TREE;               /* FIXME */ }
 |      THROW_TK error
                {yyerror ("Missing term"); RECOVER;}
 |      THROW_TK expression error
@@ -1369,6 +1404,7 @@ throw_statement:
 
 synchronized_statement:
        synchronized OP_TK expression CP_TK block
+               { $$ = NULL_TREE;               /* FIXME */ }
 |      synchronized OP_TK expression CP_TK error
                {yyerror ("'{' expected"); RECOVER;}
 |      synchronized error
@@ -1388,8 +1424,11 @@ synchronized:                    /* Test lval.sub_token here */
 
 try_statement:
        TRY_TK block catches
+               { $$ = build_try_statement ($1.location, $2, $3, NULL_TREE); }
 |      TRY_TK block finally
+               { $$ = build_try_statement ($1.location, $2, NULL_TREE, $3); }
 |      TRY_TK block catches finally
+               { $$ = build_try_statement ($1.location, $2, $3, $4); }
 |      TRY_TK error
                {yyerror ("'{' expected"); DRECOVER (try_statement);}
 ;
@@ -1397,20 +1436,51 @@ try_statement:
 catches:
        catch_clause
 |      catches catch_clause
+               { 
+                 TREE_CHAIN ($2) = $1;
+                 $$ = $2;
+               }
 ;
 
 catch_clause:
-       CATCH_TK OP_TK formal_parameter CP_TK block
+       catch_clause_parameter block
+               { 
+                 java_method_add_stmt (current_function_decl, $2);
+                 exit_block ();
+                 $$ = $1;
+               }
+
+catch_clause_parameter:
+       CATCH_TK OP_TK formal_parameter CP_TK
+               { 
+                 /* We add a block to define a scope for
+                    formal_parameter (CCBP). The formal parameter is
+                    declared initialized by the appropriate function
+                    call */
+                 tree ccpb = enter_block ();
+                 tree init = build_assignment (ASSIGN_TK, $2.location, 
+                                               TREE_PURPOSE ($3), 
+                                               soft_exceptioninfo_call_node);
+                 declare_local_variables (0, TREE_VALUE ($3),
+                                          build_tree_list (TREE_PURPOSE ($3),
+                                                           init));
+                 $$ = build1 (CATCH_EXPR, NULL_TREE, ccpb);
+                 EXPR_WFL_LINECOL ($$) = $1.location;
+               }
 |      CATCH_TK error
                {yyerror ("'(' expected"); RECOVER;}
-|      CATCH_TK OP_TK error CP_TK /* That's for () */
-               {yyerror ("Missing term"); DRECOVER (1);}
 |      CATCH_TK OP_TK error 
-               {yyerror ("Missing term"); DRECOVER (2);}
+               {yyerror ("Missing term or ')' expected"); DRECOVER (2);}
+|      CATCH_TK OP_TK error CP_TK /* That's for () */
+               {yyerror ("')' expected"); DRECOVER (1);}
 ;
 
 finally:
        FINALLY_TK block
+               { 
+                 $$ = build (FINALLY_EXPR, NULL_TREE,
+                             create_label_decl (generate_name ()), $2);
+               }
 |      FINALLY_TK error
                {yyerror ("'{' expected"); RECOVER; }
 ;
@@ -1435,12 +1505,16 @@ primary_no_new_array:
           'type' into its components. Missing is something for array,
           which will complete the reference_type part. FIXME */
 |      name DOT_TK CLASS_TK           /* Added, JDK1.1 class literals */
+               { $$ = parse_jdk1_1_error ("class literals"); }
 |      primitive_type DOT_TK CLASS_TK /* Added, JDK1.1 class literals */
+               { $$ = parse_jdk1_1_error ("class literals"); }
 |      VOID_TK DOT_TK CLASS_TK        /* Added, JDK1.1 class literals */
+               { $$ = parse_jdk1_1_error ("class literals"); }
         /* Added, JDK1.1 inner classes. Documentation is wrong
            refering to a 'ClassName' (class_name) rule that doesn't
            exist. Used name instead.  */
 |      name DOT_TK THIS_TK
+               { $$ = parse_jdk1_1_error ("class literals"); }
 |      OP_TK expression error 
                {yyerror ("')' expected"); RECOVER;}
 |      name DOT_TK error
@@ -1453,22 +1527,16 @@ primary_no_new_array:
 
 class_instance_creation_expression:
        NEW_TK class_type OP_TK argument_list CP_TK
-               {
-                 $$ = build_method_invocation ($2, $4);
-                 TREE_SET_CODE ($$, JAVA_NEW_CLASS_EXPR);
-               }
+               { $$ = build_new_invocation ($2, $4); }
 |      NEW_TK class_type OP_TK CP_TK
-               {
-                 $$ = build_method_invocation ($2, NULL_TREE);
-                 TREE_SET_CODE ($$, JAVA_NEW_CLASS_EXPR);
-               }
+               { $$ = build_new_invocation ($2, NULL_TREE); }
         /* Added, JDK1.1 inner classes but modified to use
            'class_type' instead of 'TypeName' (type_name) mentionned
            in the documentation but doesn't exist. */
 |      NEW_TK class_type OP_TK argument_list CP_TK class_body
-{$$ = $2;}
+               { $$ = parse_jdk1_1_error ("inner class instance creation"); }
 |      NEW_TK class_type OP_TK CP_TK class_body         
-{$$ = $2;}
+               { $$ = parse_jdk1_1_error ("inner class instance creation"); }
         /* Added, JDK1.1 inner classes, modified to use name or
           primary instead of primary solely which couldn't work in
           all situations.  */
@@ -1522,9 +1590,9 @@ array_creation_expression:
         /* Added, JDK1.1 anonymous array. Initial documentation rule
            modified */
 |      NEW_TK class_or_interface_type dims array_initializer
-{$$ = $2;}
+               { $$ = parse_jdk1_1_error ("anonymous array"); }
 |      NEW_TK primitive_type dims array_initializer
-{$$ = $2;}
+               { $$ = parse_jdk1_1_error ("anonymous array"); }
 |      NEW_TK error CSB_TK
                {yyerror ("'[' expected"); DRECOVER ("]");}
 |      NEW_TK error OSB_TK
@@ -1569,7 +1637,8 @@ field_access:
 |      SUPER_TK DOT_TK identifier
                {
                  tree super_wfl = 
-                   build_wfl_node (super_identifier_node, input_filename, 0, 0);
+                   build_wfl_node (super_identifier_node, 
+                                   input_filename, 0, 0);
                  EXPR_WFL_LINECOL (super_wfl) = $1.location;
                  $$ = make_qualified_name (super_wfl, $3, $2.location);
                }
@@ -1595,7 +1664,8 @@ method_invocation:
 |      SUPER_TK DOT_TK identifier OP_TK CP_TK
                {
                  tree invok;
-                 tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0);
+                 tree wfl = build_wfl_node (super_identifier_node, 
+                                            input_filename, 0, 0);
                  EXPR_WFL_LINECOL (wfl) = $1.location;
                  invok = build_method_invocation ($3, NULL_TREE);
                  $$ = make_qualified_primary (wfl, invok, $2.location);
@@ -1603,7 +1673,8 @@ method_invocation:
 |      SUPER_TK DOT_TK identifier OP_TK argument_list CP_TK
                {
                  tree invok;
-                 tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0);
+                 tree wfl = build_wfl_node (super_identifier_node, 
+                                            input_filename, 0, 0);
                  EXPR_WFL_LINECOL (wfl) = $1.location;
                  invok = build_method_invocation ($3, $5);
                  $$ = make_qualified_primary (wfl, invok, $2.location);
@@ -2043,6 +2114,17 @@ java_pop_parser_context ()
   free (toFree);
 }
 
+/* Reporting JDK1.1 features not implemented */
+
+static tree
+parse_jdk1_1_error (msg)
+    char *msg;
+{
+  sorry (": `%s' JDK1.1(TM) feature", msg);
+  java_error_count++;
+  return size_zero_node;
+}
+
 static int do_warning = 0;
 
 void
@@ -2212,8 +2294,11 @@ java_accstring_lookup (flags)
 #undef COPY_RETURN
 }
 
+/* Issuing error messages upon redefinition of classes, interfaces or
+   variables. */
+
 static void
-redefinition_error (context, id, decl, cl)
+classitf_redefinition_error (context, id, decl, cl)
      char *context;
      tree id, decl, cl;
 {
@@ -2223,6 +2308,26 @@ redefinition_error (context, id, decl, cl)
   /* Here we should point out where its redefined. It's a unicode. FIXME */
 }
 
+static void
+variable_redefinition_error (context, name, type, line)
+     tree context, name, type;
+     int line;
+{
+  char *type_name;
+
+  /* Figure a proper name for type. We might haven't resolved it */
+  if (TREE_CODE (type) == TREE_LIST)
+    type_name = IDENTIFIER_POINTER (TYPE_NAME (TREE_PURPOSE (type)));
+  else
+    type_name = (char *)lang_printable_name (type);
+
+  parse_error_context (context,
+                      "Variable `%s' is already defined in this method and "
+                      "was declared `%s %s' at line %d", 
+                      IDENTIFIER_POINTER (name),
+                      type_name, IDENTIFIER_POINTER (name), line);
+}
+
 /* Build something that the type identifier resolver will identify as
    being an array to an unresolved type. TYPE_WFL is a WFL on a
    identifier. */
@@ -2311,8 +2416,8 @@ check_class_interface_creation (is_interface, flags, raw_name, qualified_name, d
     }
   if (decl && CLASS_COMPLETE_P (decl))
     {
-      redefinition_error ((is_interface ? "Interface" : "Class"), 
-                         qualified_name, decl, cl);
+      classitf_redefinition_error ((is_interface ? "Interface" : "Class"), 
+                                  qualified_name, decl, cl);
       return 1;
     }
 
@@ -2617,6 +2722,8 @@ register_fields (flags, type, variable_list)
          must_chain = 1;
        }
     }
+  if (!must_chain && TREE_CODE (type) == RECORD_TYPE)
+    type = promote_type (type);
 
   for (current = variable_list; current; current = TREE_CHAIN (current))
     {
@@ -3235,6 +3342,7 @@ java_complete_class ()
   tree cclass;
   jdeplist *cclassd;
   int error_found;
+  tree type;
 
   push_obstacks (&permanent_obstack, &permanent_obstack);
 
@@ -3276,9 +3384,7 @@ java_complete_class ()
                tree field_decl = JDEP_DECL (dep);
                tree field_type = TREE_TYPE (decl);
                push_obstacks (&permanent_obstack, &permanent_obstack);
-#if ! JAVA_PROMOTE_TO_INT
                if (TREE_CODE (field_type) == RECORD_TYPE)
-#endif
                  field_type = promote_type (field_type);
                pop_obstacks ();
                TREE_TYPE (field_decl) = field_type;
@@ -3295,7 +3401,9 @@ java_complete_class ()
                {
                  if (decl)
                    {
-                     tree type = promote_type (TREE_TYPE(decl));
+                     type = TREE_TYPE(decl);
+                     if (TREE_CODE (type) == RECORD_TYPE)
+                       type = promote_type (type);
                      JDEP_APPLY_PATCH (dep, type);
                      SOURCE_FRONTEND_DEBUG 
                        (((JDEP_KIND (dep) == JDEP_METHOD_RETURN ?
@@ -3333,14 +3441,12 @@ java_complete_class ()
              parser_add_interface (JDEP_DECL (dep), decl, JDEP_WFL (dep));
              break;
 
+           case JDEP_PARM:
            case JDEP_VARIABLE:
-             JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl)));
-             SOURCE_FRONTEND_DEBUG 
-               (("Completing variable `%s' with type `%s'",
-                 (TREE_CODE (JDEP_DECL_WFL (dep)) == EXPR_WITH_FILE_LOCATION ?
-                  IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))) :
-                  IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL_WFL (dep)))),
-                 IDENTIFIER_POINTER (DECL_NAME (decl))));
+             type = TREE_TYPE(decl);
+             if (TREE_CODE (type) == RECORD_TYPE)
+               type = promote_type (type);
+             JDEP_APPLY_PATCH (dep, type);
              break;
 
            case JDEP_TYPE:
@@ -3350,14 +3456,6 @@ java_complete_class ()
                  tree_code_name [TREE_CODE (JDEP_DECL (dep))]));
              break;
 
-           case JDEP_PARM:
-             JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl)));
-             SOURCE_FRONTEND_DEBUG 
-               (("Completing parameter `%s' with type `%s'",
-                 IDENTIFIER_POINTER (JDEP_MISC (dep)),
-                 IDENTIFIER_POINTER (DECL_NAME (decl))));
-             break;
-
            default:
              fatal ("incomplete switch - java_complete_class");
            }
@@ -3562,7 +3660,8 @@ complete_class_report_errors (dep)
       parse_error_context
        (JDEP_WFL (dep), "Type `%s' not found in the declaration of the "
         "local variable `%s'", 
-        purify_type_name (IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep)))),
+        purify_type_name (IDENTIFIER_POINTER 
+                          (EXPR_WFL_NODE (JDEP_WFL (dep)))),
         IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep))));
       break;
     }
@@ -4268,6 +4367,8 @@ declare_local_variables (modifier, type, vlist)
          must_chain = 1;
        }
     }
+  if (!must_chain && TREE_CODE (type) == RECORD_TYPE)
+    type = promote_type (type);
   
   for (current = vlist; current; current = TREE_CHAIN (current))
     {
@@ -4281,15 +4382,10 @@ declare_local_variables (modifier, type, vlist)
        init = NULL_TREE;
 
       if (other)
-       parse_error_context 
-         (wfl, "Variable `%s' is already defined in this method and was "
-          "declared `%s %s' in line %d", 
-          IDENTIFIER_POINTER (name), lang_printable_name (TREE_TYPE (other)),
-          IDENTIFIER_POINTER (name), DECL_SOURCE_LINE (other));
+       variable_redefinition_error (wfl, name, TREE_TYPE (other),
+                                    DECL_SOURCE_LINE (other));
       else
        {
-         if (!must_chain && TREE_CODE (type) == RECORD_TYPE)
-           type = promote_type (type);
          /* Never layout this decl. This will be done when its scope
              will be entered */
          decl = build_decl_no_layout (VAR_DECL, name, type);
@@ -4382,7 +4478,13 @@ expand_start_java_method (fndecl)
   while (tem)
     {
       tree next = TREE_CHAIN (tem);
-      DECL_ARG_TYPE (tem) = TREE_TYPE (tem);
+      tree type = TREE_TYPE (tem);
+#ifdef PROMOTE_PROTOTYPES
+      if (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
+         && INTEGRAL_TYPE_P (type))
+       type = integer_type_node;
+#endif
+      DECL_ARG_TYPE (tem) = type;
       layout_decl (tem, 0);
       pushdecl (tem);
       INITIALIZED_P (tem) = 1; /* Parms are initialized */
@@ -4406,6 +4508,9 @@ source_end_java_method ()
   java_parser_context_save_global ();
   lineno = ctxp->last_ccb_indent1;
 
+  /* Set EH language codes */
+  java_set_exception_lang_code ();
+
   /* Generate function's code */
   if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl))
       && ! flag_emit_class_files)
@@ -4420,6 +4525,8 @@ source_end_java_method ()
   if (! flag_emit_class_files)
     {
       lineno = DECL_SOURCE_LINE_LAST (fndecl);
+      /* Emit catch-finally clauses */
+      emit_handlers ();
       expand_function_end (input_filename, lineno, 0);
 
       /* Run the optimizers and output assembler code for this function. */
@@ -4438,17 +4545,24 @@ tree
 java_method_add_stmt (fndecl, expr)
      tree fndecl, expr;
 {
-  tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl));
-  tree node;
+  return add_stmt_to_block (DECL_FUNCTION_BODY (fndecl), NULL_TREE, expr);
+}
 
+static tree
+add_stmt_to_block (b, type, stmt)
+     tree b, type, stmt;
+{
+  tree body = BLOCK_EXPR_BODY (b), c;
+  
   if (java_error_count)
     return body;
-  if ((node = add_stmt_to_compound (body, NULL_TREE, expr)) == body)
+    
+  if ((c = add_stmt_to_compound (body, type, stmt)) == body)
     return body;
 
-  BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) = node;
-  TREE_SIDE_EFFECTS (node) = 1;
-  return node;
+  BLOCK_EXPR_BODY (b) = c;
+  TREE_SIDE_EFFECTS (c) = 1;
+  return c;
 }
 
 /* Add STMT to EXISTING if possible, otherwise create a new
@@ -4637,7 +4751,7 @@ make_qualified_primary (primary, right, location)
   /* We want to process THIS . xxx symbolicaly, to keep it consistent
      with the way we're processing SUPER. A THIS from a primary as a
      different form than a SUPER. Turn THIS into something symbolic */
-  if (TREE_CODE (primary) == JAVA_THIS_EXPR)
+  if (TREE_CODE (primary) == THIS_EXPR)
     {
       wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0);
       EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (primary);
@@ -4880,7 +4994,7 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
       switch (TREE_CODE (qual_wfl))
        {
        case CALL_EXPR:
-       case JAVA_NEW_CLASS_EXPR:
+       case NEW_CLASS_EXPR:
          /* If the access to the function call is a non static field,
             build the code to access it. */
          if (DECL_P (decl) && !FIELD_STATIC (decl))
@@ -5027,7 +5141,10 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
             come. Don't do that when processing something after SUPER
             (we need more thing to be put in place below */
          if (!from_super && QUAL_RESOLUTION (q))
-           decl = QUAL_RESOLUTION (q);
+           {
+             decl = QUAL_RESOLUTION (q);
+             *type_found = type;
+           }
 
          /* We have to search for a field, knowing the type of its
              container. The flag FROM_TYPE indicates that we resolved
@@ -5108,7 +5225,6 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
                 search from */
              decl = field_decl;
            }
-
          from_type = 0;
          type = QUAL_DECL_TYPE (decl);
        }
@@ -5403,11 +5519,11 @@ patch_method_invocation_stmt (patch, primary, where, is_static)
 
       class_type = class_to_search;
     }
-  
+
   /* Merge point of all resolution schemes. If we have nothing, this
      is an error, already signaled */
   if (!list) return error_mark_node;
-  
+
   /* Check accessibility, position the is_static flag, build and
      return the call */
   if (not_accessible_p (class_type, list, 0))
@@ -5540,7 +5656,8 @@ invocation_mode (method, super)
   return INVOKE_VIRTUAL;
 }
 
-/* Retrieve a refined list of matching methods. */
+/* Retrieve a refined list of matching methods. It covers the step
+   15.11.2 (Compile-Time Step 2) */
 
 static tree
 lookup_method_invoke (lc, cl, class, name, arg_list)
@@ -5551,22 +5668,22 @@ lookup_method_invoke (lc, cl, class, name, arg_list)
   tree method = make_node (FUNCTION_TYPE);
   tree arg_type_list = NULL_TREE;
   tree signature, list, node, scratch;
+  char *candidates;            /* Used for error report */
 
   for (node = arg_list; node; node = TREE_CHAIN (node))
     {
-      tree current_arg;
-      current_arg = 
-       build_tree_list (NULL_TREE,
-                        promote_type (TREE_TYPE (TREE_VALUE (node))));
-      arg_type_list = chainon (current_arg, arg_type_list);
+      tree current_arg = TREE_TYPE (TREE_VALUE (node));
+      if (TREE_CODE (current_arg) == RECORD_TYPE)
+       current_arg = promote_type (current_arg);
+      arg_type_list = tree_cons (NULL_TREE, current_arg, arg_type_list);
     }
   TYPE_ARG_TYPES (method) = arg_type_list;
 
   if (!lc)
     {
-      signature = build_java_argument_signature (method);
-      list = match_java_method (class, name, signature);
-      list = refine_accessible_methods_list (lc, list);
+      list = find_applicable_accessible_methods_list (class, name, 
+                                                     arg_type_list);
+      list = find_most_specific_methods_list (list);
     }
   else
     {
@@ -5575,132 +5692,181 @@ lookup_method_invoke (lc, cl, class, name, arg_list)
       list = lookup_java_constructor (class, signature);
     }
 
-  if (!list)
-    {
-      parse_error_context (cl, "Can't find method `%s(%s)' in class `%s'",
-                          IDENTIFIER_POINTER (name),
-                          IDENTIFIER_POINTER (signature),
-                          IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class))));
-      return NULL_TREE;
-    }
-
-  if (lc)
+  if (lc && list)
     return list;
+  if (list && !TREE_CHAIN (list))
+    return TREE_VALUE (list);
 
-  if (TREE_CHAIN (list))
+  /* Issue an error. List candidates if any. Candidates are listed
+     only if accessible (non accessible methods may end-up here for
+     the sake of a better error report). */
+  candidates = NULL;
+  if (list)
     {
-      tree most_specific_list = NULL_TREE;
       tree current;
-      /* 15.11.2.2 Choose the Most Specific Method */
+      obstack_grow (&temporary_obstack, ". Candidates are:\n", 18);
       for (current = list; current; current = TREE_CHAIN (current))
        {
-         tree rest;
-         tree method = TREE_VALUE (list);
-         tree class_from = DECL_CONTEXT (method);
-         for (rest = TREE_CHAIN (current); rest; rest = TREE_CHAIN (rest))
+         tree cm = TREE_VALUE (current);
+         char string [4096];
+         if (!cm || not_accessible_p (class, cm, 0))
+           continue;
+         signature = build_java_argument_signature (TREE_TYPE (cm));
+         sprintf 
+           (string, "  `%s(%s)' in `%s'%s",
+            IDENTIFIER_POINTER (name), 
+            IDENTIFIER_POINTER (signature),
+            IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (cm)))),
+            (TREE_CHAIN (current) ? "\n" : ""));
+         obstack_grow (&temporary_obstack, string, strlen (string));
+       }
+      obstack_1grow (&temporary_obstack, '\0');
+      candidates = obstack_finish (&temporary_obstack);
+    }
+  /* Issue the error message */
+  signature = build_java_argument_signature (method);
+  parse_error_context (cl, "Can't find method `%s(%s)' in class `%s'%s",
+                      IDENTIFIER_POINTER (name),
+                      IDENTIFIER_POINTER (signature),
+                      IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class))),
+                      (candidates ? candidates : ""));
+  return NULL_TREE;
+}
+
+/* 15.11.2.1: Find Methods that are Applicable and Accessible */
+
+static tree
+find_applicable_accessible_methods_list (class, name, arglist)
+     tree class, name, arglist;
+{
+  tree method;
+  tree list = NULL_TREE, all_list = NULL_TREE;
+
+  while (class != NULL_TREE)
+    {
+      for (method = TYPE_METHODS (class);
+          method != NULL_TREE;  method = TREE_CHAIN (method))
+       {
+         /* Names have to match and we're not looking for constructor */
+         if (DECL_NAME (method) != name
+             || DECL_CONSTRUCTOR_P (method))
+           continue;
+
+         if (argument_types_convertible (method, arglist))
            {
-             tree other = TREE_VALUE (rest);
-
-             /* METHOD can be declared more specific with regard to OTHER iif:
-               
-                - The class METHOD belongs can be converted to the
-                  class OTHER belongs by method invocation conversion
-                  (5.3).  Since we're dealing with classes here, it is
-                  covered by the identity conversion or the windening
-                  primitive conversion.
-               
-                - The types of the arguments of METHOD can be
-                  converted to the types of the arguments of OTHER by
-                  method invocation conversion (5.3). */
-
-             if (valid_ref_assignconv_cast_p (class_from, 
-                                              DECL_CONTEXT (other), 0)
-                 && 1)         /* Test on args non implemented */
-               most_specific_list = tree_cons (NULL_TREE, method, 
-                                               most_specific_list);
+             /* Retain accessible methods only */
+             if (!not_accessible_p (class, method, 0))
+               list = tree_cons (NULL_TREE, method, list);
+             else
+             /* Also retain all selected method here */
+               all_list = tree_cons (NULL_TREE, method, list);
            }
        }
-      list = most_specific_list;
+      class = CLASSTYPE_SUPER (class);
     }
+  /* Either return the list obtained or all selected (but
+     inaccessible) methods for better error report. */
+  return (!list ? all_list : list);
+}
 
-  if (!list || TREE_CHAIN (list))
+/* 15.11.2.2 Choose the Most Specific Method */
+
+static tree
+find_most_specific_methods_list (list)
+     tree list;
+{
+  int max = 0;
+  tree current, new_list = NULL_TREE;
+  for (current = list; current; current = TREE_CHAIN (current))
     {
-      parse_error_context (cl, "Can't find method `%s(%s)' in class `%s'",
-                          IDENTIFIER_POINTER (name),
-                          IDENTIFIER_POINTER (signature),
-                          IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class))));
-      return NULL_TREE;
+      tree method;
+      DECL_SPECIFIC_COUNT (TREE_VALUE (current)) = 0;
+
+      for (method = list; method; method = TREE_CHAIN (method))
+       {
+         /* 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))))
+           {
+             int v = ++DECL_SPECIFIC_COUNT (TREE_VALUE (current));
+             max = (v > max ? v : max);
+           }
+       }
     }
 
-  /* 15.11.3 Is the Chosen Method Appropriate ? */
-  else
-    return TREE_VALUE (list);
+  /* Review the list and select the maximally specific methods */
+  for (current = list; current; current = TREE_CHAIN (current))
+    if (DECL_SPECIFIC_COUNT (TREE_VALUE (current)) == max)
+      new_list = tree_cons (NULL_TREE, TREE_VALUE (current), new_list);
+
+  /* If we can't find one, lower expectations and try to gather multiple
+     maximally specific methods */
+  while (!new_list)
+    {
+      while (--max > 0)
+       {
+         if (DECL_SPECIFIC_COUNT (TREE_VALUE (current)) == max)
+           new_list = tree_cons (NULL_TREE, TREE_VALUE (current), new_list);
+       }
+      return new_list;
+    }
+
+  return new_list;
 }
 
-/* Refine accessible methods from the raw matching method list, as
-   specified in 15.11.4.3. Return a (possibly empty) new method
-   list.  */
+/* Make sure that the type of each M2_OR_ARGLIST arguments can be
+   converted by method invocation conversion (5.3) to the type of the
+   corresponding parameter of M1. Implementation expects M2_OR_ARGLIST
+   to change less often than M1. */
 
-static tree
-refine_accessible_methods_list (lc, list)
-     int lc;                   /* Looking for Constructor */
-     tree list;
+static int
+argument_types_convertible (m1, m2_or_arglist)
+    tree m1, m2_or_arglist;
 {
-#define ADD_TO_LIST_AND_CONTINUE                               \
-  {                                                            \
-    refined_list = tree_cons (NULL_TREE, method, refined_list);        \
-    continue;                                                  \
-  }
-  tree node, refined_list = NULL_TREE;
-  tree current_class_name = DECL_NAME (TYPE_NAME (current_class));
+  static tree m2_arg_value = NULL_TREE;
+  static tree m2_arg_cache = NULL_TREE;
 
-  for (node = list; node; node = TREE_CHAIN (node))
-    {
-      int access, identical;
-      tree class_from, method, class_from_name;
-      
-      method = TREE_VALUE (node);
+  register tree m1_arg, m2_arg;
 
-      /* Constructor not retained here, unless were specifically
-       looking for them. */
-      if (lc && DECL_CONSTRUCTOR_P (method))
-       ADD_TO_LIST_AND_CONTINUE;
+  m1_arg = TYPE_ARG_TYPES (TREE_TYPE (m1));
+  if (!METHOD_STATIC (m1))
+    m1_arg = TREE_CHAIN (m1_arg);
 
-      access = get_access_flags_from_decl (method);
-      class_from = DECL_CONTEXT (method);
-      class_from_name = DECL_NAME (TYPE_NAME (class_from));
-      
-      identical = identical_subpath_p (current_class_name, class_from_name);
-
-      /* Check accessibility of class_from from the current one: This
-        test has been already carried out when qualify_ambiguous_name
-        tried to resolve a type found in an other package. It is not
-        necessary to retest things here, the error has been already
-        reported. */
-                 
-      /* Public method are always OK */
-      if (access & ACC_PUBLIC)
-       ADD_TO_LIST_AND_CONTINUE;
-      
-      /* Protected method access is OK if classes are from the
-        same package or part of the same inheritance lineage */
-      if ((access & ACC_PROTECTED)
-         && (inherits_from_p (current_class, class_from) || identical))
-       ADD_TO_LIST_AND_CONTINUE;
+  if (m2_arg_value == m2_or_arglist)
+    m2_arg = m2_arg_cache;
+  else
+    {
+      /* M2_OR_ARGLIST can be a function DECL or a raw list of
+         argument types */
+      if (m2_or_arglist && TREE_CODE (m2_or_arglist) == FUNCTION_DECL)
+       {
+         m2_arg = TYPE_ARG_TYPES (TREE_TYPE (m2_or_arglist));
+         if (!METHOD_STATIC (m2_or_arglist))
+           m2_arg = TREE_CHAIN (m2_arg);
+       }
+      else
+       m2_arg = m2_or_arglist;
 
-      /* Methods with default (package) access are OK if classes are
-        from the same default package. */
-      if (identical || 
-         (!QUALIFIED_P (class_from_name) && !QUALIFIED_P (current_class_name)))
-       ADD_TO_LIST_AND_CONTINUE;
+      m2_arg_value = m2_or_arglist;
+      m2_arg_cache = m2_arg;
+    }
 
-      /* Private method accessible iff current class is the node where
-        the method is defined */
-      if ((access & ACC_PRIVATE) && (class_from == current_class))
-       ADD_TO_LIST_AND_CONTINUE;
+  while (m1_arg && m2_arg)
+    {
+      if (!valid_method_invocation_conversion_p (TREE_VALUE (m1_arg),
+                                                TREE_VALUE (m2_arg)))
+       break;
+      m1_arg = TREE_CHAIN (m1_arg);
+      m2_arg = TREE_CHAIN (m2_arg);
     }
-#undef ADD_TO_LIST_AND_CONTINUE
-  return refined_list;
+  return (!m1_arg && !m2_arg ? 1 : 0);
 }
 
 /* Qualification routines */
@@ -5738,7 +5904,7 @@ qualify_ambiguous_name (id)
            qual_wfl = QUAL_WFL (qual);
          }
        break;
-      case JAVA_NEW_CLASS_EXPR:
+      case NEW_CLASS_EXPR:
       case CONVERT_EXPR:
       case ARRAY_REF:
        qual_wfl = TREE_OPERAND (qual_wfl, 0);
@@ -5908,10 +6074,10 @@ java_complete_tree (node)
      tree node;
 {
   tree nn, cn, wfl_op1, wfl_op2;
-  int flag, location;
+  int flag;
 
   /* CONVERT_EXPR always has its type set, even though it needs to be
-     worked out */
+     worked out. */
   if (TREE_TYPE (node) && TREE_CODE (node) != CONVERT_EXPR)
     return node;
 
@@ -5946,6 +6112,10 @@ java_complete_tree (node)
       break;
 
       /* 2- They are expressions but ultimately deal with statements */
+
+    case TRY_EXPR:
+      return patch_try_statement (node);
+
     case LABELED_BLOCK_EXPR:
       PUSH_LABELED_BLOCK (node);
       if (LABELED_BLOCK_BODY (node))
@@ -5959,14 +6129,21 @@ java_complete_tree (node)
          the EXIT_BLOCK_EXPR which doesn't exist it Java */
       return patch_bc_statement (node);
 
+    case SWITCH_EXPR:
     case LOOP_EXPR:
       PUSH_LOOP (node);
       /* Check whether the loop was enclosed in a labeled
          statement. If not, create one, insert the loop in it and
          return the node */
       nn = patch_loop_statement (node);
+
       /* Anyways, walk the body of the loop */
-      TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0));
+      if (TREE_CODE (node) == LOOP_EXPR)
+       TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0));
+      /* Switch statement: walk the switch expression and the cases */
+      else
+       node = patch_switch_statement (node);
+
       if (TREE_OPERAND (node, 0) == error_mark_node)
        return error_mark_node;
       TREE_TYPE (nn) = TREE_TYPE (node) = void_type_node;
@@ -6028,7 +6205,7 @@ java_complete_tree (node)
        }
       break;
 
-    case JAVA_NEW_ARRAY_EXPR:
+    case NEW_ARRAY_EXPR:
       /* Patch all the dimensions */
       flag = 0;
       for (cn = TREE_OPERAND (node, 1); cn; cn = TREE_CHAIN (cn))
@@ -6054,9 +6231,9 @@ java_complete_tree (node)
          were found. */
       return (flag ? error_mark_node : patch_newarray (node));
 
-    case JAVA_NEW_CLASS_EXPR:
+    case NEW_CLASS_EXPR:
     case CALL_EXPR:
-      /* Complete function's argument first */
+      /* Complete function's argument(s) first */
       if (complete_function_arguments (node))
        return error_mark_node;
       else
@@ -6102,6 +6279,12 @@ java_complete_tree (node)
          return error_mark_node;
        }
       TREE_OPERAND (node, 1) = nn;
+
+      /* In case we're handling = with a String as a RHS, we need to
+        produce a String out of the RHS (it might still be a
+        STRING_CST or a StringBuffer at this stage */
+      if ((nn = patch_string (TREE_OPERAND (node, 1))))
+       TREE_OPERAND (node, 1) = nn;
       return patch_assignment (node, wfl_op1, wfl_op2);
 
     case MULT_EXPR:
@@ -6127,15 +6310,23 @@ java_complete_tree (node)
         knows how to handle those cases. */
       wfl_op1 = TREE_OPERAND (node, 0);
       wfl_op2 = TREE_OPERAND (node, 1);
-      TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1);
-      if (TREE_OPERAND (node, 0) == error_mark_node)
-        return error_mark_node;
-      TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2);
-      if (TREE_OPERAND (node, 1) == error_mark_node)
-       return error_mark_node;
+
+      /* Don't complete string nodes if dealing with the PLUS operand. */
+      if (TREE_CODE (node) != PLUS_EXPR || !JSTRING_P (wfl_op1))
+       {
+         TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1);
+         if (TREE_OPERAND (node, 0) == error_mark_node)
+           return error_mark_node;
+       }
+      if (TREE_CODE (node) != PLUS_EXPR || !JSTRING_P (wfl_op2))
+       {
+         TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2);
+         if (TREE_OPERAND (node, 1) == error_mark_node)
+           return error_mark_node;
+       }
       return patch_binop (node, wfl_op1, wfl_op2);
 
-    case JAVA_UNARY_PLUS_EXPR:
+    case UNARY_PLUS_EXPR:
     case NEGATE_EXPR:
     case TRUTH_NOT_EXPR:
     case BIT_NOT_EXPR:
@@ -6159,14 +6350,17 @@ java_complete_tree (node)
       TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1);
       if (TREE_OPERAND (node, 0) == error_mark_node)
        return error_mark_node;
+      if (!flag_emit_class_files)
+       TREE_OPERAND (node, 0) = save_expr (TREE_OPERAND (node, 0));
       /* The same applies to wfl_op2 */
       wfl_op2 = TREE_OPERAND (node, 1);
       TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2);
       if (TREE_OPERAND (node, 1) == error_mark_node)
        return error_mark_node;
+      TREE_OPERAND (node, 1) = save_expr (TREE_OPERAND (node, 1));
       return patch_array_ref (node, wfl_op1, wfl_op2);
 
-    case JAVA_THIS_EXPR:
+    case THIS_EXPR:
       /* Can't use THIS in a static environment */
       if (!current_this)
        {
@@ -6178,16 +6372,12 @@ java_complete_tree (node)
        }
       return current_this;
 
-    case STRING_CST:
-      /* Build the internal string representation */
-      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);
-      TREE_TYPE (node) = promote_type (string_type_node);
-      return node;
-
     default:
+      /* Ok: may be we have a STRING_CST or a crafted `StringBuffer'
+        and it's time to turn it into the appropriate String object
+        */
+      if ((node = patch_string (node)))
+       return node;
       fatal ("No case for tree code `%s' - java_complete_tree\n",
             tree_code_name [TREE_CODE (node)]);
     }
@@ -6206,13 +6396,19 @@ complete_function_arguments (node)
 
   for (cn = TREE_OPERAND (node, 1); cn; cn = TREE_CHAIN (cn))
     {
-      tree wfl = TREE_VALUE (cn), parm;
+      tree wfl = TREE_VALUE (cn), parm, temp;
       parm = java_complete_tree (wfl);
       if (parm == error_mark_node)
        {
          flag = 1;
          continue;
        }
+      /* If have a string literal that we haven't transformed yet or a
+        crafted string buffer, as a result of use of the the String
+        `+' operator. Build `parm.toString()' and expand it. */
+      if ((temp = patch_string (parm)))
+       parm = TREE_VALUE (cn) = temp;
+      
       if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE)
        TREE_VALUE (cn) = convert (promote_type (TREE_TYPE (parm)), parm);
       else
@@ -6250,25 +6446,31 @@ build_expr_block (body, decls)
 {
   tree node = make_node (BLOCK);
   BLOCK_EXPR_DECLS (node) = decls;
-  BLOCK_EXPR_BODY (body);
+  BLOCK_EXPR_BODY (node) = body;
   if (body)
     TREE_TYPE (node) = TREE_TYPE (body);
   TREE_SIDE_EFFECTS (node) = 1;
   return node;
 }
 
-/* Create a new function block and link its supercontext to the
-   previous block. The current function DECL is used as supercontext
-   when enter_block is called for the first time for a given
-   function. The current function body (DECL_FUNCTION_BODY) is set to
-   the newly created block.  */
-
-static block_level = 0;
+/* Create a new function block and link it approriately to current
+   function block chain */
 
 static tree
 enter_block ()
 {
-  tree b = build_expr_block (NULL_TREE, NULL_TREE);
+  return (enter_a_block (build_expr_block (NULL_TREE, NULL_TREE)));
+}
+
+/* Link block B supercontext to the previous block. The current
+   function DECL is used as supercontext when enter_a_block is called
+   for the first time for a given function. The current function body
+   (DECL_FUNCTION_BODY) is set to be block B.  */
+
+static tree
+enter_a_block (b)
+     tree b;
+{
   tree fndecl = current_function_decl; 
 
   if (!DECL_FUNCTION_BODY (fndecl))
@@ -6342,7 +6544,7 @@ maybe_absorb_scoping_blocks ()
    are building incomplete tree nodes and the patch_* functions that
    are completing them.  */
 
-/* Build an incomplete CALL_EXPR node. Encapsulate it within a WFL */
+/* Build an incomplete CALL_EXPR node. */
 
 static tree
 build_method_invocation (name, args)
@@ -6351,7 +6553,18 @@ build_method_invocation (name, args)
 {
   tree call = build (CALL_EXPR, NULL_TREE, name, args, NULL_TREE);
   TREE_SIDE_EFFECTS (call) = 1;
-  /* Check on cases where NAME isn't a WFL. FIXME */
+  EXPR_WFL_LINECOL (call) = EXPR_WFL_LINECOL (name);
+  return call;
+}
+
+/* Build an incomplete new xxx(...) node. */
+
+static tree
+build_new_invocation (name, args)
+    tree name, args;
+{
+  tree call = build (NEW_CLASS_EXPR, NULL_TREE, name, args, NULL_TREE);
+  TREE_SIDE_EFFECTS (call) = 1;
   EXPR_WFL_LINECOL (call) = EXPR_WFL_LINECOL (name);
   return call;
 }
@@ -6413,7 +6626,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
      tree wfl_op1;
      tree wfl_op2;
 {
-  tree rhs = TREE_OPERAND (node, 1);
+  tree rhs = TREE_OPERAND (node, 1), temp;
   tree lvalue = TREE_OPERAND (node, 0);
   tree lhs_type, rhs_type, new_rhs = NULL_TREE;
   int all_primitive;
@@ -6458,56 +6671,14 @@ patch_assignment (node, wfl_op1, wfl_op2)
     }
 
   rhs_type = TREE_TYPE (rhs);
+  /* 5.1 Try the assignment conversion for builtin type. */
+  if ((new_rhs = try_builtin_assignconv (wfl_op1, lhs_type, rhs)))
+    ;
 
-  /* 5.2 Begin Assignment conversion */
-
-  /* 5.1.1 Try Identity Conversion */
-  if (lhs_type == rhs_type) 
-    new_rhs = rhs;
-  
-  /* 5.1.2 Try Widening Primitive Conversion */
-  all_primitive = JPRIMITIVE_TYPE_P (lhs_type) && JPRIMITIVE_TYPE_P (rhs_type);
-  if (all_primitive && JINTEGRAL_TYPE_P (rhs_type)
-      && ((TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type))
-         || (JFLOAT_TYPE_P (lhs_type) &&
-             TYPE_PRECISION (rhs_type) == TYPE_PRECISION (lhs_type))))
-    new_rhs = convert (lhs_type, rhs);
-  else if (all_primitive && JFLOAT_TYPE_P (rhs_type)
-          && (TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type)))
-    new_rhs = convert (lhs_type, rhs);
-
-  /* Try a narrowing primitive conversion: 
-       - expression is a constant expression of type int AND
-       - variable is byte, short or char AND
-       - The value of the expression is representable in the type of the 
-         variable */
-  else if (rhs_type == int_type_node && TREE_CONSTANT (rhs)
-          && (lhs_type == byte_type_node || lhs_type == char_type_node
-              || lhs_type == short_type_node))
-    {
-      if (int_fits_type_p (rhs, lhs_type))
-        new_rhs = convert (lhs_type, rhs);
-      else
-       parse_warning_context 
-         (wfl_op1, "Constant expression `%s' to wide for narrowing "
-          "primitive conversion to `%s'", 
-          print_int_node (rhs), lang_printable_name (lhs_type));
-      /* Reported a warning that will turn into an error further
-        down, so we don't return */
-    }
-
-  /* 5.2 Try a reference conversion */
-  else if (!JPRIMITIVE_TYPE_P (rhs_type) && JREFERENCE_TYPE_P (lhs_type))
-    {
-      /* `null' may be assigned to any reference type */
-      if (rhs == null_pointer_node)
-        new_rhs = null_pointer_node;
-      /* Try the reference assignment conversion */
-      else if (valid_ref_assignconv_cast_p (rhs_type, lhs_type, 0))
-       new_rhs = rhs;
-      if (new_rhs)
-       lhs_type = promote_type (rhs_type);
-    }
+  /* 5.2 If it failed, try a reference conversion */
+  if (!new_rhs &&
+      (new_rhs = try_reference_assignconv (lhs_type, rhs)))
+    lhs_type = promote_type (rhs_type);
 
   /* 15.25.2 If we have a compound assignment, convert RHS into the
      type of the LHS */
@@ -6546,7 +6717,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
        }
 
       parse_error_context 
-       (wfl, (!can_cast_to_p (rhs_type, lhs_type) ?
+       (wfl, (!valid_cast_to_p (rhs_type, lhs_type) ?
               "Incompatible type for %s. Can't convert `%s' to `%s'" :
               "Incompatible type for %s. Explicit cast "
               "needed to convert `%s' to `%s'"), operation, t1, t2);
@@ -6576,28 +6747,106 @@ patch_assignment (node, wfl_op1, wfl_op2)
   return node;
 }
 
-/* Check that SOURCE can be converted into DEST, at least with a
-   cast. If the convertion can't occur at all, return 0 otherwise
-   1. This function is used to produce accurate error messages on the
-   reasons why an assignment failed. */
+/* Check that type SOURCE can be cast into type DEST. If the cast
+   can't occur at all, return 0 otherwise 1. This function is used to
+   produce accurate error messages on the reasons why an assignment
+   failed. */
 
-static int
-can_cast_to_p (source, dest)
-     tree source;
-     tree dest;
+static tree
+try_reference_assignconv (lhs_type, rhs)
+     tree lhs_type, rhs;
 {
-  if (TREE_CODE (source) == POINTER_TYPE)
-    source = TREE_TYPE (source);
-  if (TREE_CODE (dest) == POINTER_TYPE)
-    dest = TREE_TYPE (dest);
+  tree new_rhs = NULL_TREE;
+  tree rhs_type = TREE_TYPE (rhs);
 
-  if (TREE_CODE (source) == RECORD_TYPE && TREE_CODE (dest) == RECORD_TYPE)
-    return valid_ref_assignconv_cast_p (source, dest, 1);
-
-  else if (JNUMERIC_TYPE_P (source) && JNUMERIC_TYPE_P (dest))
-    return 1;
-
-  return 0;
+  if (!JPRIMITIVE_TYPE_P (rhs_type) && JREFERENCE_TYPE_P (lhs_type))
+    {
+      /* `null' may be assigned to any reference type */
+      if (rhs == null_pointer_node)
+        new_rhs = null_pointer_node;
+      /* Try the reference assignment conversion */
+      else if (valid_ref_assignconv_cast_p (rhs_type, lhs_type, 0))
+       new_rhs = rhs;
+      /* This is a magic assignment that we process differently */
+      else if (rhs == soft_exceptioninfo_call_node)
+       new_rhs = rhs;
+    }
+  return new_rhs;
+}
+
+/* Check that RHS can be converted into LHS_TYPE by the assignment
+   conversion (5.2), for the cases of RHS being a builtin type. Return
+   NULL_TREE if the conversion fails or if because RHS isn't of a
+   builtin type. Return a converted RHS if the conversion is possible.  */
+
+static tree
+try_builtin_assignconv (wfl_op1, lhs_type, rhs)
+     tree wfl_op1, lhs_type, rhs;
+{
+  tree new_rhs = NULL_TREE;
+  tree rhs_type = TREE_TYPE (rhs);
+
+  /* 5.1.1 Try Identity Conversion,
+     5.1.2 Try Widening Primitive Conversion */
+  if (valid_builtin_assignconv_identity_widening_p (lhs_type, rhs_type))
+    new_rhs = convert (lhs_type, rhs);
+
+  /* Try a narrowing primitive conversion (5.1.3): 
+       - expression is a constant expression of type int AND
+       - variable is byte, short or char AND
+       - The value of the expression is representable in the type of the 
+         variable */
+  else if (rhs_type == int_type_node && TREE_CONSTANT (rhs)
+          && (lhs_type == byte_type_node || lhs_type == char_type_node
+              || lhs_type == short_type_node))
+    {
+      if (int_fits_type_p (rhs, lhs_type))
+        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'", 
+          print_int_node (rhs), lang_printable_name (lhs_type));
+      /* Reported a warning that will turn into an error further
+        down, so we don't return */
+    }
+
+  return new_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
+   0 is the conversion test fails.  This implements parts the method
+   invocation convertion (5.3).  */
+
+static int
+valid_builtin_assignconv_identity_widening_p (lhs_type, rhs_type)
+     tree lhs_type, rhs_type;
+{
+  int all_primitive = 
+    JPRIMITIVE_TYPE_P (lhs_type) && JPRIMITIVE_TYPE_P (rhs_type);
+
+  if (!all_primitive)
+    return 0;
+
+  if (lhs_type == rhs_type)
+    return 1;
+
+  /* byte, even if it's smaller than a char can't be converted into a
+     char. Short can't too, but the < test below takes care of that */
+  if (lhs_type == char_type_node && rhs_type == byte_type_node)
+    return 0;
+
+  if (JINTEGRAL_TYPE_P (rhs_type)
+      && ((TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type))
+         || (JFLOAT_TYPE_P (lhs_type) &&
+             TYPE_PRECISION (rhs_type) == TYPE_PRECISION (lhs_type))))
+    return 1;
+  else if (JFLOAT_TYPE_P (rhs_type)
+          && (TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type)))
+    return 1;
+
+  return 0;
 }
 
 /* Check that something of SOURCE type can be assigned or cast to
@@ -6644,7 +6893,7 @@ valid_ref_assignconv_cast_p (source, dest, cast)
            return dest == object_type_node;
          /* We're doing a cast. The cast is always valid is class
             DEST is not final, otherwise, DEST must implement SOURCE */
-         else if (!CLASS_FINAL (TYPE_NAME (source)))
+         else if (!CLASS_FINAL (TYPE_NAME (dest)))
            return 1;
          else
            return interface_of_p (source, dest);
@@ -6704,6 +6953,41 @@ valid_ref_assignconv_cast_p (source, dest, cast)
   return 0;
 }
 
+static int
+valid_cast_to_p (source, dest)
+     tree source;
+     tree dest;
+{
+  if (TREE_CODE (source) == POINTER_TYPE)
+    source = TREE_TYPE (source);
+  if (TREE_CODE (dest) == POINTER_TYPE)
+    dest = TREE_TYPE (dest);
+
+  if (TREE_CODE (source) == RECORD_TYPE && TREE_CODE (dest) == RECORD_TYPE)
+    return valid_ref_assignconv_cast_p (source, dest, 1);
+
+  else if (JNUMERIC_TYPE_P (source) && JNUMERIC_TYPE_P (dest))
+    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 int
+valid_method_invocation_conversion_p (dest, source)
+     tree dest, source;
+{
+  return ((JPRIMITIVE_TYPE_P (source) 
+           && JPRIMITIVE_TYPE_P (dest)
+           && valid_builtin_assignconv_identity_widening_p (dest, source))
+          || (JREFERENCE_TYPE_P (source) 
+              && JREFERENCE_TYPE_P (dest)
+              && valid_ref_assignconv_cast_p (source, dest, 0)));
+}
+
 /* Build an incomplete binop expression. */
 
 static tree
@@ -6712,15 +6996,9 @@ build_binop (op, op_location, op1, op2)
      int op_location;
      tree op1, op2;
 {
-  tree wfl;
-
-  /* URSHIFT_EXPR is not part of what GCC understands, we can't directly build
-     a node with it */
-  tree binop = 
-    build ((op == URSHIFT_EXPR ? RSHIFT_EXPR : op), NULL_TREE, op1, op2);
-  if (op == URSHIFT_EXPR)
-    TREE_SET_CODE (binop, op);
+  tree wfl, binop, merge;
 
+  binop = build (op, NULL_TREE, op1, op2);
   TREE_SIDE_EFFECTS (binop) = 1;
   /* Store the location of the operator, for better error report. The
      string of the operator will be rebuild based on the OP value. */
@@ -6766,7 +7044,7 @@ operator_string (node)
     case GE_EXPR: BUILD_OPERATOR_STRING (">=");
     case LT_EXPR: BUILD_OPERATOR_STRING ("<");
     case LE_EXPR: BUILD_OPERATOR_STRING ("<=");
-    case JAVA_UNARY_PLUS_EXPR: BUILD_OPERATOR_STRING ("+");
+    case UNARY_PLUS_EXPR: BUILD_OPERATOR_STRING ("+");
     case NEGATE_EXPR: BUILD_OPERATOR_STRING ("-");
     case TRUTH_NOT_EXPR: BUILD_OPERATOR_STRING ("!");
     case BIT_NOT_EXPR: BUILD_OPERATOR_STRING ("~");
@@ -6800,6 +7078,7 @@ patch_binop (node, wfl_op1, wfl_op2)
   tree op2_type = TREE_TYPE (op2);
   tree prom_type;
   int code = TREE_CODE (node);
+
   /* If 1, tell the routine that we have to return error_mark_node
      after checking for the initialization of the RHS */
   int error_found = 0;
@@ -6850,8 +7129,20 @@ patch_binop (node, wfl_op1, wfl_op2)
 
     /* 15.17 Additive Operators */
     case PLUS_EXPR:            /* 15.17.1 String Concatenation Operator + */
-      if (JSTRING_TYPE_P (op1_type) || JSTRING_TYPE_P (op2_type))
-       fatal ("operator `+' non implemented on String - patch_binop");
+
+      /* Operation is valid if either one argument is a string
+        constant, a String object or a StringBuffer crafted for the
+        purpose of the a previous usage of the String concatenation
+        operator */
+
+      if (TREE_CODE (op1) == STRING_CST 
+         || TREE_CODE (op2) == STRING_CST
+         || JSTRING_TYPE_P (op1_type)
+         || JSTRING_TYPE_P (op2_type)
+         || IS_CRAFTED_STRING_BUFFER_P (op1)
+         || IS_CRAFTED_STRING_BUFFER_P (op2))
+       return build_string_concatenation (op1, op2);
+
     case MINUS_EXPR:           /* 15.17.2 Additive Operators (+ and -) for
                                   Numeric Types */
       if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type))
@@ -7002,7 +7293,7 @@ patch_binop (node, wfl_op1, wfl_op2)
                || JREFERENCE_TYPE_P (op1_type) 
                || JREFERENCE_TYPE_P (op2_type))
               && ((op1_type == op2_type)
-                  /* The should use a can_cast_to_p() */
+                  /* There should use a valid_cast_to_p() */
                   ))
        ;                       /* Nothing to do here */
          
@@ -7044,10 +7335,195 @@ patch_binop (node, wfl_op1, wfl_op2)
   return fold (node);
 }
 
-/* Build an incomplete unary operator expression. Unary `+' node is
-   build as a CONV_EXPR, even though its tree code is overridden by a
-   JAVA_UNARY_PLUS_EXPR that isn't a tree code, to differentiate it during
-   the walk. */
+/* Concatenate the STRING_CST CSTE and STRING. When AFTER is a non
+   zero value, the value of CSTE comes after the valude of STRING */
+
+static tree
+do_merge_string_cste (cste, string, string_len, after)
+     tree cste;
+     char *string;
+     int string_len, after;
+{
+  int len = TREE_STRING_LENGTH (cste) + string_len;
+  char *old = TREE_STRING_POINTER (cste);
+  TREE_STRING_LENGTH (cste) = len;
+  TREE_STRING_POINTER (cste) = obstack_alloc (expression_obstack, len+1);
+  if (after)
+    {
+      strcpy (TREE_STRING_POINTER (cste), string);
+      strcat (TREE_STRING_POINTER (cste), old);
+    }
+  else
+    {
+      strcpy (TREE_STRING_POINTER (cste), old);
+      strcat (TREE_STRING_POINTER (cste), string);
+    }
+  return cste;
+}
+
+/* Tries to merge OP1 (a STRING_CST) and OP2 (if suitable). Return a
+   new STRING_CST on success, NULL_TREE on failure */
+
+static tree
+merge_string_cste (op1, op2, after)
+     tree op1, op2;
+     int after;
+{
+  /* Handle two string constants right away */
+  if (TREE_CODE (op2) == STRING_CST)
+    return do_merge_string_cste (op1, TREE_STRING_POINTER (op2), 
+                                TREE_STRING_LENGTH (op2), after);
+  
+  /* Reasonable integer constant can be treated right away */
+  if (TREE_CODE (op2) == INTEGER_CST && !TREE_CONSTANT_OVERFLOW (op2))
+    {
+      static char *boolean_true = "true";
+      static char *boolean_false = "false";
+      static char *null_pointer = "null";
+      char ch[3];
+      char *string;
+      
+      if (op2 == boolean_true_node)
+       string = boolean_true;
+      else if (op2 == boolean_false_node)
+       string = boolean_false;
+      else if (op2 == null_pointer_node)
+       string = null_pointer;
+      else if (TREE_TYPE (op2) == char_type_node)
+       {
+         ch[0] = (char )TREE_INT_CST_LOW (op2);
+         ch[1] = '\0';
+         string = ch;
+       }
+      else
+         string = print_int_node (op2);
+      
+      return do_merge_string_cste (op1, string, strlen (string), after);
+    }
+  return NULL_TREE;
+}
+
+/* Tries to statically concatenate OP1 and OP2 if possible. Either one
+   has to be a STRING_CST and the other part must be a STRING_CST or a
+   INTEGRAL constant. Return a new STRING_CST if the operation
+   succeed, NULL_TREE otherwise.
+
+   If the case we want to optimize for space, we might want to return
+   NULL_TREE for each invocation of this routine. FIXME */
+
+static tree
+string_constant_concatenation (op1, op2)
+     tree op1, op2;
+{
+  if (TREE_CODE (op1) == STRING_CST || (TREE_CODE (op2) == STRING_CST))
+    {
+      tree string, rest, result;
+      int invert;
+      
+      string = (TREE_CODE (op1) == STRING_CST ? op1 : op2);
+      rest   = (string == op1 ? op2 : op1);
+      invert = (string == op1 ? 0 : 1 );
+      
+      /* Walk REST, only if it looks reasonable */
+      if (TREE_CODE (rest) != STRING_CST
+         && !IS_CRAFTED_STRING_BUFFER_P (rest)
+         && !JSTRING_TYPE_P (TREE_TYPE (rest))
+         && TREE_CODE (rest) == EXPR_WITH_FILE_LOCATION)
+       {
+         rest = java_complete_tree (rest);
+         if (rest == error_mark_node)
+           return error_mark_node;
+         rest = fold (rest);
+       }
+      return merge_string_cste (string, rest, invert);
+    }
+  return NULL_TREE;
+}
+
+/* Implement the `+' operator. Does static optimization if possible,
+   otherwise create (if necessary) and append elements to a
+   StringBuffer. The StringBuffer will be carried around until it is
+   used for a function call or an assignment. Then toString() will be
+   called on it to turn it into a String object. */
+
+static tree
+build_string_concatenation (op1, op2)
+     tree op1, op2;
+{
+  tree result;
+  
+  /* Try to do some static optimization */
+  if ((result = string_constant_concatenation (op1, op2)))
+    return result;
+
+  /* If operands are string constant, turn then into object references */
+
+  if (TREE_CODE (op1) == STRING_CST)
+    op1 = patch_string_cst (op1);
+  if (TREE_CODE (op2) == STRING_CST)
+    op2 = patch_string_cst (op2);
+
+  /* If OP1 isn't already a StringBuffer, create and
+     initialize a new one */
+  if (!IS_CRAFTED_STRING_BUFFER_P (op1))
+    {
+      /* Two solutions here: 
+        1) OP1 is a string reference, we call new StringBuffer(OP1)
+        2) Op2 is something else, we call new StringBuffer().append(OP1). */
+      if (JSTRING_TYPE_P (TREE_TYPE (op1)))
+       op1 = BUILD_STRING_BUFFER (op1);
+      else
+       {
+         tree aNew = BUILD_STRING_BUFFER (NULL_TREE);
+         op1 = make_qualified_primary (aNew, BUILD_APPEND (op1), 0);
+       }
+    }
+
+  /* No longer the last node holding a crafted StringBuffer */
+  IS_CRAFTED_STRING_BUFFER_P (op1) = 0;
+  /* Create a node for `{new...,xxx}.append (op2)' */
+  op1 = make_qualified_primary (op1, BUILD_APPEND (op2), 0);
+  /* Mark the last node holding a crafted StringBuffer */
+  IS_CRAFTED_STRING_BUFFER_P (op1) = 1;
+  
+  return op1;
+}
+
+/* Patch the string node NODE. NODE can be a STRING_CST of a crafted
+   StringBuffer. If no string were found to be patched, return
+   NULL. */
+
+static tree
+patch_string (node)
+    tree node;
+{
+  if (TREE_CODE (node) == STRING_CST)
+    return patch_string_cst (node);
+  else if (IS_CRAFTED_STRING_BUFFER_P (node))
+    {
+      tree invoke = build_method_invocation (wfl_to_string, NULL_TREE);
+      return java_complete_tree (make_qualified_primary (node, invoke, 0));
+    }
+  return NULL_TREE;
+}
+
+/* Build the internal representation of a string constant.  */
+
+static tree
+patch_string_cst (node)
+     tree node;
+{
+  int location;
+  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);
+  TREE_TYPE (node) = promote_type (string_type_node);
+  TREE_CONSTANT (node) = 1;
+  return node;
+}
+
+/* Build an incomplete unary operator expression. */
 
 static tree
 build_unaryop (op_token, op_location, op1)
@@ -7058,7 +7534,7 @@ build_unaryop (op_token, op_location, op1)
   tree unaryop;
   switch (op_token)
     {
-    case PLUS_TK: op = CONVERT_EXPR; break;
+    case PLUS_TK: op = UNARY_PLUS_EXPR; break;
     case MINUS_TK: op = NEGATE_EXPR; break;
     case NEG_TK: op = TRUTH_NOT_EXPR; break;
     case NOT_TK: op = BIT_NOT_EXPR; break;
@@ -7067,9 +7543,6 @@ build_unaryop (op_token, op_location, op1)
     }
 
   unaryop = build1 (op, NULL_TREE, op1);
-  if (op_token == PLUS_TK)
-    TREE_SET_CODE (unaryop, JAVA_UNARY_PLUS_EXPR);
-
   TREE_SIDE_EFFECTS (unaryop) = 1;
   /* Store the location of the operator, for better error report. The
      string of the operator will be rebuild based on the OP value. */
@@ -7142,7 +7615,8 @@ patch_unaryop (node, wfl_op)
     case PREINCREMENT_EXPR:
       /* 15.14.2 Prefix Decrement Operator -- */
     case PREDECREMENT_EXPR:
-      if (!DECL_P (op))
+      if (!DECL_P (op) && !(TREE_CODE (op) == INDIRECT_REF 
+                           && JPRIMITIVE_TYPE_P (TREE_TYPE (op))))
        {
          parse_error_context (wfl_operator, "Invalid argument to `%s'",
                               operator_string (node));
@@ -7181,7 +7655,7 @@ patch_unaryop (node, wfl_op)
       break;
 
       /* 15.14.3 Unary Plus Operator + */
-    case JAVA_UNARY_PLUS_EXPR:
+    case UNARY_PLUS_EXPR:
       /* 15.14.4 Unary Minus Operator - */
     case NEGATE_EXPR:
       if (!JNUMERIC_TYPE_P (op_type))
@@ -7195,7 +7669,7 @@ patch_unaryop (node, wfl_op)
        {
          prom_type = promote_type (op_type);
          op = convert (prom_type, op);
-         if (code == JAVA_UNARY_PLUS_EXPR)
+         if (code == UNARY_PLUS_EXPR)
            node = op;
        }
       break;
@@ -7249,8 +7723,8 @@ patch_unaryop (node, wfl_op)
   
   if (error_found)
     return error_mark_node;
-  /* In the case of JAVA_UNARY_PLUS_EXPR, we replaced NODE by a new one */
-  else if (code != JAVA_UNARY_PLUS_EXPR && code != CONVERT_EXPR)
+  /* In the case of UNARY_PLUS_EXPR, we replaced NODE by a new one */
+  else if (code != UNARY_PLUS_EXPR && code != CONVERT_EXPR)
     {
       TREE_OPERAND (node, 0) = op;
       TREE_TYPE (node) = prom_type;
@@ -7316,7 +7790,7 @@ patch_cast (node, wfl_op, wfl_operator)
   /* The remaining legal casts involve conversion between reference
      types. Check for their compile time correctness. */
   if (JREFERENCE_TYPE_P (op_type) && JREFERENCE_TYPE_P (cast_type) 
-      && valid_ref_assignconv_cast_p (op_type, cast_type, 1))
+      && valid_ref_assignconv_cast_p (cast_type, op_type, 1))
     {
       TREE_TYPE (node) = promote_type (cast_type);
       /* Now, the case can be determined correct at compile time if
@@ -7374,8 +7848,6 @@ patch_array_ref (node, wfl_array, wfl_index)
       ERROR_VARIABLE_NOT_INITIALIZED (wfl_array, DECL_NAME (array));
       INITIALIZED_P (array) = 1;
     }
-  if (! flag_emit_class_files)
-    array = save_expr (array);
 
   if (TREE_CODE (array_type) == POINTER_TYPE)
     array_type = TREE_TYPE (array_type);
@@ -7395,7 +7867,7 @@ patch_array_ref (node, wfl_array, wfl_index)
   promoted_index_type = promote_type (index_type);
   if (promoted_index_type != int_type_node)
     {
-      int could_cast = can_cast_to_p (index_type, int_type_node);
+      int could_cast = valid_cast_to_p (index_type, int_type_node);
       parse_error_context 
        (wfl_operator, 
         (could_cast ? "Incompatible type for `[]'. Explicit cast needed to "
@@ -7439,9 +7911,8 @@ build_newarray_node (type, dims, extra_dims)
      int extra_dims;
 {
   tree node =
-    build (CALL_EXPR, NULL_TREE, type, nreverse (dims), 
+    build (NEW_ARRAY_EXPR, NULL_TREE, type, nreverse (dims), 
           build_int_2 (extra_dims, 0));
-  TREE_SET_CODE (node, JAVA_NEW_ARRAY_EXPR);
   return node;
 }
 
@@ -7487,7 +7958,7 @@ patch_newarray (node)
            (TREE_PURPOSE (cdim), 
             "Incompatible type for dimension in array creation expression. "
             "%s convert `%s' to `int'", 
-            (can_cast_to_p (TREE_TYPE (dim), int_type_node) ?
+            (valid_cast_to_p (TREE_TYPE (dim), int_type_node) ?
              "Explicit cast needed to" : "Can't"),
             lang_printable_name (TREE_TYPE (dim)));
          error_found = 1;
@@ -7578,7 +8049,7 @@ build_this (location)
      int location;
 {
   tree node = build_wfl_node (this_identifier_node, input_filename, 0, 0);
-  TREE_SET_CODE (node, JAVA_THIS_EXPR);
+  TREE_SET_CODE (node, THIS_EXPR);
   EXPR_WFL_LINECOL (node) = location;
   return node;
 }
@@ -7594,6 +8065,7 @@ build_return (location, op)
 {
   tree node = build1 (RETURN_EXPR, NULL_TREE, op);
   EXPR_WFL_LINECOL (node) = location;
+  node = build_debugable_stmt (location, node);
   return node;
 }
 
@@ -7663,6 +8135,7 @@ build_if_else_statement (location, expression, if_body, else_body)
     else_body = build (COMPOUND_EXPR, void_type_node, NULL_TREE, NULL_TREE);
   node = build (COND_EXPR, NULL_TREE, expression, if_body, else_body);
   EXPR_WFL_LINECOL (node) = location;
+  node = build_debugable_stmt (location, node);
   return node;
 }
 
@@ -7676,7 +8149,8 @@ patch_if_else_statement (node)
   EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
 
   /* The type of expression must be boolean */
-  if (TREE_TYPE (expression) != boolean_type_node)
+  if (TREE_TYPE (expression) != boolean_type_node
+      && TREE_TYPE (expression) != promoted_boolean_type_node)
     {
       parse_error_context 
        (wfl_operator, 
@@ -7734,17 +8208,10 @@ build_labeled_block (location, label, wfl)
 static tree
 generate_labeled_block ()
 {
-  static int l_number = 0;
-  char buf [20];
-  tree label_name;
-  
-  sprintf (buf, "$a%d", l_number++);
-  return build_labeled_block (0, get_identifier (buf), NULL_TREE);
+  return build_labeled_block (0, generate_name (), NULL_TREE);
 }
 
-/* A labeled statement LBE is attached a statement. If the statement
-   happens to be a loop, a link from the loop back to the label is
-   installed.  */
+/* A labeled statement LBE is attached a statement.  */
 
 static tree
 complete_labeled_statement (lbe, statement)
@@ -7791,7 +8258,15 @@ build_new_loop (loop_body)
        INCREMENT               (if any)
 
   REVERSED, if non zero, tells that the loop condition expr comes
-  after the body, like in the do-while loop.  */
+  after the body, like in the do-while loop.
+
+  To obtain a loop, the loop body structure described above is
+  encapsulated within a LOOP_EXPR surrounded by a LABELED_BLOCK_EXPR:
+
+   LABELED_BLOCK_EXPR
+     LABEL_DECL                   (use this label to exit the loop)
+     LOOP_EXPR
+       <structure described above> */
 
 static tree
 build_loop_body (location, condition, reversed)
@@ -7912,6 +8387,7 @@ build_bc_statement (location, is_break, name)
   IS_BREAK_STMT_P (break_continue) = is_break;
   TREE_SIDE_EFFECTS (break_continue) = 1;
   EXPR_WFL_LINECOL (break_continue) = location;
+  break_continue = build_debugable_stmt (location, break_continue);
   return break_continue;
 }
 
@@ -7923,24 +8399,30 @@ patch_bc_statement (node)
 {
   tree bc_label = EXIT_BLOCK_LABELED_BLOCK (node), target_stmt;
   int is_unlabeled = 0;
- EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
 EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
  
   /* Not having a target means that the break/continue statement is
-     unlabeled. We try to find a descent label for it */
+     unlabeled. We try to find a decent label for it */
   if (!bc_label)
     {
       is_unlabeled = 1;
-      /* There should be a loop to branch to */
+      /* There should be a loop/switch to branch to */
       if (ctxp->current_loop)
        {
-         /* At that stage, we're in the loop body, which is
-            encapsulated around a LABELED_BLOCK_EXPR. So searching
-            the current loop label requires us to consider the
-            labeled block before the current one. */
-         if (!LOOP_HAS_LABEL_SKIP_P (ctxp->current_loop))
-           fatal ("unlabeled loop has not installed label -- "
-                  "patch_bc_statement");
-         bc_label = TREE_CHAIN (ctxp->current_labeled_block);
+         if (TREE_CODE (ctxp->current_loop) == LOOP_EXPR)
+           {
+             /* At that stage, we're in the loop body, which is
+                encapsulated around a LABELED_BLOCK_EXPR. So searching
+                the current loop label requires us to consider the
+                labeled block before the current one. */
+             if (!LOOP_HAS_LABEL_SKIP_P (ctxp->current_loop))
+               fatal ("unlabeled loop has no installed label -- "
+                      "patch_bc_statement");
+             bc_label = TREE_CHAIN (ctxp->current_labeled_block);
+           }
+         /* For a SWITCH statement, this is the current one */
+         else
+           bc_label = ctxp->current_labeled_block;
        }
       /* Not having a loop to break/continue to is an error */
       else
@@ -7969,8 +8451,8 @@ patch_bc_statement (node)
          (already verified). Anonymous break need to target
          while/do/for/switch */
       if (is_unlabeled &&
-         !(TREE_CODE (target_stmt) == LOOP_EXPR   /* do/while/for */
-           || 0))                                 /* switch FIXME */
+         !(TREE_CODE (target_stmt) == LOOP_EXPR        /* do/while/for */
+           || TREE_CODE (target_stmt) == SWITCH_EXPR)) /* switch FIXME */
        {
          parse_error_context (wfl_operator, 
                               "`break' must be in loop or switch");
@@ -8033,3 +8515,425 @@ patch_exit_expr (node)
   TREE_TYPE (node) = void_type_node;
   return node;
 }
+
+/* 14.9 Switch statement */
+
+static tree
+patch_switch_statement (node)
+     tree node;
+{
+  int error_found = 0;
+  tree se = TREE_OPERAND (node, 0), se_type, sb;
+  tree default_found = NULL_TREE;
+
+  /* Complete the switch expression */
+  se = TREE_OPERAND (node, 0) = java_complete_tree (se);
+  se_type = TREE_TYPE (se);
+  /* The type of the switch expression must be char, byte, short or
+     int */
+  if (!JINTEGRAL_TYPE_P (se_type))
+    {
+      EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
+      parse_error_context (wfl_operator, "Incompatible type for `switch'. "
+                          "Can't convert `%s' to `int'",
+                          lang_printable_name (se_type));
+      /* This is what java_complete_tree will check */
+      TREE_OPERAND (node, 0) = error_mark_node;
+      return error_mark_node;
+    }
+
+  /* Process the switch body. We should have a list of TREE_LIST. The
+     PURPOSE of each node should be a list of case values, VALUE
+     should be the associated block. We try to process all cases and
+     defaults before returning, possibly finding errors.  */
+  TREE_OPERAND (node, 1) = nreverse (TREE_OPERAND (node, 1));
+  for (sb = TREE_OPERAND (node, 1); sb; sb = TREE_CHAIN (sb))
+    {
+      tree label;
+
+      /* If we don't have a TREE_LIST here, we have a statement inside
+        the switch that isn't tied to a label. This error is caught
+        by the parser and we don't have to report it here. */
+
+      TREE_PURPOSE (sb) = nreverse (TREE_PURPOSE (sb));
+      for (label = TREE_PURPOSE (sb); label; label = TREE_CHAIN (label))
+       {
+         tree case_expr;
+         
+         /* Verification of the default label */
+         if (TREE_CODE (label) == DEFAULT_EXPR)
+           {
+             /* Only one default label is allowed per switch
+                 statement */
+             if (default_found)
+               {
+                 EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
+                 parse_error_context (wfl_operator, 
+                                      "Duplicate case label: `default'");
+                 error_found = 1;
+               }
+             else
+               default_found = label;
+             continue;
+           }
+         /* Verification of case labels */
+         else
+           {
+             case_expr = java_complete_tree (TREE_OPERAND (label, 0));
+             if (case_expr == error_mark_node)
+               continue;
+
+             /* First, the case expression must be constant */
+             case_expr = fold (case_expr);
+             if (!TREE_CONSTANT (case_expr))
+               {
+                 EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
+                 parse_error_context (label, "Constant expression required");
+                 error_found = 1;
+                 break;
+               }
+             
+             /* It must be assignable to the type of the switch
+                expression. */
+             if (!try_builtin_assignconv (NULL_TREE, se_type, case_expr))
+               {
+                 EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
+                 parse_error_context 
+                   (wfl_operator,
+                    "Incompatible type for case. Can't convert `%s' to `int'",
+                    lang_printable_name (TREE_TYPE (case_expr)));
+                 error_found = 1;
+                 break;
+               }
+
+             /* Multiple instance of a case label bearing the same
+                 value is checked during code generation. The case
+                 expression is allright so far. */
+             TREE_OPERAND (label, 0) = case_expr;
+           }
+       }
+
+      /* First TREE_VALUE should be the block tied to this list of
+         cases. Check that this block exists and the walk it */
+      if (TREE_VALUE (sb))
+       {
+         TREE_VALUE (sb) = java_complete_tree (TREE_VALUE (sb));
+         if (TREE_VALUE (sb) == error_mark_node)
+           error_found = 1;
+       }
+    }
+
+  /* Ready to return */
+  if (error_found)
+    {
+      TREE_TYPE (node) = error_mark_node;
+      return error_mark_node;
+    }
+  TREE_TYPE (node) = void_type_node;
+  TREE_SIDE_EFFECTS (node) = 1;
+  return node;
+}
+
+/* Do the expansion of a Java switch. With Gcc, switches are front-end
+   dependant things, but they rely on gcc routines. This function is
+   placed here because it uses things defined locally in parse.y. */
+
+static tree
+case_identity (t, v)
+     tree t, v;
+{
+  return v;
+}
+
+void
+java_expand_switch (exp)
+     tree exp;
+{
+  tree sb;
+  expand_start_case (0, TREE_OPERAND (exp, 0), int_type_node, "switch");
+
+  for (sb = TREE_OPERAND (exp, 1); sb; sb = TREE_CHAIN (sb))
+    {
+      /* We have a list of TREE_LIST. PURPOSE is the case value, and
+        when it exists, VALUE is the associated block */
+      
+      /* The first CASE element should contain the associated block,
+        if any. All other should be case statements related to the
+        same block */
+      tree label;
+      for (label = TREE_PURPOSE (sb); label; label = TREE_CHAIN (label))
+       {
+         tree label_decl = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+         if (TREE_CODE (label) == CASE_EXPR)
+           {
+             tree duplicate;
+             if (pushcase (TREE_OPERAND (label, 0), case_identity,
+                           label_decl, &duplicate) == 2)
+               {
+                 EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
+                 parse_error_context
+                   (wfl_operator, "Duplicate case label: `%s'",
+                    print_int_node (TREE_OPERAND (label, 0)));
+               }
+           }
+         else
+           pushcase (NULL_TREE, 0, label_decl, NULL);
+       }
+      /* Expand the associated block, if any */
+      if (TREE_VALUE (sb))
+       expand_expr_stmt (TREE_VALUE (sb));
+    } 
+  expand_end_case (TREE_OPERAND (exp, 0));
+}
+
+/* 14.18 The try statement */
+
+/* Wrap BLOCK around a LABELED_BLOCK, set DECL to the newly generated
+   exit labeld and issue a jump to FINALLY_LABEL:
+     
+   LABELED_BLOCK
+     BLOCK
+       <orignal_statments>
+       DECL = &LABEL_DECL
+       GOTO_EXPR
+         FINALLY_LABEL
+     LABEL_DECL */
+
+static tree
+build_jump_to_finally (block, decl, finally_label, type)
+     tree block, decl, finally_label, type;
+{
+  tree stmt;
+  tree new_block = build (LABELED_BLOCK_EXPR, type,
+                         create_label_decl (generate_name ()), block);
+
+  stmt = build (MODIFY_EXPR, void_type_node, decl,
+               build_address_of (LABELED_BLOCK_LABEL (new_block)));
+  TREE_SIDE_EFFECTS (stmt) = 1;
+  add_stmt_to_block (block, type, stmt);
+  stmt = build (GOTO_EXPR, void_type_node, finally_label);
+  TREE_SIDE_EFFECTS (stmt) = 1;
+  add_stmt_to_block (block, type, stmt);
+  return new_block;
+}
+
+static tree
+build_try_statement (location, try_block, catches, finally)
+     int location;
+     tree try_block, catches, finally;
+{
+  tree node, rff;
+
+  if (finally)
+    {
+      /* This block defines a scope for the entire try[-catch]-finally
+        sequence. It hold a local variable used to return from the
+        finally using a computed goto. We call it
+        return_from_finally (RFF). */
+      rff = build_decl_no_layout (VAR_DECL, generate_name (),
+                                  return_address_type_node);
+
+      /* Modification of the try block. */
+      try_block = build_jump_to_finally (try_block, rff, 
+                                        FINALLY_EXPR_LABEL (finally), 
+                                        NULL_TREE);
+
+      /* To the finally block: add the computed goto */
+      add_stmt_to_block (FINALLY_EXPR_BLOCK (finally), NULL_TREE,
+                        build (GOTO_EXPR, void_type_node, rff));
+
+      /* Modification of each catch blocks, if any */
+      if (catches)
+       {
+         tree catch, catch_decl, catch_block, stmt;
+
+         for (catch = catches; catch; catch = TREE_CHAIN (catch))
+           TREE_OPERAND (catch, 0) = 
+             build_jump_to_finally (TREE_OPERAND (catch, 0), rff,
+                                    FINALLY_EXPR_LABEL (finally),
+                                    NULL_TREE);
+
+         /* Plus, at the end of the list, we add the catch clause that
+            will catch an uncaught exception, call finally and rethrow it:
+              BLOCK
+                void *exception_parameter; (catch_decl)
+                LABELED_BLOCK
+                  BLOCK
+                    exception_parameter = _Jv_exception_info ();
+                    RFF = &LABEL_DECL;
+                    goto finally;
+                LABEL_DECL;
+                CALL_EXPR
+                  Jv_ReThrow
+                  exception_parameter */
+         catch_decl = build_decl_no_layout (VAR_DECL, generate_name (),
+                                            ptr_type_node);
+         stmt = build (MODIFY_EXPR, void_type_node, catch_decl,
+                       soft_exceptioninfo_call_node);
+         TREE_SIDE_EFFECTS (stmt) = 1;
+         catch_block = build_expr_block (stmt, NULL_TREE);
+         catch_block = build_jump_to_finally (catch_block, rff, 
+                                              FINALLY_EXPR_LABEL (finally), 
+                                              void_type_node);
+         stmt = build (CALL_EXPR, void_type_node,
+                       build_address_of (throw_node),
+                       build_tree_list (NULL_TREE, catch_decl), NULL_TREE);
+         catch_block = build_expr_block (catch_block, catch_decl);
+         TREE_SIDE_EFFECTS (stmt) = 1;
+         add_stmt_to_block (catch_block, void_type_node, stmt);
+
+         /* Link the new handler to the existing list as the first
+            entry. It will be the last one to be generated. */
+         catch = build1 (CATCH_EXPR, void_type_node, catch_block);
+         TREE_CHAIN (catch) = catches;
+         catches = catch;
+       }
+    }
+
+  node = build (TRY_EXPR, NULL_TREE, try_block, catches, finally);
+  EXPR_WFL_LINECOL (node) = location;
+  
+  /* If we have a finally, surround this whole thing by a block where
+     the RFF local variable is defined. */
+
+  return (finally ? build_expr_block (node, rff) : node);
+}
+
+/* Get the catch clause block from an element of the catch clause
+   list. If depends on whether a finally clause exists or node (in
+   which case the original catch clause was surrounded by a
+   LABELED_BLOCK_EXPR. */
+
+tree
+java_get_catch_block (node, finally_present_p)
+     tree node;
+     int finally_present_p;
+{
+  return (CATCH_EXPR_GET_EXPR (TREE_OPERAND (node, 0), finally_present_p));
+}
+
+static tree
+patch_try_statement (node)
+     tree node;
+{
+  int error_found = 0;
+  tree try = TREE_OPERAND (node, 0);
+  /* Exception handlers are considered in left to right order */
+  tree catch = nreverse (TREE_OPERAND (node, 1));
+  tree finally = TREE_OPERAND (node, 2);
+  int finally_p = (finally ? 1 : 0);
+  tree current;
+
+  /* Walk the try block */
+  if ((try = java_complete_tree (try)) == error_mark_node)
+    error_found = 1;
+
+  /* Check catch clauses, if any. Every time we find an error, we try
+     to process the next catch clause. */
+  for (current = catch; current; current = TREE_CHAIN (current))
+    {
+      tree carg_decl, carg_type;
+      tree sub_current, catch_block, catch_clause;
+      int unreachable;
+
+      /* Always detect the last catch clause if a finally is
+         present. This is the catch-all handler and it just needs to
+         be walked. */
+      if (!TREE_CHAIN (current) && finally)
+       {
+         TREE_OPERAND (current, 0) = 
+           java_complete_tree (TREE_OPERAND (current, 0));
+         continue;
+       }
+
+      /* At this point, the structure of the catch clause is
+         LABELED_BLOCK_EXPR    (if we have a finally)
+          CATCH_EXPR           (catch node)
+            BLOCK              (with the decl of the parameter)
+               COMPOUND_EXPR
+                 MODIFIY_EXPR   (assignemnt of the catch parameter)
+                BLOCK          (catch clause block)
+           LABEL_DECL          (where to return after finally (if any))
+
+        Since the structure of the catch clause depends on the
+        presence of a finally, we use a function call to get to the
+        cath clause */
+      catch_clause = java_get_catch_block (current, finally_p);
+      carg_decl = BLOCK_EXPR_DECLS (catch_clause);
+      carg_type = TREE_TYPE (TREE_TYPE (carg_decl));
+
+      /* Catch clauses can't have more than one parameter declared,
+        but it's already enforced by the grammar. Make sure that the
+        only parameter of the clause statement in of class Throwable
+        or a subclass of Throwable, but that was done earlier. The
+        catch clause parameter type has also been resolved. */
+      
+      /* Just make sure that the catch clause parameter type inherits
+        from java.lang.Throwable */
+      if (!inherits_from_p (carg_type, throwable_type_node))
+       {
+         EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (current);
+         parse_error_context (wfl_operator,
+                              "Can't catch class `%s'. Catch clause "
+                              "parameter type must be a subclass of "
+                              "class `java.lang.Throwable'",
+                              lang_printable_name (carg_type));
+         error_found = 1;
+         continue;
+       }
+      
+      /* Partial check for unreachable catch statement: The catch
+        clause is reachable iff is no earlier catch block A in
+        the try statement such that the type of the catch
+        clause's parameter is the same as or a subclass of the
+        type of A's parameter */
+      unreachable = 0;
+      for (sub_current = catch;
+          sub_current != current; sub_current = TREE_CHAIN (sub_current))
+       {
+         tree sub_catch_clause, decl;
+         sub_catch_clause = java_get_catch_block (sub_current, finally_p);
+         decl = BLOCK_EXPR_DECLS (sub_catch_clause);
+
+         if (inherits_from_p (carg_type, TREE_TYPE (TREE_TYPE (decl))))
+           {
+             EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (current);
+             parse_error_context 
+               (wfl_operator, "`catch' not reached because of the catch "
+                "clause at line %d", EXPR_WFL_LINENO (sub_current));
+             unreachable = error_found = 1;
+             break;
+           }
+       }
+      if (unreachable)
+       continue;
+
+      /* Complete the catch clause block */
+      catch_block = java_complete_tree (TREE_OPERAND (current, 0));
+      if (catch_block == error_mark_node)
+       {
+         error_found = 1;
+         continue;
+       }
+      TREE_OPERAND (current, 0) = catch_block;
+    }
+
+  /* Process finally */
+  if (finally)
+    {
+      FINALLY_EXPR_BLOCK (finally) = 
+       java_complete_tree (FINALLY_EXPR_BLOCK (finally));
+      if (FINALLY_EXPR_BLOCK (finally) == error_mark_node)
+       error_found = 1;
+    }
+
+  /* Verification ends here */
+  if (error_found) 
+    return error_mark_node;
+
+  TREE_OPERAND (node, 0) = try;
+  TREE_OPERAND (node, 1) = catch;
+  TREE_OPERAND (node, 2) = finally;
+  TREE_TYPE (node) = void_type_node;
+  return node;
+}