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)
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)
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.
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. */
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'. */
#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
{
<non_primitive_type>.class */
unsigned pic:1; /* Private Inner Class. */
unsigned poic:1; /* Protected Inner Class. */
+ unsigned afv:1; /* Has final variables */
};
#ifdef JAVA_USE_HANDLES
#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): */
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));
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 */
BOOLEAN_TK INTEGRAL_TK FP_TK
/* Added or modified JDK 1.1 rule types */
-%type <node> type_literals array_type_literal
+%type <node> type_literals
%%
/* 19.2 Production from 2.3: The Syntactic Grammar */
;
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 */
{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); }
| 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,
}
| 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);
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
| 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)));
;
%%
+
+/* Helper function to retrieve an OSB count. Should be used when the
+ `dims:' rule is being used. */
+
+static int
+pop_current_osb (ctxp)
+ struct parser_ctxt *ctxp;
+{
+ int to_return;
+
+ if (ctxp->osb_depth < 0)
+ fatal ("osb stack underflow");
+
+ to_return = CURRENT_OSB (ctxp);
+ ctxp->osb_depth--;
+
+ return to_return;
+}
+
\f
/* This section of the code deal with save/restoring parser contexts.
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));
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)
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;
}
/* 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);
/* 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);
}
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 ();
}
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 ();
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);
/* If there is indeed a <clinit>, fully expand it now */
if (clinit)
{
+ /* Reset the final local variable assignment flags */
+ if (TYPE_HAS_FINAL_VARIABLE (current_class))
+ reset_static_final_variable_assignment_flag (current_class);
/* Prevent the use of `this' inside <clinit> */
ctxp->explicit_constructor_p = 1;
java_complete_expand_method (clinit);
ctxp->explicit_constructor_p = 0;
+ /* Check for missed out static final variable assignment */
+ if (TYPE_HAS_FINAL_VARIABLE (current_class)
+ && !CLASS_INTERFACE (class_decl))
+ check_static_final_variable_assignment_flag (current_class);
}
/* We might have generated a class$ that we now want to expand */
&& 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;
}
continue;
/* Anything that isn't String or a basic type is ruled out -- or
- if we now how to deal with it (when doing things natively) we
+ if we know how to deal with it (when doing things natively) we
should generated an empty <clinit> so that SUID are computed
correctly. */
if (! JSTRING_TYPE_P (TREE_TYPE (current))
{
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 ();
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 */
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))
{
else if (!lc && (DECL_CONSTRUCTOR_P (method)
|| (GET_METHOD_NAME (method) != name)))
continue;
-
+
if (argument_types_convertible (method, arglist))
{
/* Retain accessible methods only */
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)
{
else
return value;
}
+ else
+ DECL_FIELD_FINAL_IUD (node) = 0;
}
return 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);
return buffer;
}
+\f
+
+/* This section of the code handle assignment check with FINAL
+ variables. */
+
+static void
+reset_static_final_variable_assignment_flag (class)
+ tree class;
+{
+ tree field;
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (CLASS_FINAL_VARIABLE_P (field))
+ DECL_FIELD_FINAL_LIIC (field) = 0;
+}
+
+/* Figure whether all final static variable have been initialized. */
+
+static void
+check_static_final_variable_assignment_flag (class)
+ tree class;
+{
+ tree field;
+
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (CLASS_FINAL_VARIABLE_P (field)
+ && !DECL_FIELD_FINAL_IUD (field) && !DECL_FIELD_FINAL_LIIC (field))
+ parse_error_context
+ (DECL_FIELD_FINAL_WFL (field),
+ "Blank static final variable `%s' may not have be initialized",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+}
+
+/* This function marks all final variable locally unassigned. */
+
+static void
+reset_final_variable_local_assignment_flag (class)
+ tree class;
+{
+ tree field;
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FINAL_VARIABLE_P (field))
+ DECL_FIELD_FINAL_LIIC (field) = 0;
+}
+
+/* Figure whether all final variables have beem initialized in MDECL
+ and mark MDECL accordingly. */
+
+static void
+check_final_variable_local_assignment_flag (class, mdecl)
+ tree class;
+ tree mdecl;
+{
+ tree field;
+ int initialized = 0;
+ int non_initialized = 0;
+
+ if (DECL_FUNCTION_SYNTHETIC_CTOR (mdecl))
+ return;
+
+ /* First find out whether all final variables or no final variable
+ are initialized in this ctor. We don't take into account final
+ variable that have been initialized upon declaration. */
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FINAL_VARIABLE_P (field) && !DECL_FIELD_FINAL_IUD (field))
+ {
+ if (DECL_FIELD_FINAL_LIIC (field))
+ initialized++;
+ else
+ non_initialized++;
+ }
+
+ /* There were no non initialized variable and no initialized variable.
+ This ctor is fine. */
+ if (!non_initialized && !initialized)
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+ /* If no variables have been initialized, that fine. We'll check
+ later whether this ctor calls a constructor which initializes
+ them. We mark the ctor as not initializing all its finals. */
+ else if (initialized == 0)
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 0;
+ /* If we have a mixed bag, then we have a problem. We need to report
+ all the variables we're not initializing. */
+ else if (initialized && non_initialized)
+ {
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 0;
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FIELD_FINAL (field)
+ && !DECL_FIELD_FINAL_IUD (field) && !DECL_FIELD_FINAL_LIIC (field))
+ {
+ parse_error_context
+ (lookup_cl (mdecl),
+ "Blank final variable `%s' may not have been initialized in this constructor",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+ DECL_FIELD_FINAL_IERR (field) = 1;
+ }
+ }
+ /* Otherwise we know this ctor is initializing all its final
+ variable. We mark it so. */
+ else
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+}
+
+/* This function recurses in a simple what through STMT and stops when
+ it finds a constructor call. It then verifies that the called
+ constructor initialized its final properly. Return 1 upon success,
+ 0 or -1 otherwise. */
+
+static int
+check_final_variable_indirect_assignment (stmt)
+ tree stmt;
+{
+ int res;
+ switch (TREE_CODE (stmt))
+ {
+ case EXPR_WITH_FILE_LOCATION:
+ return check_final_variable_indirect_assignment (EXPR_WFL_NODE (stmt));
+ case COMPOUND_EXPR:
+ res = check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 0));
+ if (res)
+ return res;
+ return check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 1));
+ case SAVE_EXPR:
+ return check_final_variable_indirect_assignment (TREE_OPERAND (stmt, 0));
+ case CALL_EXPR:
+ {
+ tree decl = TREE_OPERAND (stmt, 0);
+ tree fbody;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ fatal ("Can't find FUNCTION_DECL in CALL_EXPR - check_final_variable_indirect_assignment");
+ if (DECL_FUNCTION_ALL_FINAL_INITIALIZED (decl))
+ return 1;
+ if (DECL_FINIT_P (decl) || DECL_CONTEXT (decl) != current_class)
+ return -1;
+ fbody = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (decl));
+ if (fbody == error_mark_node)
+ return -1;
+ fbody = BLOCK_EXPR_BODY (fbody);
+ return check_final_variable_indirect_assignment (fbody);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* This is the last chance to catch a final variable initialization
+ problem. This routine will report an error if a final variable was
+ never (globally) initialized and never reported as not having been
+ initialized properly. */
+
+static void
+check_final_variable_global_assignment_flag (class)
+ tree class;
+{
+ tree field, mdecl;
+ int nnctor = 0;
+
+ /* We go through all natural ctors and see whether they're
+ initializing all their final variables or not. */
+ current_function_decl = NULL_TREE; /* For the error report. */
+ for (mdecl = TYPE_METHODS (class); mdecl; mdecl = TREE_CHAIN (mdecl))
+ if (DECL_CONSTRUCTOR_P (mdecl) && ! DECL_FUNCTION_SYNTHETIC_CTOR (mdecl))
+ {
+ if (!DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl))
+ {
+ /* It doesn't. Maybe it calls a constructor that initializes
+ them. find out. */
+ tree fbody = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl));
+ if (fbody == error_mark_node)
+ continue;
+ fbody = BLOCK_EXPR_BODY (fbody);
+ if (check_final_variable_indirect_assignment (fbody) == 1)
+ {
+ DECL_FUNCTION_ALL_FINAL_INITIALIZED (mdecl) = 1;
+ nnctor++;
+ }
+ else
+ parse_error_context
+ (lookup_cl (mdecl),
+ "Final variable initialization error in this constructor");
+ }
+ else
+ nnctor++;
+ }
+
+ /* Finally we catch final variables that never were initialized */
+ for (field = TYPE_FIELDS (class); field; field = TREE_CHAIN (field))
+ if (FINAL_VARIABLE_P (field)
+ /* If the field wasn't initialized upon declaration */
+ && !DECL_FIELD_FINAL_IUD (field)
+ /* There wasn't natural ctor in which the field could have been
+ initialized */
+ && !nnctor
+ /* If we never reported a problem with this field */
+ && !DECL_FIELD_FINAL_IERR (field))
+ {
+ current_function_decl = NULL;
+ parse_error_context
+ (DECL_FIELD_FINAL_WFL (field),
+ "Final variable `%s' hasn't been initialized upon its declaration",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+ }
+
+}
+
/* Return 1 if an assignment to a FINAL is attempted in a non suitable
context. */
check_final_assignment (lvalue, wfl)
tree lvalue, wfl;
{
- if (TREE_CODE (lvalue) == COMPOUND_EXPR
+ if (TREE_CODE (lvalue) != COMPONENT_REF && !JDECL_P (lvalue))
+ return 0;
+
+ if (TREE_CODE (lvalue) == COMPONENT_REF
&& JDECL_P (TREE_OPERAND (lvalue, 1)))
lvalue = TREE_OPERAND (lvalue, 1);
- /* When generating class files, references to the `length' field
- look a bit different. */
- if ((flag_emit_class_files
- && TREE_CODE (lvalue) == COMPONENT_REF
- && TYPE_ARRAY_P (TREE_TYPE (TREE_OPERAND (lvalue, 0)))
- && FIELD_FINAL (TREE_OPERAND (lvalue, 1)))
- || (TREE_CODE (lvalue) == FIELD_DECL
- && FIELD_FINAL (lvalue)
- && !DECL_CLINIT_P (current_function_decl)
- && !DECL_FINIT_P (current_function_decl)))
+ if (!FIELD_FINAL (lvalue))
+ return 0;
+
+ /* Now the logic. We can modify a final VARIABLE:
+ 1) in finit$, (its declaration was followed by an initialization,)
+ 2) consistently in each natural ctor, if it wasn't initialized in
+ finit$ or once in <clinit>. In any other cases, an error should be
+ reported. */
+ if (DECL_FINIT_P (current_function_decl))
{
- parse_error_context
- (wfl, "Can't assign a value to the final variable `%s'",
- IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
- return 1;
+ DECL_FIELD_FINAL_IUD (lvalue) = 1;
+ return 0;
}
- return 0;
+
+ if (!DECL_FUNCTION_SYNTHETIC_CTOR (current_function_decl)
+ /* Only if it wasn't given a value upon initialization */
+ && DECL_LANG_SPECIFIC (lvalue) && !DECL_FIELD_FINAL_IUD (lvalue)
+ /* If it was never assigned a value in this constructor */
+ && !DECL_FIELD_FINAL_LIIC (lvalue))
+ {
+ /* Turn the locally assigned flag on, it will be checked later
+ on to point out at discrepancies. */
+ DECL_FIELD_FINAL_LIIC (lvalue) = 1;
+ if (DECL_CLINIT_P (current_function_decl))
+ DECL_FIELD_FINAL_IUD (lvalue) = 1;
+ return 0;
+ }
+
+ /* Other problems should be reported right away. */
+ parse_error_context
+ (wfl, "Can't %sassign a value to the final variable `%s'",
+ (FIELD_STATIC (lvalue) ? "re" : ""),
+ IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
+
+ /* Note that static field can be initialized once and only once. */
+ if (FIELD_STATIC (lvalue))
+ DECL_FIELD_FINAL_IERR (lvalue) = 1;
+
+ return 1;
}
/* Inline references to java.lang.PRIMTYPE.TYPE when accessed in
/* 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))
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)
{
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)))
{
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: