[multiple changes]
authorAlexandre Petit-Bianco <apbianco@gcc.gnu.org>
Wed, 6 Dec 2000 18:55:42 +0000 (10:55 -0800)
committerAlexandre Petit-Bianco <apbianco@gcc.gnu.org>
Wed, 6 Dec 2000 18:55:42 +0000 (10:55 -0800)
2000-10-18  Alexandre Petit-Bianco  <apbianco@cygnus.com>

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

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

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

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

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

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

        * parse.y (array_type_literal): Remove production.
        (type_literals): Refer to array_type, not array_type_literal.

(http://gcc.gnu.org/ml/gcc-patches/2000-12/msg00317.html)

From-SVN: r38070

gcc/java/ChangeLog
gcc/java/check-init.c
gcc/java/decl.c
gcc/java/java-tree.h
gcc/java/jcf-write.c
gcc/java/parse.y

index 69044f8506a0694aefbb97d6d25ae02f512d91da..895f618eb24599160b091de099949e3faae89f54 100644 (file)
@@ -235,6 +235,17 @@ Thu Nov 23 02:19:14 2000  J"orn Rennecke <amylaar@redhat.com>
 
        * verify.c (CHECK_PC_IN_RANGE): Cast result of stmt-expr to void.
 
+2000-10-18  Alexandre Petit-Bianco  <apbianco@cygnus.com>
+
+       * jcf-write.c (OP1): Update `last_bc'.
+       (struct jcf_block): Fixed indentation and typo in comments.  New
+       field `last_bc'.
+       (generate_bytecode_insns): Insert `nop' if `jsr' immediately
+       follows `monitorenter'.
+       * parse.y (patch_synchronized_statement): New local `tmp'. Call
+       `patch_string'.
+       Fixes gcj/232.
+
 2000-10-16  Tom Tromey  <tromey@cygnus.com>
 
        * jvspec.c (lang_specific_driver): Recognize -MF and -MT.
@@ -298,6 +309,68 @@ Thu Nov 23 02:19:14 2000  J"orn Rennecke <amylaar@redhat.com>
        * decl.c (init_decl_processing): Call init_class_processing before
        anything else.
 
+2000-10-13  Alexandre Petit-Bianco  <apbianco@cygnus.com>
+
+       * check-init.c (check_init): Fixed leading comment. Use
+       LOCAL_FINAL_P.
+       * decl.c (push_jvm_slot): Use MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
+       (give_name_to_locals): Likewise.
+       (lang_mark_tree): Handle FIELD_DECL. Register `am' and `wfl'
+       fields in lang_decl_var.
+       * java-tree.h (DECL_FUNCTION_SYNTHETIC_CTOR,
+       DECL_FUNCTION_ALL_FINAL_INITIALIZED): New macros.
+       (FIELD_INNER_ACCESS): Removed ugly cast, macro rewritten.
+       (FIELD_INNER_ACCESS_P, DECL_FIELD_FINAL_IUD, DECL_FIELD_FINAL_LIIC,
+       DECL_FIELD_FINAL_IERR, DECL_FIELD_FINAL_WFL): New macros.
+       (LOCAL_FINAL): Rewritten.
+       (LOCAL_FINAL_P, FINAL_VARIABLE_P, CLASS_FINAL_VARIABLE_P
+       MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC): New macros.
+       (struct lang_decl): Fixed comments. Added `synthetic_ctor' and
+       `init_final' fields.
+       (struct lang_decl_var): Fixed leading comment. Added `am', `wfl',
+       `final_uid', `final_liic', `final_ierr' and `local_final' fields.
+       (TYPE_HAS_FINAL_VARIABLE): New macro.
+       (struct lang_type): Added `afv' field.
+       * parse.y (check_static_final_variable_assignment_flag): New function.
+       (reset_static_final_variable_assignment_flag): Likewise.
+       (check_final_variable_local_assignment_flag): Likewise.
+       (reset_final_variable_local_assignment_flag): Likewise.
+       (check_final_variable_indirect_assignment): Likewise.
+       (check_final_variable_global_assignment_flag): Likewise.
+       (add_inner_class_fields): Use LOCAL_FINAL_P.
+       (register_fields): Handle local finals and final variables.
+       (craft_constructor): Set DECL_FUNCTION_SYNTHETIC_CTOR.
+       (declare_local_variables): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
+       (source_start_java_method): Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC
+       on local finals.
+       (java_complete_expand_methods): Loop to set
+       TYPE_HAS_FINAL_VARIABLE. Call
+       `reset_final_variable_local_assignment_flag' and 
+       `check_final_variable_local_assignment_flag' accordingly before
+       and after constructor expansion. Call
+       `reset_static_final_variable_assignment_flag'
+       before expanding <clinit> and after call 
+       `check_static_final_variable_assignment_flag' if the
+       current_class isn't an interface. After all methods have been
+       expanded, call `check_final_variable_global_assignment_flag' and
+       `check_static_final_variable_assignment_flag' if the current class
+       is an interface. 
+       (maybe_yank_clinit): Fixed typo in comment.
+       (build_outer_field_access_methods): Removed old sanity check. Use
+       FIELD_INNER_ACCESS_P. Call MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC.
+       Don't create access methods for finals.
+       (resolve_field_access): Use `CLASS_FINAL_VARIABLE_P'.
+       (java_complete_tree): Likewise. Reset DECL_FIELD_FINAL_IUD if
+       existing DECL_INIT has been processed. 
+       (java_complete_lhs): Likewise.
+       (check_final_assignment): Filter input on `lvalue''s TREE_CODE.
+       Test for COMPONENT_REF to get to the FIELD_DECL. Implemented new
+       logic.
+       (patch_assignment): Use LOCAL_FINAL_P.
+       (fold_constant_for_init): Reset DECL_FIELD_FINAL_IUD if
+       DECL_INITIAL is nullified.
+       Fixes gcj/163.
+
 2000-10-13  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * Make-lang.in (parse.c, parse-scan.c): Create atomically.
@@ -403,6 +476,20 @@ Thu Nov 23 02:19:14 2000  J"orn Rennecke <amylaar@redhat.com>
        fields.
        * lex.h (java_lexer): Added out_buffer, out_first, out_last.
 
+2000-10-09  Alexandre Petit-Bianco  <apbianco@cygnus.com>
+
+       * parse.y (pop_current_osb): New function.
+       (array_type:): Use `dims:', changed actions
+       accordingly. Suggested by Anthony Green.
+       (array_creation_expression:): Used pop_current_osb.
+       (cast_expression:): Likewise.
+       (search_applicable_method_list): Fixed indentation.
+
+2000-10-08  Anthony Green  <green@redhat.com>
+
+       * parse.y (array_type_literal): Remove production.
+       (type_literals): Refer to array_type, not array_type_literal.
+
 2000-10-07  Alexandre Petit-Bianco  <apbianco@cygnus.com>
 
        Patch contributed by Corey Minyard.
index f75e4fb4799e8b89fcc4e526ae60fb2a7ed4d4f7..7de0e183b3a433acb9bebe4a59e2697681473941 100644 (file)
@@ -356,8 +356,7 @@ done_alternative (after, current)
   start_current_locals = current.save_start_current_locals; \
 }
 
-/* Check for (un)initialized local variables in EXP.
-*/
+/* Check for (un)initialized local variables in EXP.  */
 
 static void
 check_init (exp, before)
@@ -387,14 +386,14 @@ check_init (exp, before)
       /* We're interested in variable declaration and parameter
          declaration when they're declared with the `final' modifier. */
       if ((TREE_CODE (tmp) == VAR_DECL && ! FIELD_STATIC (tmp))
-         || (TREE_CODE (tmp) == PARM_DECL && LOCAL_FINAL (tmp)))
+         || (TREE_CODE (tmp) == PARM_DECL && LOCAL_FINAL_P (tmp)))
        {
          int index;
          check_init (TREE_OPERAND (exp, 1), before);
          index = DECL_BIT_INDEX (tmp);
          /* A final local already assigned or a final parameter
              assigned must be reported as errors */
-         if (LOCAL_FINAL (tmp) 
+         if (LOCAL_FINAL_P (tmp)
              && (index == -1 || TREE_CODE (tmp) == PARM_DECL))
            parse_error_context (wfl, "Can't assign here a value to the `final' variable `%s'", IDENTIFIER_POINTER (DECL_NAME (tmp)));
 
index 04e0734054b572a955e8444e62a73d0c39795fc2..0ed71700bde8ee5ffe4e2871ec10e96de8306526 100644 (file)
@@ -127,8 +127,7 @@ push_jvm_slot (index, decl)
   /* Now link the decl into the decl_map. */
   if (DECL_LANG_SPECIFIC (decl) == NULL)
     {
-      DECL_LANG_SPECIFIC (decl)
-       = (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl_var));
+      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
       DECL_LOCAL_START_PC (decl) = 0;
       DECL_LOCAL_END_PC (decl) = DECL_CODE_LENGTH (current_function_decl);
       DECL_LOCAL_SLOT_NUMBER (decl) = index;
@@ -1620,8 +1619,7 @@ give_name_to_locals (jcf)
             comments for expr.c:maybe_adjust_start_pc. */
          start_pc = maybe_adjust_start_pc (jcf, code_offset, start_pc, slot);
 
-         DECL_LANG_SPECIFIC (decl)
-           = (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl_var));
+         MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
          DECL_LOCAL_SLOT_NUMBER (decl) = slot;
          DECL_LOCAL_START_PC (decl) = start_pc;
 #if 0
@@ -1901,7 +1899,8 @@ lang_mark_tree (t)
       ggc_mark_tree (li->utf8_ref);
     }
   else if (TREE_CODE (t) == VAR_DECL
-          || TREE_CODE (t) == PARM_DECL)
+          || TREE_CODE (t) == PARM_DECL
+          || TREE_CODE (t) == FIELD_DECL)
     {
       struct lang_decl_var *ldv = 
        ((struct lang_decl_var *) DECL_LANG_SPECIFIC (t));
@@ -1909,6 +1908,8 @@ lang_mark_tree (t)
        {
          ggc_mark (ldv);
          ggc_mark_tree (ldv->slot_chain);
+         ggc_mark_tree (ldv->am);
+         ggc_mark_tree (ldv->wfl);
        }
     }
   else if (TREE_CODE (t) == FUNCTION_DECL)
index fa898f8a68e4d7cd0b87c66b542c1dcb35bbcbc3..f9b47ddb082a2cec2b86bc34e9ecd420a2121640 100644 (file)
@@ -88,7 +88,6 @@ struct JCF;
    3: METHOD_FINAL (in FUNCTION_DECL)
       FIELD_FINAL (in FIELD_DECL)
       CLASS_FINAL (in TYPE_DECL)
-      LOCAL_FINAL (in VAR_DECL)
    4: METHOD_SYNCHRONIZED (in FUNCTION_DECL).
       LABEL_IN_SUBR (in LABEL_DECL)
       CLASS_INTERFACE (in TYPE_DECL)
@@ -701,11 +700,12 @@ struct lang_identifier
    is excluded, because sometimes created as a parameter before the
    function decl exists. */
 #define DECL_FUNCTION_NAP(DECL) (DECL_LANG_SPECIFIC(DECL)->nap)
-
-/* For a FIELD_DECL, holds the name of the access method used to
-   read/write the content of the field from an inner class. 
-   The cast is ugly. FIXME  */
-#define FIELD_INNER_ACCESS(DECL)       ((tree)DECL_LANG_SPECIFIC (DECL))
+/* True if DECL is a synthetic ctor.  */
+#define DECL_FUNCTION_SYNTHETIC_CTOR(DECL) \
+  (DECL_LANG_SPECIFIC(DECL)->synthetic_ctor)
+/* True if DECL initializes all its finals */
+#define DECL_FUNCTION_ALL_FINAL_INITIALIZED(DECL) \
+  (DECL_LANG_SPECIFIC(DECL)->init_final)
 
 /* True when DECL aliases an outer context local variable.  */
 #define FIELD_LOCAL_ALIAS(DECL) DECL_LANG_FLAG_6 (DECL)
@@ -779,6 +779,46 @@ struct lang_identifier
    slot_number in decl_map. */
 #define DECL_LOCAL_SLOT_CHAIN(NODE) \
   (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->slot_chain)
+/* For a FIELD_DECL, holds the name of the access method. Used to
+   read/write the content of the field from an inner class.  */
+#define FIELD_INNER_ACCESS(DECL) \
+  (((struct lang_decl_var*)DECL_LANG_SPECIFIC(DECL))->am)
+/* Safely tests whether FIELD_INNER_ACCESS exists or not. */
+#define FIELD_INNER_ACCESS_P(DECL) \
+  DECL_LANG_SPECIFIC (DECL) && FIELD_INNER_ACCESS (DECL)
+/* True if a final variable was initialized upon its declaration. */
+#define DECL_FIELD_FINAL_IUD(NODE) \
+  (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->final_iud)
+/* Set to true if a final variable is seen locally initialized on a
+   ctor. */
+#define DECL_FIELD_FINAL_LIIC(NODE) \
+  (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->final_liic)
+/* Set to true if an initialization error was already found with this
+   final variable. */
+#define DECL_FIELD_FINAL_IERR(NODE) \
+  (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->final_ierr)
+/* The original WFL of a final variable. */
+#define DECL_FIELD_FINAL_WFL(NODE) \
+  (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->wfl)
+/* True if NODE is a local final (as opposed to a final variable.)
+   This macro accesses the flag to read or set it. */
+#define LOCAL_FINAL(NODE) \
+  (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->local_final)
+/* True if NODE is a local final. */
+#define LOCAL_FINAL_P(NODE) (DECL_LANG_SPECIFIC (NODE) && LOCAL_FINAL (NODE))
+/* True if NODE is a final variable */
+#define FINAL_VARIABLE_P(NODE) (FIELD_FINAL (NODE) && !FIELD_STATIC (NODE))
+/* True if NODE is a class final variable */
+#define CLASS_FINAL_VARIABLE_P(NODE) \
+  (FIELD_FINAL (NODE) && FIELD_STATIC (NODE))
+/* Create a DECL_LANG_SPECIFIC if necessary. */
+#define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T)                 \
+  if (DECL_LANG_SPECIFIC (T) == NULL)                          \
+    {                                                          \
+      DECL_LANG_SPECIFIC ((T))                                 \
+       = ((struct lang_decl *)                                 \
+          ggc_alloc_cleared (sizeof (struct lang_decl_var)));  \
+    }
 
 /* For a local VAR_DECL, holds the index into a words bitstring that
    specifies if this decl is definitively assigned.
@@ -798,15 +838,15 @@ struct lang_decl
   tree throws_list;            /* Exception specified by `throws' */
   tree function_decl_body;     /* Hold all function's statements */
   tree called_constructor;     /* When decl is a constructor, the
-                                  list of other constructor it calls. */
+                                  list of other constructor it calls */
   struct hash_table init_test_table;
-                               /* Class initialization test variables.  */
+                               /* Class initialization test variables  */
   tree inner_access;           /* The identifier of the access method
                                   used for invocation from inner classes */
   int nap;                     /* Number of artificial parameters */
-
-  int native : 1;              /* Nonzero if this is a native
-                                  method.  */
+  int native : 1;              /* Nonzero if this is a native method  */
+  int synthetic_ctor : 1;      /* Nonzero if this is a synthetic ctor */
+  int init_final : 1;          /* Nonzero all finals are initialized */
 };
 
 /* init_test_table hash table entry structure.  */
@@ -816,13 +856,20 @@ struct init_test_hash_entry
   tree init_test_decl;
 };
 
-/* DECL_LANG_SPECIFIC for VAR_DECL and PARM_DECL. */
+/* DECL_LANG_SPECIFIC for VAR_DECL, PARM_DECL and sometimes FIELD_DECL
+   (access methods on outer class fields) and final fields. */
 struct lang_decl_var
 {
   int slot_number;
   int start_pc;
   int end_pc;
   tree slot_chain;
+  tree am;                     /* Access method for this field (1.1) */
+  tree wfl;                    /* Original wfl */
+  int final_iud : 1;           /* Final initialized upon declaration */
+  int final_liic : 1;          /* Final locally initialized in ctors */
+  int final_ierr : 1;          /* Initialization error already detected */
+  int local_final : 1;         /* True if the decl is a local final */
 };
 
 /* Macro to access fields in `struct lang_type'.  */
@@ -847,6 +894,7 @@ struct lang_decl_var
 #define TYPE_DOT_CLASS(T)        (TYPE_LANG_SPECIFIC(T)->dot_class)
 #define TYPE_PRIVATE_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->pic)
 #define TYPE_PROTECTED_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->poic)
+#define TYPE_HAS_FINAL_VARIABLE(T) (TYPE_LANG_SPECIFIC(T)->afv)
 
 struct lang_type
 {
@@ -863,6 +911,7 @@ struct lang_type
                                   <non_primitive_type>.class */
   unsigned pic:1;              /* Private Inner Class. */
   unsigned poic:1;             /* Protected Inner Class. */
+  unsigned afv:1;              /* Has final variables */
 };
 
 #ifdef JAVA_USE_HANDLES
@@ -1110,7 +1159,6 @@ struct rtx_def * java_lang_expand_expr PARAMS ((tree, rtx, enum machine_mode,
 #define FIELD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
 #define FIELD_VOLATILE(DECL) DECL_LANG_FLAG_4 (DECL)
 #define FIELD_TRANSIENT(DECL) DECL_LANG_FLAG_5 (DECL)
-#define LOCAL_FINAL(DECL) FIELD_FINAL(DECL)
 
 /* Access flags etc for a class (a TYPE_DECL): */
 
index e08b37d54570f94d139654da396414249279c0b2..b66db937245d5f50ae407adb1db80579874094e6 100644 (file)
@@ -57,7 +57,7 @@ char *jcf_write_base_directory = NULL;
 /* Add a 1-byte instruction/operand I to bytecode.data,
    assuming space has already been RESERVE'd. */
 
-#define OP1(I) (*state->bytecode.ptr++ = (I), CHECK_OP(state))
+#define OP1(I) (state->last_bc = *state->bytecode.ptr++ = (I), CHECK_OP(state))
 
 /* Like OP1, but I is a 2-byte big endian integer. */
 
@@ -131,13 +131,14 @@ struct jcf_block
 
   int linenumber;
 
-  /* After finish_jcf_block is called, The actual instructions contained in this block.
-     Before than NULL, and the instructions are in state->bytecode. */
+  /* After finish_jcf_block is called, The actual instructions
+     contained in this block.  Before than NULL, and the instructions
+     are in state->bytecode. */
   union {
     struct chunk *chunk;
 
     /* If pc==PENDING_CLEANUP_PC, start_label is the start of the region
-       coveed by the cleanup. */
+       covered by the cleanup. */
     struct jcf_block *start_label;
   } v;
 
@@ -272,8 +273,10 @@ struct jcf_partial
   /* If non-NULL, use this for the return value. */
   tree return_value_decl;
 
-  /* Information about the current switch statemenet. */
+  /* Information about the current switch statement. */
   struct jcf_switch_state *sw_state;
+
+  enum java_opcode last_bc;    /* The last emitted bytecode */
 };
 
 static void generate_bytecode_insns PARAMS ((tree, int, struct jcf_partial *));
@@ -2158,7 +2161,16 @@ generate_bytecode_insns (exp, target, state)
        tree src = TREE_OPERAND (exp, 0);
        tree src_type = TREE_TYPE (src);
        tree dst_type = TREE_TYPE (exp);
-       generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
+       /* Detect the situation of compiling an empty synchronized
+          block.  A nop should be emitted in order to produce
+          verifiable bytecode. */
+       if (exp == empty_stmt_node
+           && state->last_bc == OPCODE_monitorenter
+           && state->labeled_blocks
+           && state->labeled_blocks->pc == PENDING_CLEANUP_PC)
+         OP1 (OPCODE_nop);
+       else
+         generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
        if (target == IGNORE_TARGET || src_type == dst_type)
          break;
        if (TREE_CODE (dst_type) == POINTER_TYPE)
index d89ace421cc9e475f8315b924c6b2f4434b5a8db..249dcfd9e5ee31645df9598f6db634a14d348ed1 100644 (file)
@@ -102,6 +102,12 @@ static int process_imports PARAMS ((void));
 static void read_import_dir PARAMS ((tree));
 static int find_in_imports_on_demand PARAMS ((tree));
 static void find_in_imports PARAMS ((tree));
+static void check_static_final_variable_assignment_flag PARAMS ((tree));
+static void reset_static_final_variable_assignment_flag PARAMS ((tree));
+static void check_final_variable_local_assignment_flag PARAMS ((tree, tree));
+static void reset_final_variable_local_assignment_flag PARAMS ((tree));
+static int  check_final_variable_indirect_assignment PARAMS ((tree));
+static void check_final_variable_global_assignment_flag PARAMS ((tree));
 static void check_inner_class_access PARAMS ((tree, tree, tree));
 static int check_pkg_class_access PARAMS ((tree, tree));
 static void register_package PARAMS ((tree));
@@ -287,6 +293,7 @@ static void java_parser_context_pop_initialized_field PARAMS ((void));
 static tree reorder_static_initialized PARAMS ((tree));
 static void java_parser_context_suspend PARAMS ((void));
 static void java_parser_context_resume PARAMS ((void));
+static int pop_current_osb PARAMS ((struct parser_ctxt *));
 
 /* JDK 1.1 work. FIXME */
 
@@ -580,7 +587,7 @@ static tree currently_caught_type_list;
                        BOOLEAN_TK INTEGRAL_TK FP_TK
 
 /* Added or modified JDK 1.1 rule types  */
-%type   <node>         type_literals array_type_literal
+%type   <node>         type_literals
 
 %%
 /* 19.2 Production from 2.3: The Syntactic Grammar  */
@@ -652,19 +659,23 @@ interface_type:
 ;
 
 array_type:
-       primitive_type OSB_TK CSB_TK
+       primitive_type dims
                { 
-                 $$ = build_java_array_type ($1, -1);
-                 CLASS_LOADED_P ($$) = 1;
+                 int osb = pop_current_osb (ctxp);
+                 tree t = build_java_array_type (($1), -1);
+                 CLASS_LOADED_P (t) = 1;
+                 while (--osb)
+                   t = build_unresolved_array_type (t);
+                 $$ = t;
+               }
+|      name dims
+               { 
+                 int osb = pop_current_osb (ctxp);
+                 tree t = $1;
+                 while (osb--)
+                   t = build_unresolved_array_type (t);
+                 $$ = t;
                }
-|      name OSB_TK CSB_TK
-               { $$ = build_unresolved_array_type ($1); }
-|      array_type OSB_TK CSB_TK
-               { $$ = build_unresolved_array_type ($1); }
-|      primitive_type OSB_TK error
-               {RULE ("']' expected"); RECOVER;}
-|      array_type OSB_TK error
-               {RULE ("']' expected"); RECOVER;}
 ;
 
 /* 19.5 Productions from 6: Names  */
@@ -1935,28 +1946,10 @@ primary_no_new_array:
                {yyerror ("'class' expected" ); RECOVER;}
 ;
 
-/* Added, JDK1.1 type literals. We can't use `type' directly, so we
-   broke the rule down a bit. */
-
-array_type_literal:
-       primitive_type OSB_TK CSB_TK
-               { 
-                 $$ = build_java_array_type ($1, -1);
-                 CLASS_LOADED_P ($$) = 1;
-               }
-|      name OSB_TK CSB_TK
-               { $$ = build_unresolved_array_type ($1); }
-/* This triggers two reduce/reduce conflict between array_type_literal and
-   dims. FIXME.
-|      array_type OSB_TK CSB_TK
-               { $$ = build_unresolved_array_type ($1); }
-*/
-;
-
 type_literals:
        name DOT_TK CLASS_TK
                { $$ = build_incomplete_class_ref ($2.location, $1); }
-|      array_type_literal DOT_TK CLASS_TK
+|      array_type DOT_TK CLASS_TK
                { $$ = build_incomplete_class_ref ($2.location, $1); }
 |      primitive_type DOT_TK CLASS_TK
                { $$ = build_class_ref ($1); }
@@ -2085,15 +2078,16 @@ array_creation_expression:
 |      NEW_TK class_or_interface_type dim_exprs
                { $$ = build_newarray_node ($2, $3, 0); }
 |      NEW_TK primitive_type dim_exprs dims
-               { $$ = build_newarray_node ($2, $3, CURRENT_OSB (ctxp));}
+               { $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));}
 |      NEW_TK class_or_interface_type dim_exprs dims
-               { $$ = build_newarray_node ($2, $3, CURRENT_OSB (ctxp));}
+               { $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));}
         /* Added, JDK1.1 anonymous array. Initial documentation rule
            modified */
 |      NEW_TK class_or_interface_type dims array_initializer
                {
                  char *sig;
-                 while (CURRENT_OSB (ctxp)--)
+                 int osb = pop_current_osb (ctxp);
+                 while (osb--)
                    obstack_1grow (&temporary_obstack, '[');
                  sig = obstack_finish (&temporary_obstack);
                  $$ = build (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE,
@@ -2101,8 +2095,9 @@ array_creation_expression:
                }
 |      NEW_TK primitive_type dims array_initializer
                { 
+                 int osb = pop_current_osb (ctxp);
                  tree type = $2;
-                 while (CURRENT_OSB (ctxp)--)
+                 while (osb--)
                    type = build_java_array_type (type, -1);
                  $$ = build (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE, 
                              build_pointer_type (type), NULL_TREE, $4);
@@ -2325,9 +2320,9 @@ cast_expression:          /* Error handling here is potentially weak */
        OP_TK primitive_type dims CP_TK unary_expression
                { 
                  tree type = $2;
-                 while (CURRENT_OSB (ctxp)--)
+                 int osb = pop_current_osb (ctxp);
+                 while (osb--)
                    type = build_java_array_type (type, -1);
-                 ctxp->osb_depth--;
                  $$ = build_cast ($1.location, type, $5); 
                }
 |      OP_TK primitive_type CP_TK unary_expression
@@ -2337,9 +2332,9 @@ cast_expression:          /* Error handling here is potentially weak */
 |      OP_TK name dims CP_TK unary_expression_not_plus_minus
                { 
                  const char *ptr;
-                 while (CURRENT_OSB (ctxp)--)
+                 int osb = pop_current_osb (ctxp); 
+                 while (osb--)
                    obstack_1grow (&temporary_obstack, '[');
-                 ctxp->osb_depth--;
                  obstack_grow0 (&temporary_obstack, 
                                 IDENTIFIER_POINTER (EXPR_WFL_NODE ($2)),
                                 IDENTIFIER_LENGTH (EXPR_WFL_NODE ($2)));
@@ -2593,6 +2588,25 @@ constant_expression:
 ;
 
 %%
+
+/* Helper function to retrieve an OSB count. Should be used when the
+   `dims:' rule is being used.  */
+
+static int
+pop_current_osb (ctxp)
+     struct parser_ctxt *ctxp;
+{
+  int to_return;
+
+  if (ctxp->osb_depth < 0)
+    fatal ("osb stack underflow");
+  
+  to_return = CURRENT_OSB (ctxp);
+  ctxp->osb_depth--;
+  
+  return to_return;
+}
+
 \f
 
 /* This section of the code deal with save/restoring parser contexts.
@@ -3952,7 +3966,7 @@ add_inner_class_fields (class_decl, fct_decl)
          tree wfl, init, list;
          
          /* Avoid non final arguments. */
-         if (!LOCAL_FINAL (decl))
+         if (!LOCAL_FINAL_P (decl))
            continue;
          
          MANGLE_OUTER_LOCAL_VARIABLE_NAME (name, DECL_NAME (decl));
@@ -4185,11 +4199,29 @@ register_fields (flags, type, variable_list)
       field_decl = add_field (class_type, current_name, real_type, flags);
       CHECK_DEPRECATED (field_decl);
 
-      /* If the couple initializer/initialized is marked ARG_FINAL_P, we
-        mark the created field FIELD_LOCAL_ALIAS, so that we can 
-        hide parameters to this inner class finit$ and constructors. */
+      /* If the field denotes a final instance variable, then we
+        allocate a LANG_DECL_SPECIFIC part to keep track of its
+        initialization. We also mark whether the field was
+        initialized upon it's declaration. We don't do that if the
+        created field is an alias to a final local. */
+      if (!ARG_FINAL_P (current) && (flags & ACC_FINAL))
+       {
+         MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (field_decl);
+         DECL_FIELD_FINAL_WFL (field_decl) = cl;
+         if ((flags & ACC_STATIC) && init)
+           DECL_FIELD_FINAL_IUD (field_decl) = 1;
+       }
+
+      /* If the couple initializer/initialized is marked ARG_FINAL_P,
+        we mark the created field FIELD_LOCAL_ALIAS, so that we can
+        hide parameters to this inner class finit$ and
+        constructors. It also means that the field isn't final per
+        say. */
       if (ARG_FINAL_P (current))
-       FIELD_LOCAL_ALIAS (field_decl) = 1;
+       {
+         FIELD_LOCAL_ALIAS (field_decl) = 1;
+         FIELD_FINAL (field_decl) = 0;
+       }
       
       /* Check if we must chain. */
       if (must_chain)
@@ -5182,7 +5214,7 @@ craft_constructor (class_decl, args)
   fix_method_argument_names (parm, decl);
   /* Now, mark the artificial parameters. */
   DECL_FUNCTION_NAP (decl) = artificial;
-  DECL_CONSTRUCTOR_P (decl) = 1;
+  DECL_FUNCTION_SYNTHETIC_CTOR (decl) = DECL_CONSTRUCTOR_P (decl) = 1;
 }
 
 
@@ -7039,6 +7071,7 @@ declare_local_variables (modifier, type, vlist)
       /* Never layout this decl. This will be done when its scope
         will be entered */
       decl = build_decl (VAR_DECL, name, real_type);
+      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
       LOCAL_FINAL (decl) = final_p;
       BLOCK_CHAIN_DECL (decl);
       
@@ -7116,7 +7149,10 @@ source_start_java_method (fndecl)
       /* Remember if a local variable was declared final (via its
          TREE_LIST of type/name.) Set LOCAL_FINAL accordingly. */
       if (ARG_FINAL_P (tem))
-       LOCAL_FINAL (parm_decl) = 1;
+       {
+         MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (parm_decl);
+         LOCAL_FINAL (parm_decl) = 1;
+       }
 
       BLOCK_CHAIN_DECL (parm_decl);
     }
@@ -7164,7 +7200,7 @@ static void
 end_artificial_method_body (mdecl)
      tree mdecl;
 {
-  BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_block ();
+  BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_blcok ();
   exit_block ();
 }
 
@@ -7472,6 +7508,14 @@ java_complete_expand_methods (class_decl)
 
   current_class = TREE_TYPE (class_decl);
 
+  /* Find whether the class has final variables */
+  for (decl = TYPE_FIELDS (current_class); decl; decl = TREE_CHAIN (decl))
+    if (FIELD_FINAL (decl))
+      {
+       TYPE_HAS_FINAL_VARIABLE (current_class) = 1;
+       break;
+      }
+
   /* Initialize a new constant pool */
   init_outgoing_cpool ();
 
@@ -7504,7 +7548,15 @@ java_complete_expand_methods (class_decl)
       if (no_body)
        restore_line_number_status (1);
 
+      /* Reset the final local variable assignment flags */
+      if (TYPE_HAS_FINAL_VARIABLE (current_class))
+       reset_final_variable_local_assignment_flag (current_class);
+
       java_complete_expand_method (decl);
+
+      /* Check for missed out final variable assignment */
+      if (TYPE_HAS_FINAL_VARIABLE (current_class))
+       check_final_variable_local_assignment_flag (current_class, decl);
       
       if (no_body)
        restore_line_number_status (0);
@@ -7532,10 +7584,17 @@ java_complete_expand_methods (class_decl)
   /* If there is indeed a <clinit>, fully expand it now */
   if (clinit)
     {
+      /* Reset the final local variable assignment flags */
+      if (TYPE_HAS_FINAL_VARIABLE (current_class))
+       reset_static_final_variable_assignment_flag (current_class);
       /* Prevent the use of `this' inside <clinit> */
       ctxp->explicit_constructor_p = 1;
       java_complete_expand_method (clinit);
       ctxp->explicit_constructor_p = 0;
+      /* Check for missed out static final variable assignment */
+      if (TYPE_HAS_FINAL_VARIABLE (current_class)
+         && !CLASS_INTERFACE (class_decl))
+       check_static_final_variable_assignment_flag (current_class);
     }
   
   /* We might have generated a class$ that we now want to expand */
@@ -7550,6 +7609,15 @@ java_complete_expand_methods (class_decl)
          && verify_constructor_circularity (decl, decl))
        break;
 
+  /* Final check on the initialization of final variables. */
+  if (TYPE_HAS_FINAL_VARIABLE (current_class))
+    {
+      check_final_variable_global_assignment_flag (current_class);
+      /* If we have an interface, check for uninitialized fields. */
+      if (CLASS_INTERFACE (class_decl))
+       check_static_final_variable_assignment_flag (current_class);
+    }
+
   /* Save the constant pool. We'll need to restore it later. */
   TYPE_CPOOL (current_class) = outgoing_cpool;
 }
@@ -7690,7 +7758,7 @@ maybe_yank_clinit (mdecl)
        continue;
 
       /* Anything that isn't String or a basic type is ruled out -- or
-        if we now how to deal with it (when doing things natively) we
+        if we know how to deal with it (when doing things natively) we
         should generated an empty <clinit> so that SUID are computed
         correctly. */
       if (! JSTRING_TYPE_P (TREE_TYPE (current))
@@ -8045,14 +8113,11 @@ build_outer_field_access_methods (decl)
 {
   tree id, args, stmt, mdecl;
   
-  /* Check point, to be removed. FIXME */
-  if (FIELD_INNER_ACCESS (decl) 
-      && TREE_CODE (FIELD_INNER_ACCESS (decl)) != IDENTIFIER_NODE)
-    abort ();
-
-  if (FIELD_INNER_ACCESS (decl))
+  if (FIELD_INNER_ACCESS_P (decl))
     return FIELD_INNER_ACCESS (decl);
 
+  MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
   /* Create the identifier and a function named after it. */
   id = build_new_access_id ();
 
@@ -8070,17 +8135,21 @@ build_outer_field_access_methods (decl)
                                           TREE_TYPE (decl), id, args, stmt);
   DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
 
-  /* Create the write access method */
-  args = build_tree_list (inst_id, build_pointer_type (DECL_CONTEXT (decl)));
-  TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
-  TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
-  stmt = make_qualified_primary (build_wfl_node (inst_id),
-                                build_wfl_node (DECL_NAME (decl)), 0);
-  stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
-                                           build_wfl_node (wpv_id)));
-
-  mdecl = build_outer_field_access_method (DECL_CONTEXT (decl), 
-                                          TREE_TYPE (decl), id, args, stmt);
+  /* Create the write access method. No write access for final variable */
+  if (!FIELD_FINAL (decl))
+    {
+      args = build_tree_list (inst_id, 
+                             build_pointer_type (DECL_CONTEXT (decl)));
+      TREE_CHAIN (args) = build_tree_list (wpv_id, TREE_TYPE (decl));
+      TREE_CHAIN (TREE_CHAIN (args)) = end_params_node;
+      stmt = make_qualified_primary (build_wfl_node (inst_id),
+                                    build_wfl_node (DECL_NAME (decl)), 0);
+      stmt = build_return (0, build_assignment (ASSIGN_TK, 0, stmt,
+                                               build_wfl_node (wpv_id)));
+      mdecl = build_outer_field_access_method (DECL_CONTEXT (decl), 
+                                              TREE_TYPE (decl), id, 
+                                              args, stmt);
+    }
   DECL_FUNCTION_ACCESS_DECL (mdecl) = decl;
 
   /* Return the access name */
@@ -8986,7 +9055,7 @@ resolve_field_access (qual_wfl, field_decl, field_type)
       if (!type_found)
        type_found = DECL_CONTEXT (decl);
       is_static = JDECL_P (decl) && FIELD_STATIC (decl);
-      if (FIELD_FINAL (decl) && FIELD_STATIC (decl)
+      if (CLASS_FINAL_VARIABLE_P (decl)
          && JPRIMITIVE_TYPE_P (TREE_TYPE (decl))
          && DECL_INITIAL (decl))
        {
@@ -10587,7 +10656,7 @@ search_applicable_methods_list (lc, method, name, arglist, list, all_list)
       else if (!lc && (DECL_CONSTRUCTOR_P (method) 
                       || (GET_METHOD_NAME (method) != name)))
        continue;
-         
+
       if (argument_types_convertible (method, arglist))
        {
          /* Retain accessible methods only */
@@ -10996,7 +11065,7 @@ java_complete_tree (node)
      tree node;
 {
   node = java_complete_lhs (node);
-  if (JDECL_P (node) && FIELD_STATIC (node) && FIELD_FINAL (node) 
+  if (JDECL_P (node) && CLASS_FINAL_VARIABLE_P (node)
       && DECL_INITIAL (node) != NULL_TREE
       && !flag_emit_xref)
     {
@@ -11015,6 +11084,8 @@ java_complete_tree (node)
          else
            return value;
        }
+      else
+        DECL_FIELD_FINAL_IUD (node) = 0;
     }
   return node;
 }
@@ -11505,6 +11576,8 @@ java_complete_lhs (node)
            }
          if (! flag_emit_class_files)
            DECL_INITIAL (nn) = NULL_TREE;
+         if (CLASS_FINAL_VARIABLE_P (nn))
+           DECL_FIELD_FINAL_IUD (nn) = 0;
        }
       wfl_op2 = TREE_OPERAND (node, 1);
 
@@ -12062,6 +12135,214 @@ print_int_node (node)
   return buffer;
 }
 
+\f
+
+/* This section of the code handle assignment check with FINAL
+   variables.  */
+
+static void
+reset_static_final_variable_assignment_flag (class)
+     tree class;
+{
+  tree field;
+  for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+    if (CLASS_FINAL_VARIABLE_P (field))
+      DECL_FIELD_FINAL_LIIC (field) = 0;
+}
+
+/* Figure whether all final static variable have been initialized.  */
+
+static void
+check_static_final_variable_assignment_flag (class)
+     tree class;
+{
+  tree field;
+
+  for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+    if (CLASS_FINAL_VARIABLE_P (field)
+       && !DECL_FIELD_FINAL_IUD (field) && !DECL_FIELD_FINAL_LIIC (field))
+      parse_error_context
+       (DECL_FIELD_FINAL_WFL (field),
+        "Blank static final variable `%s' may not have be initialized",
+        IDENTIFIER_POINTER (DECL_NAME (field)));
+}
+
+/* This function marks all final variable locally unassigned.  */
+
+static void
+reset_final_variable_local_assignment_flag (class)
+     tree class;
+{
+  tree field;
+  for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+    if (FINAL_VARIABLE_P (field))
+      DECL_FIELD_FINAL_LIIC (field) = 0;
+}
+
+/* Figure whether all final variables have beem initialized in MDECL
+   and mark MDECL accordingly.  */
+
+static void
+check_final_variable_local_assignment_flag (class, mdecl)
+     tree class;
+     tree mdecl;
+{
+  tree field;
+  int initialized = 0;
+  int non_initialized = 0; 
+
+  if (DECL_FUNCTION_SYNTHETIC_CTOR (mdecl))
+    return;
+
+  /* First find out whether all final variables or no final variable
+     are initialized in this ctor. We don't take into account final
+     variable that have been initialized upon declaration.  */
+  for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+    if (FINAL_VARIABLE_P (field) && !DECL_FIELD_FINAL_IUD (field))
+      {
+       if (DECL_FIELD_FINAL_LIIC (field))
+         initialized++;
+       else
+         non_initialized++;
+      }
+
+  /* There were no non initialized variable and no initialized variable.
+     This ctor is fine. */
+  if (!non_initialized && !initialized)
+    DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+  /* If no variables have been initialized, that fine. We'll check
+     later whether this ctor calls a constructor which initializes
+     them. We mark the ctor as not initializing all its finals. */
+  else if (initialized == 0)
+    DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 0;
+  /* If we have a mixed bag, then we have a problem. We need to report
+     all the variables we're not initializing.  */
+  else if (initialized && non_initialized)
+    {
+      DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 0;
+      for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+       if (FIELD_FINAL (field)
+           && !DECL_FIELD_FINAL_IUD (field) && !DECL_FIELD_FINAL_LIIC (field))
+         {
+           parse_error_context 
+             (lookup_cl (mdecl),
+              "Blank final variable `%s' may not have been initialized in this constructor",
+              IDENTIFIER_POINTER (DECL_NAME (field)));
+           DECL_FIELD_FINAL_IERR (field) = 1;
+         }
+    }
+  /* Otherwise we know this ctor is initializing all its final
+     variable. We mark it so. */
+  else
+    DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+}
+
+/* This function recurses in a simple what through STMT and stops when
+   it finds a constructor call. It then verifies that the called
+   constructor initialized its final properly. Return 1 upon success,
+   0 or -1 otherwise.  */
+
+static int
+check_final_variable_indirect_assignment (stmt)
+     tree stmt;
+{
+  int res;
+  switch (TREE_CODE (stmt))
+    {
+    case EXPR_WITH_FILE_LOCATION:
+      return check_final_variable_indirect_assignment (EXPR_WFL_NODE (stmt));
+    case COMPOUND_EXPR:
+      res = check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 0));
+      if (res)
+       return res;
+      return check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 1));
+    case SAVE_EXPR:
+      return check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 0));
+    case CALL_EXPR:
+      {
+       tree decl = TREE_OPERAND (stmt, 0);
+       tree fbody;
+
+       if (TREE_CODE (decl) != FUNCTION_DECL)
+         decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+       if (TREE_CODE (decl) != FUNCTION_DECL)
+         fatal ("Can't find FUNCTION_DECL in CALL_EXPR - check_final_variable_indirect_assignment");
+       if (DECL_FUNCTION_ALL_FINAL_INITIALIZED (decl))
+         return 1;
+       if (DECL_FINIT_P (decl) || DECL_CONTEXT (decl) != current_class)
+         return -1;
+       fbody = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (decl));
+       if (fbody == error_mark_node)
+         return -1;
+       fbody = BLOCK_EXPR_BODY (fbody);
+       return check_final_variable_indirect_assignment (fbody);
+      }
+    default:
+      break;
+    }
+  return 0;
+}
+
+/* This is the last chance to catch a final variable initialization
+   problem. This routine will report an error if a final variable was
+   never (globally) initialized and never reported as not having been
+   initialized properly. */
+
+static void
+check_final_variable_global_assignment_flag (class)
+     tree class;
+{
+  tree field, mdecl;
+  int nnctor = 0;
+
+  /* We go through all natural ctors and see whether they're
+     initializing all their final variables or not. */
+  current_function_decl = NULL_TREE; /* For the error report. */
+  for (mdecl = TYPE_METHODS (class); mdecl; mdecl = TREE_CHAIN (mdecl))
+    if (DECL_CONSTRUCTOR_P (mdecl) && ! DECL_FUNCTION_SYNTHETIC_CTOR (mdecl))
+      {
+       if (!DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl))
+         {
+           /* It doesn't. Maybe it calls a constructor that initializes
+              them.  find out. */
+           tree fbody = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl));
+           if (fbody == error_mark_node)
+             continue;
+           fbody = BLOCK_EXPR_BODY (fbody);
+           if (check_final_variable_indirect_assignment (fbody) == 1)
+             {
+               DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+               nnctor++;
+             }
+           else
+             parse_error_context
+               (lookup_cl (mdecl),
+                "Final variable initialization error in this constructor");
+         }
+       else
+         nnctor++;
+      }
+
+  /* Finally we catch final variables that never were initialized */
+  for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+    if (FINAL_VARIABLE_P (field)
+       /* If the field wasn't initialized upon declaration */
+       && !DECL_FIELD_FINAL_IUD (field)
+       /* There wasn't natural ctor in which the field could have been
+          initialized */
+       && !nnctor
+       /* If we never reported a problem with this field */
+       && !DECL_FIELD_FINAL_IERR (field))
+      {
+       current_function_decl = NULL;
+       parse_error_context
+         (DECL_FIELD_FINAL_WFL (field),
+          "Final variable `%s' hasn't been initialized upon its declaration",
+          IDENTIFIER_POINTER (DECL_NAME (field)));
+      }
+
+}
+
 /* Return 1 if an assignment to a FINAL is attempted in a non suitable
    context.  */
 
@@ -12069,27 +12350,52 @@ static int
 check_final_assignment (lvalue, wfl)
      tree lvalue, wfl;
 {
-  if (TREE_CODE (lvalue) == COMPOUND_EXPR 
+  if (TREE_CODE (lvalue) != COMPONENT_REF && !JDECL_P (lvalue))
+    return 0;
+
+  if (TREE_CODE (lvalue) == COMPONENT_REF
       && JDECL_P (TREE_OPERAND (lvalue, 1)))
     lvalue = TREE_OPERAND (lvalue, 1);
 
-  /* When generating class files, references to the `length' field
-     look a bit different.  */
-  if ((flag_emit_class_files
-       && TREE_CODE (lvalue) == COMPONENT_REF
-       && TYPE_ARRAY_P (TREE_TYPE (TREE_OPERAND (lvalue, 0)))
-       && FIELD_FINAL (TREE_OPERAND (lvalue, 1)))
-      || (TREE_CODE (lvalue) == FIELD_DECL
-         && FIELD_FINAL (lvalue)
-         && !DECL_CLINIT_P (current_function_decl)
-         && !DECL_FINIT_P (current_function_decl)))
+  if (!FIELD_FINAL (lvalue))
+    return 0;
+
+  /* Now the logic. We can modify a final VARIABLE:
+     1) in finit$, (its declaration was followed by an initialization,)
+     2) consistently in each natural ctor, if it wasn't initialized in
+        finit$ or once in <clinit>.  In any other cases, an error should be
+       reported. */
+  if (DECL_FINIT_P (current_function_decl))
     {
-      parse_error_context 
-        (wfl, "Can't assign a value to the final variable `%s'",
-        IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
-      return 1;
+      DECL_FIELD_FINAL_IUD (lvalue) = 1;
+      return 0;
     }
-  return 0;
+
+  if (!DECL_FUNCTION_SYNTHETIC_CTOR (current_function_decl)
+      /* Only if it wasn't given a value upon initialization */
+      && DECL_LANG_SPECIFIC (lvalue) && !DECL_FIELD_FINAL_IUD (lvalue)
+      /* If it was never assigned a value in this constructor */
+      && !DECL_FIELD_FINAL_LIIC (lvalue))
+    {
+      /* Turn the locally assigned flag on, it will be checked later
+        on to point out at discrepancies. */
+      DECL_FIELD_FINAL_LIIC (lvalue) = 1;
+      if (DECL_CLINIT_P (current_function_decl))
+       DECL_FIELD_FINAL_IUD (lvalue) = 1;
+      return 0;
+    }
+
+  /* Other problems should be reported right away. */
+  parse_error_context 
+    (wfl, "Can't %sassign a value to the final variable `%s'",
+     (FIELD_STATIC (lvalue) ? "re" : ""),
+     IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
+
+  /* Note that static field can be initialized once and only once. */
+  if (FIELD_STATIC (lvalue))
+    DECL_FIELD_FINAL_IERR (lvalue) = 1;
+
+  return 1;
 }
 
 /* Inline references to java.lang.PRIMTYPE.TYPE when accessed in
@@ -12297,7 +12603,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
   /* Final locals can be used as case values in switch
      statement. Prepare them for this eventuality. */
   if (TREE_CODE (lvalue) == VAR_DECL 
-      && LOCAL_FINAL (lvalue)
+      && LOCAL_FINAL_P (lvalue)
       && TREE_CONSTANT (new_rhs)
       && IDENTIFIER_LOCAL_VALUE (DECL_NAME (lvalue))
       && JINTEGRAL_TYPE_P (TREE_TYPE (lvalue))
@@ -14820,7 +15126,7 @@ patch_synchronized_statement (node, wfl_op1)
   tree expr = java_complete_tree (TREE_OPERAND (node, 0));
   tree block = TREE_OPERAND (node, 1);
 
-  tree enter, exit, expr_decl, assignment;
+  tree tmp, enter, exit, expr_decl, assignment;
 
   if (expr == error_mark_node)
     {
@@ -14828,6 +15134,10 @@ patch_synchronized_statement (node, wfl_op1)
       return expr;
     }
 
+  /* We might be trying to synchronize on a STRING_CST */
+  if ((tmp = patch_string (expr)))
+    expr = tmp;
+
   /* The TYPE of expr must be a reference type */
   if (!JREFERENCE_TYPE_P (TREE_TYPE (expr)))
     {
@@ -15265,6 +15575,8 @@ fold_constant_for_init (node, context)
       DECL_INITIAL (node) = NULL_TREE;
       val = fold_constant_for_init (val, node);
       DECL_INITIAL (node) = val;
+      if (!val && CLASS_FINAL_VARIABLE_P (node))
+       DECL_FIELD_FINAL_IUD (node) = 0;
       return val;
 
     case EXPR_WITH_FILE_LOCATION: