[multiple changes]

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