diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 69044f8506a..895f618eb24 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -235,6 +235,17 @@ Thu Nov 23 02:19:14 2000 J"orn Rennecke * verify.c (CHECK_PC_IN_RANGE): Cast result of stmt-expr to void. +2000-10-18 Alexandre Petit-Bianco + + * 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 * jvspec.c (lang_specific_driver): Recognize -MF and -MT. @@ -298,6 +309,68 @@ Thu Nov 23 02:19:14 2000 J"orn Rennecke * decl.c (init_decl_processing): Call init_class_processing before anything else. +2000-10-13 Alexandre Petit-Bianco + + * 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 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 * Make-lang.in (parse.c, parse-scan.c): Create atomically. @@ -403,6 +476,20 @@ Thu Nov 23 02:19:14 2000 J"orn Rennecke fields. * lex.h (java_lexer): Added out_buffer, out_first, out_last. +2000-10-09 Alexandre Petit-Bianco + + * 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 + + * parse.y (array_type_literal): Remove production. + (type_literals): Refer to array_type, not array_type_literal. + 2000-10-07 Alexandre Petit-Bianco Patch contributed by Corey Minyard. diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c index f75e4fb4799..7de0e183b3a 100644 --- a/gcc/java/check-init.c +++ b/gcc/java/check-init.c @@ -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))); diff --git a/gcc/java/decl.c b/gcc/java/decl.c index 04e0734054b..0ed71700bde 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -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) diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index fa898f8a68e..f9b47ddb082 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -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 .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): */ diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index e08b37d5457..b66db937245 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -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) diff --git a/gcc/java/parse.y b/gcc/java/parse.y index d89ace421cc..249dcfd9e5e 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -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 type_literals array_type_literal +%type 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; +} + /* 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 , 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 */ 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 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; } + + +/* 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 . 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: