/* Source code parsing and tree node generation for the GNU compiler
for the Java(TM) language.
- Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
This file is part of GNU CC.
#include "xref.h"
#include "function.h"
#include "except.h"
-#include "defaults.h"
#include "ggc.h"
#ifndef DIR_SEPARATOR
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 resolve_package PARAMS ((tree, tree *));
static tree lookup_package_type PARAMS ((const char *, int));
-static tree lookup_package_type_and_set_next PARAMS ((const char *, int, tree *));
static tree resolve_class PARAMS ((tree, tree, tree, tree));
static void declare_local_variables PARAMS ((int, tree, tree));
static void source_start_java_method PARAMS ((tree));
static void source_end_java_method PARAMS ((void));
-static void expand_start_java_method PARAMS ((tree));
static tree find_name_in_single_imports PARAMS ((tree));
static void check_abstract_method_header PARAMS ((tree));
static tree lookup_java_interface_method2 PARAMS ((tree, tree));
static tree maybe_create_class_interface_decl PARAMS ((tree, tree, tree, tree));
static int check_class_interface_creation PARAMS ((int, int, tree,
tree, tree, tree));
-static tree patch_method_invocation PARAMS ((tree, tree, tree,
+static tree patch_method_invocation PARAMS ((tree, tree, tree, int,
int *, tree *));
static int breakdown_qualified PARAMS ((tree *, tree *, tree));
+static int in_same_package PARAMS ((tree, tree));
static tree resolve_and_layout PARAMS ((tree, tree));
static tree qualify_and_find PARAMS ((tree, tree, tree));
static tree resolve_no_layout PARAMS ((tree, tree));
static void create_jdep_list PARAMS ((struct parser_ctxt *));
static tree build_expr_block PARAMS ((tree, tree));
static tree enter_block PARAMS ((void));
-static tree enter_a_block PARAMS ((tree));
static tree exit_block PARAMS ((void));
static tree lookup_name_in_blocks PARAMS ((tree));
static void maybe_absorb_scoping_blocks PARAMS ((void));
static int complete_function_arguments PARAMS ((tree));
static int check_for_static_method_reference PARAMS ((tree, tree, tree,
tree, tree));
-static int not_accessible_p PARAMS ((tree, tree, int));
+static int not_accessible_p PARAMS ((tree, tree, tree, int));
static void check_deprecation PARAMS ((tree, tree));
static int class_in_current_package PARAMS ((tree));
static tree build_if_else_statement PARAMS ((int, tree, tree, tree));
static tree patch_conditional_expr PARAMS ((tree, tree, tree));
static tree generate_finit PARAMS ((tree));
static void add_instance_initializer PARAMS ((tree));
+static tree build_instance_initializer PARAMS ((tree));
static void fix_constructors PARAMS ((tree));
static tree build_alias_initializer_parameter_list PARAMS ((int, tree,
tree, int *));
static void start_artificial_method_body PARAMS ((tree));
static void end_artificial_method_body PARAMS ((tree));
static int check_method_redefinition PARAMS ((tree, tree));
-static int reset_method_name PARAMS ((tree));
static int check_method_types_complete PARAMS ((tree));
static void java_check_regular_methods PARAMS ((tree));
static void java_check_abstract_methods 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 */
static tree build_dot_class_method_invocation PARAMS ((tree));
static void create_new_parser_context PARAMS ((int));
static void mark_parser_ctxt PARAMS ((void *));
+static tree maybe_build_class_init_for_field PARAMS ((tree, tree));
/* Number of error found so far. */
int java_error_count;
/* Tell when not to fold, when doing xrefs */
int do_not_fold;
/* Cyclic inheritance report, as it can be set by layout_class */
-char *cyclic_inheritance_report;
+const char *cyclic_inheritance_report;
/* Tell when we're within an instance initializer */
static int in_instance_initializer;
struct parser_ctxt *ctxp;
/* List of things that were analyzed for which code will be generated */
-static struct parser_ctxt *ctxp_for_generation = NULL;
+struct parser_ctxt *ctxp_for_generation = NULL;
/* binop_lookup maps token to tree_code. It is used where binary
operations are involved and required by the parser. RDIV_EXPR
the list of the catch clauses of the currently analysed try block. */
static tree currently_caught_type_list;
+static tree src_parse_roots[1] = { NULL_TREE };
+
+/* All classes seen from source code */
+#define gclass_list src_parse_roots[0]
+
/* Check modifiers. If one doesn't fit, retrieve it in its declaration
line and point it out. */
/* Should point out the one that don't fit. ASCII/unicode, going
%token STATIC_TK FINAL_TK SYNCHRONIZED_TK
%token VOLATILE_TK TRANSIENT_TK NATIVE_TK
%token PAD_TK ABSTRACT_TK MODIFIER_TK
+%token STRICT_TK
/* Keep those two in order, too */
%token DECR_TK INCR_TK
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 */
ggc_add_tree_root (&package_list, 1);
ggc_add_tree_root (¤t_this, 1);
ggc_add_tree_root (¤tly_caught_type_list, 1);
- ggc_add_string_root (&cyclic_inheritance_report, 1);
ggc_add_root (&ctxp, 1,
sizeof (struct parser_ctxt *),
mark_parser_ctxt);
;
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);
+ 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 */
}
| DEFAULT_TK REL_CL_TK
{
- tree lab = build1 (DEFAULT_EXPR, NULL_TREE, NULL_TREE);
+ tree lab = build (DEFAULT_EXPR, NULL_TREE, NULL_TREE);
EXPR_WFL_LINECOL (lab) = $1.location;
java_method_add_stmt (current_function_decl, lab);
}
declared initialized by the appropriate function
call */
tree ccpb = enter_block ();
- tree init = build_assignment (ASSIGN_TK, $2.location,
- TREE_PURPOSE ($3),
- soft_exceptioninfo_call_node);
+ tree init = build_assignment
+ (ASSIGN_TK, $2.location, TREE_PURPOSE ($3),
+ build (JAVA_EXC_OBJ_EXPR, ptr_type_node));
declare_local_variables (0, TREE_VALUE ($3),
build_tree_list (TREE_PURPOSE ($3),
init));
{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); }
+ { $$ = build_incomplete_class_ref ($2.location, $1); }
| VOID_TK DOT_TK CLASS_TK
- { $$ = build_class_ref (void_type_node); }
+ {
+ $$ = build_incomplete_class_ref ($2.location,
+ void_type_node);
+ }
;
class_instance_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,
}
| 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)
+ abort ();
+
+ to_return = CURRENT_OSB (ctxp);
+ ctxp->osb_depth--;
+
+ return to_return;
+}
+
\f
/* This section of the code deal with save/restoring parser contexts.
java_push_parser_context ()
{
create_new_parser_context (0);
- if (ctxp->next)
- {
- ctxp->incomplete_class = ctxp->next->incomplete_class;
- ctxp->gclass_list = ctxp->next->gclass_list;
- }
}
void
next = ctxp->next;
if (next)
{
- next->incomplete_class = ctxp->incomplete_class;
- next->gclass_list = ctxp->gclass_list;
lineno = ctxp->lineno;
current_class = ctxp->class_type;
}
/* Set the single import class file flag to 0 for the current list
of imported things */
for (current = ctxp->import_list; current; current = TREE_CHAIN (current))
- IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_PURPOSE (current)) = 0;
+ IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_VALUE (current)) = 0;
/* And restore those of the previous context */
if ((ctxp = next)) /* Assignment is really meant here */
for (current = ctxp->import_list; current; current = TREE_CHAIN (current))
- IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_PURPOSE (current)) = 1;
+ IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_VALUE (current)) = 1;
/* If we pushed a context to parse a class intended to be generated,
we keep it so we can remember the class. What we could actually
struct parser_ctxt *restored = saver->next; /* This one is the old current */
/* We need to inherit the list of classes to complete/generate */
- restored->incomplete_class = old->incomplete_class;
- restored->gclass_list = old->gclass_list;
restored->classd_list = old->classd_list;
restored->class_list = old->class_list;
ctxp = restored;
/* Re-installed the data for the parsing to carry on */
- bcopy (&old->marker_begining, &ctxp->marker_begining,
- (size_t)(&ctxp->marker_end - &ctxp->marker_begining));
+ memcpy (&ctxp->marker_begining, &old->marker_begining,
+ (size_t)(&ctxp->marker_end - &ctxp->marker_begining));
/* Buffer context can now be discarded */
free (saver);
int save_lineno;
char *remainder, *code_from_source;
- extern struct obstack temporary_obstack;
if (!force_error && prev_lineno == lineno)
return;
parse_error_context (wfl_operator, "Unreachable statement");
}
else
- fatal ("Can't get valid statement - unreachable_stmt_error");
+ abort ();
}
int
/* If we have, then craft a new type for this variable */
if (more_dims)
{
+ tree save = type;
+
name = get_identifier (&string [more_dims]);
/* If we have a pointer, use its type */
if (JPRIMITIVE_TYPE_P (type))
{
type = build_java_array_type (type, -1);
- CLASS_LOADED_P (type) = 1;
more_dims--;
}
/* Otherwise, if we have a WFL for this type, use it (the type
is already an array on an unresolved type, and we just keep
on adding dimensions) */
else if (type_wfl)
- type = type_wfl;
+ {
+ int i = 0;
+ type = type_wfl;
+ string = IDENTIFIER_POINTER (TYPE_NAME (save));
+ while (string[i] == '[')
+ ++i;
+ more_dims += i;
+ }
/* Add all the dimensions */
while (more_dims--)
tree type_or_wfl;
{
const char *ptr;
+ tree wfl;
/* TYPE_OR_WFL might be an array on a resolved type. In this case,
just create a array type */
if (TREE_CODE (type_or_wfl) == RECORD_TYPE)
- {
- tree type = build_java_array_type (type_or_wfl, -1);
- CLASS_LOADED_P (type) = CLASS_LOADED_P (type_or_wfl);
- return type;
- }
+ return build_java_array_type (type_or_wfl, -1);
obstack_1grow (&temporary_obstack, '[');
obstack_grow0 (&temporary_obstack,
IDENTIFIER_POINTER (EXPR_WFL_NODE (type_or_wfl)),
IDENTIFIER_LENGTH (EXPR_WFL_NODE (type_or_wfl)));
ptr = obstack_finish (&temporary_obstack);
- EXPR_WFL_NODE (type_or_wfl) = get_identifier (ptr);
- return type_or_wfl;
+ wfl = build_expr_wfl (get_identifier (ptr),
+ EXPR_WFL_FILENAME (type_or_wfl),
+ EXPR_WFL_LINENO (type_or_wfl),
+ EXPR_WFL_COLNO (type_or_wfl));
+ /* Re-install the existing qualifications so that the type can be
+ resolved properly. */
+ EXPR_WFL_QUALIFICATION (wfl) = EXPR_WFL_QUALIFICATION (type_or_wfl);
+ return wfl;
}
static void
/* Why is NO_DOLLAR_IN_LABEL defined? */
#if 0
#ifdef NO_DOLLAR_IN_LABEL
- fatal ("make_nested_class_name: Can't use '$' as a separator "
- "for inner classes");
+ internal_error ("Can't use '$' as a separator for inner classes");
#endif
#endif
obstack_1grow (&temporary_obstack, '$');
acc = merge_qualified_name (acc,
EXPR_WFL_NODE (TREE_PURPOSE (qual)));
BUILD_PTR_FROM_NAME (ptr, acc);
- decl = do_resolve_class (NULL_TREE, ptr, NULL_TREE, cl);
+
+ /* Don't try to resolve ACC as a class name if it follows
+ the current package name. We don't want to pick something
+ that's accidentally there: for example `a.b.c' in package
+ `a.b' shouldn't trigger loading `a' if it's there by
+ itself. */
+ if (ctxp->package
+ && strstr (IDENTIFIER_POINTER (ctxp->package),
+ IDENTIFIER_POINTER (acc)))
+ decl = NULL;
+ else
+ decl = do_resolve_class (NULL_TREE, ptr, NULL_TREE, cl);
}
/* A NULL qual and a decl means that the search ended
else
DECL_SOURCE_LINE (decl) = EXPR_WFL_LINENO (cl);
CLASS_FROM_SOURCE_P (TREE_TYPE (decl)) = 1;
- CLASS_FROM_CURRENTLY_COMPILED_SOURCE_P (TREE_TYPE (decl)) =
+ CLASS_PARSED_P (TREE_TYPE (decl)) = 1;
+ CLASS_FROM_CURRENTLY_COMPILED_P (TREE_TYPE (decl)) =
IS_A_COMMAND_LINE_FILENAME_P (EXPR_WFL_FILENAME_NODE (cl));
PUSH_CPC (decl, raw_name);
ctxp->class_list = decl;
/* Create a new nodes in the global lists */
- ctxp->gclass_list = tree_cons (NULL_TREE, decl, ctxp->gclass_list);
+ gclass_list = tree_cons (NULL_TREE, decl, gclass_list);
all_class_list = tree_cons (NULL_TREE, decl, all_class_list);
/* Install a new dependency list element */
else
super_decl_type = NULL_TREE;
- /* Set super info and mark the class a complete */
+ /* A class nested in an interface is implicitly static. */
+ if (INNER_CLASS_DECL_P (decl)
+ && CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (DECL_CONTEXT (decl)))))
+ {
+ flags |= ACC_STATIC;
+ }
+
+ /* Set super info and mark the class as complete. */
set_super_info (flags, TREE_TYPE (decl), super_decl_type,
ctxp->interface_number);
ctxp->interface_number = 0;
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));
/* Last chance: if we're within the context of an inner class, we
might be trying to access a local variable defined in an outer
context. We try to look for it now. */
- if (INNER_CLASS_TYPE_P (class))
+ if (INNER_CLASS_TYPE_P (class) && TREE_CODE (name) == IDENTIFIER_NODE)
{
tree new_name;
MANGLE_OUTER_LOCAL_VARIABLE_NAME (new_name, name);
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)
return mdecl;
}
-static void
-add_instance_initializer (mdecl)
+static tree
+build_instance_initializer (mdecl)
tree mdecl;
{
- tree current;
- tree stmt_list = TYPE_II_STMT_LIST (DECL_CONTEXT (mdecl));
tree compound = NULL_TREE;
+ tree stmt_list = TYPE_II_STMT_LIST (DECL_CONTEXT (mdecl));
+ tree current;
- if (stmt_list)
- {
- for (current = stmt_list; current; current = TREE_CHAIN (current))
- compound = add_stmt_to_compound (compound, NULL_TREE, current);
+ for (current = stmt_list; current; current = TREE_CHAIN (current))
+ compound = add_stmt_to_compound (compound, NULL_TREE, current);
- java_method_add_stmt (mdecl, build1 (INSTANCE_INITIALIZERS_EXPR,
- NULL_TREE, compound));
- }
+ return compound;
+}
+
+static void
+add_instance_initializer (mdecl)
+ tree mdecl;
+{
+ tree compound = build_instance_initializer (mdecl);
+
+ if (compound)
+ java_method_add_stmt (mdecl, build1 (INSTANCE_INITIALIZERS_EXPR,
+ NULL_TREE, compound));
}
/* Shared accros method_declarator and method_header to remember the
DECL_FUNCTION_THROWS (meth) = throws;
}
- /* We set the DECL_NAME to ID so we can track the location where
- the function was declared. This allow us to report
- redefinition error accurately. When method are verified,
- DECL_NAME is reinstalled properly (using the content of the
- WFL node ID) (see check_method_redefinition). We don't do that
- when Object is being defined. Constructor <init> names will be
- reinstalled the same way. */
if (TREE_TYPE (GET_CPC ()) != object_type_node)
- DECL_NAME (meth) = id;
+ DECL_FUNCTION_WFL (meth) = id;
/* Set the flag if we correctly processed a constructor */
if (constructor_ok)
/* 8.4.5 Method Body */
if ((flags & ACC_ABSTRACT || flags & ACC_NATIVE) && method_body)
{
- tree wfl = DECL_NAME (current_function_decl);
- parse_error_context (wfl,
+ tree name = DECL_NAME (current_function_decl);
+ parse_error_context (DECL_FUNCTION_WFL (current_function_decl),
"%s method `%s' can't have a body defined",
(METHOD_NATIVE (current_function_decl) ?
"Native" : "Abstract"),
- IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
+ IDENTIFIER_POINTER (name));
method_body = NULL_TREE;
}
else if (!(flags & ACC_ABSTRACT) && !(flags & ACC_NATIVE) && !method_body)
{
- tree wfl = DECL_NAME (current_function_decl);
+ tree name = DECL_NAME (current_function_decl);
parse_error_context
- (wfl,
+ (DECL_FUNCTION_WFL (current_function_decl),
"Non native and non abstract method `%s' must have a body defined",
- IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)));
+ IDENTIFIER_POINTER (name));
method_body = NULL_TREE;
}
tree meth;
{
int flags = get_access_flags_from_decl (meth);
- /* DECL_NAME might still be a WFL node */
- tree name = GET_METHOD_NAME (meth);
OBSOLETE_MODIFIER_WARNING2 (MODIFIER_WFL (ABSTRACT_TK), flags,
ACC_ABSTRACT, "abstract method",
- IDENTIFIER_POINTER (name));
+ IDENTIFIER_POINTER (DECL_NAME (meth)));
OBSOLETE_MODIFIER_WARNING2 (MODIFIER_WFL (PUBLIC_TK), flags,
ACC_PUBLIC, "abstract method",
- IDENTIFIER_POINTER (name));
+ IDENTIFIER_POINTER (DECL_NAME (meth)));
check_modifiers ("Illegal modifier `%s' for interface method",
flags, INTERFACE_METHOD_MODIFIERS);
return 1;
}
- /* Check scope: same package OK, other package: OK if public */
- if (check_pkg_class_access (DECL_NAME (super_decl), lookup_cl (this_decl)))
+ /* Check top-level interface access. Inner classes are subject to member
+ access rules (6.6.1). */
+ if (! INNER_CLASS_P (super_type)
+ && check_pkg_class_access (DECL_NAME (super_decl), lookup_cl (this_decl)))
return 1;
SOURCE_FRONTEND_DEBUG (("Completing interface %s with %s",
return 1;
}
- /* Check scope: same package OK, other package: OK if public */
- if (check_pkg_class_access (DECL_NAME (super_decl), wfl))
+ /* Check top-level class scope. Inner classes are subject to member access
+ rules (6.6.1). */
+ if (! INNER_CLASS_P (super_type)
+ && (check_pkg_class_access (DECL_NAME (super_decl), wfl)))
return 1;
SOURCE_FRONTEND_DEBUG (("Completing class %s with %s",
obtain_incomplete_type (type_name)
tree type_name;
{
- tree ptr, name;
+ tree ptr = NULL_TREE, name;
if (TREE_CODE (type_name) == EXPR_WITH_FILE_LOCATION)
name = EXPR_WFL_NODE (type_name);
else if (INCOMPLETE_TYPE_P (type_name))
name = TYPE_NAME (type_name);
else
- fatal ("invalid type name - obtain_incomplete_type");
-
- for (ptr = ctxp->incomplete_class; ptr; ptr = TREE_CHAIN (ptr))
- if (TYPE_NAME (ptr) == name)
- break;
+ abort ();
- if (!ptr)
- {
- BUILD_PTR_FROM_NAME (ptr, name);
- layout_type (ptr);
- TREE_CHAIN (ptr) = ctxp->incomplete_class;
- ctxp->incomplete_class = ptr;
- }
+ BUILD_PTR_FROM_NAME (ptr, name);
+ layout_type (ptr);
return ptr;
}
JDEP_KIND (new) = kind;
JDEP_DECL (new) = decl;
- JDEP_SOLV (new) = ptr;
+ JDEP_TO_RESOLVE (new) = ptr;
JDEP_WFL (new) = wfl;
JDEP_CHAIN (new) = NULL;
JDEP_MISC (new) = NULL_TREE;
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;
}
if (CLASS_INTERFACE (TYPE_NAME (class_type)))
continue;
+ current_class = class_type;
for (decl = TYPE_METHODS (class_type); decl; decl = TREE_CHAIN (decl))
{
if (DECL_CONSTRUCTOR_P (decl))
current_class = save_current_class;
input_filename = save_input_filename;
lineno = save_lineno;
- CLASS_LOADED_P (class) = 1;
}
static tree
if (!decl)
complete_class_report_errors (dep);
else if (PURE_INNER_CLASS_DECL_P (decl))
- check_inner_class_access (decl, JDEP_ENCLOSING (dep), JDEP_WFL (dep));
+ {
+ tree inner = TREE_TYPE (decl);
+ if (! CLASS_LOADED_P (inner))
+ {
+ safe_layout_class (inner);
+ if (TYPE_SIZE (inner) == error_mark_node)
+ TYPE_SIZE (inner) = NULL_TREE;
+ }
+ check_inner_class_access (decl, JDEP_ENCLOSING (dep), JDEP_WFL (dep));
+ }
return decl;
}
break;
default:
- fatal ("Can't handle patch code %d - java_complete_class",
- JDEP_KIND (dep));
+ abort ();
}
}
}
{
while (base != name)
{
- if (TREE_CODE (resolved_type) == RECORD_TYPE)
- resolved_type = promote_type (resolved_type);
resolved_type = build_java_array_type (resolved_type, -1);
- CLASS_LOADED_P (resolved_type) = 1;
name--;
}
- /* Build a fake decl for this, since this is what is expected to
- be returned. */
- resolved_type_decl =
- build_decl (TYPE_DECL, TYPE_NAME (resolved_type), resolved_type);
- /* Figure how those two things are important for error report. FIXME */
- DECL_SOURCE_LINE (resolved_type_decl) = 0;
- DECL_SOURCE_FILE (resolved_type_decl) = input_filename;
- TYPE_NAME (class_type) = TYPE_NAME (resolved_type);
+ /* A TYPE_NAME that is a TYPE_DECL was set in
+ build_java_array_type, return it. */
+ resolved_type_decl = TYPE_NAME (resolved_type);
}
TREE_TYPE (class_type) = resolved_type;
return resolved_type_decl;
do_resolve_class (enclosing, class_type, decl, cl)
tree enclosing, class_type, decl, cl;
{
- tree new_class_decl;
+ tree new_class_decl, super, start;
/* Do not try to replace TYPE_NAME (class_type) by a variable, since
it is changed by find_in_imports{_on_demand} and (but it doesn't
really matter) qualify_and_find */
/* 0- Search in the current class as an inner class */
+ start = enclosing;
/* Maybe some code here should be added to load the class or
something, at least if the class isn't an inner class and ended
being loaded from class file. FIXME. */
while (enclosing)
{
- tree name;
tree intermediate;
if ((new_class_decl = find_as_inner_class (enclosing, class_type, cl)))
}
/* Now go to the upper classes, bail out if necessary. */
- enclosing = CLASSTYPE_SUPER (TREE_TYPE (enclosing));
- if (!enclosing || enclosing == object_type_node)
- break;
-
- if (TREE_CODE (enclosing) == RECORD_TYPE)
- {
- enclosing = TYPE_NAME (enclosing);
- continue;
- }
+ super = CLASSTYPE_SUPER (TREE_TYPE (enclosing));
+ if (!super || super == object_type_node)
+ break;
- if (TREE_CODE (enclosing) == IDENTIFIER_NODE)
- BUILD_PTR_FROM_NAME (name, enclosing);
+ if (TREE_CODE (super) == POINTER_TYPE)
+ super = do_resolve_class (NULL, super, NULL, NULL);
else
- name = enclosing;
- enclosing = do_resolve_class (NULL, name, NULL, NULL);
+ super = TYPE_NAME (super);
+
+ /* We may not have checked for circular inheritance yet, so do so
+ here to prevent an infinite loop. */
+ if (super == start)
+ {
+ if (!cl)
+ cl = lookup_cl (decl);
+
+ parse_error_context
+ (cl, "Cyclic inheritance involving %s",
+ IDENTIFIER_POINTER (DECL_NAME (enclosing)));
+ break;
+ }
+ enclosing = super;
}
/* 1- Check for the type in single imports. This will change
/* 5- Check an other compilation unit that bears the name of type */
load_class (TYPE_NAME (class_type), 0);
- if (check_pkg_class_access (TYPE_NAME (class_type),
- (cl ? cl : lookup_cl (decl))))
- return NULL_TREE;
-
+
+ if (!cl)
+ cl = lookup_cl (decl);
+
+ /* If we don't have a value for CL, then we're being called recursively.
+ We can't check package access just yet, but it will be taken care of
+ by the caller. */
+ if (cl)
+ {
+ if (check_pkg_class_access (TYPE_NAME (class_type), cl))
+ return NULL_TREE;
+ }
+
/* 6- Last call for a resolution */
return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
}
return to_return;
}
-/* Reinstall the proper DECL_NAME on METHOD. Return 0 if the method
- nevertheless needs to be verfied, 1 otherwise. */
-
-static int
-reset_method_name (method)
- tree method;
-{
- if (!DECL_CLINIT_P (method) && !DECL_FINIT_P (method))
- {
- /* NAME is just the plain name when Object is being defined */
- if (DECL_CONTEXT (method) != object_type_node)
- DECL_NAME (method) = (DECL_CONSTRUCTOR_P (method) ?
- init_identifier_node : GET_METHOD_NAME (method));
- return 0;
- }
- else
- return 1;
-}
-
-/* Return the name of METHOD_DECL, when DECL_NAME is a WFL */
-
-tree
-java_get_real_method_name (method_decl)
- tree method_decl;
-{
- tree method_name = DECL_NAME (method_decl);
- if (DECL_CONSTRUCTOR_P (method_decl))
- return init_identifier_node;
-
- /* Explain here why METHOD_DECL doesn't have the DECL_CONSTRUCTUR_P
- and still can be a constructor. FIXME */
-
- /* Don't confuse method only bearing the name of their class as
- constructors */
- else if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (method_decl))
- && ctxp
- && GET_CPC_UN () == EXPR_WFL_NODE (method_name)
- && get_access_flags_from_decl (method_decl) <= ACC_PROTECTED
- && TREE_TYPE (TREE_TYPE (method_decl)) == void_type_node)
- return init_identifier_node;
- else
- return EXPR_WFL_NODE (method_name);
-}
-
/* Track method being redefined inside the same class. As a side
effect, set DECL_NAME to an IDENTIFIER (prior entering this
function it's a FWL, so we can track errors more accurately.) */
check_method_redefinition (class, method)
tree class, method;
{
- tree redef, name;
- tree cl = DECL_NAME (method);
- tree sig = TYPE_ARGUMENT_SIGNATURE (TREE_TYPE (method));
- /* decl name of artificial <clinit> and finit$ doesn't need to be
- fixed and checked */
+ tree redef, sig;
- /* Reset the method name before running the check. If it returns 1,
- the method doesn't need to be verified with respect to method
- redeclaration and we return 0 */
- if (reset_method_name (method))
+ /* There's no need to verify <clinit> and finit$ */
+ if (DECL_CLINIT_P (method) || DECL_FINIT_P (method))
return 0;
- name = DECL_NAME (method);
+ sig = TYPE_ARGUMENT_SIGNATURE (TREE_TYPE (method));
for (redef = TYPE_METHODS (class); redef; redef = TREE_CHAIN (redef))
{
if (redef == method)
break;
- if (DECL_NAME (redef) == name
- && sig == TYPE_ARGUMENT_SIGNATURE (TREE_TYPE (redef)))
+ if (DECL_NAME (redef) == DECL_NAME (method)
+ && sig == TYPE_ARGUMENT_SIGNATURE (TREE_TYPE (redef))
+ && !DECL_ARTIFICIAL (method))
{
parse_error_context
- (cl, "Duplicate %s declaration `%s'",
+ (DECL_FUNCTION_WFL (method), "Duplicate %s declaration `%s'",
(DECL_CONSTRUCTOR_P (redef) ? "constructor" : "method"),
get_printable_method_name (redef));
return 1;
char *t = xstrdup (lang_printable_name
(TREE_TYPE (TREE_TYPE (method)), 0));
tree ccn = DECL_NAME (TYPE_NAME (DECL_CONTEXT (method)));
- tree saved_wfl = NULL_TREE;
-
- if (TREE_CODE (DECL_NAME (method)) == EXPR_WITH_FILE_LOCATION)
- {
- saved_wfl = DECL_NAME (method);
- DECL_NAME (method) = EXPR_WFL_NODE (DECL_NAME (method));
- }
parse_error_context
(lookup_cl (class_decl),
IDENTIFIER_POINTER (DECL_NAME (class_decl)));
ok = 0;
free (t);
-
- if (saved_wfl)
- DECL_NAME (method) = saved_wfl;
}
}
int saw_constructor = ANONYMOUS_CLASS_P (TREE_TYPE (class_decl));
tree method;
tree class = CLASS_TO_HANDLE_TYPE (TREE_TYPE (class_decl));
- tree saved_found_wfl = NULL_TREE, found = NULL_TREE;
+ tree found = NULL_TREE;
tree mthrows;
/* It is not necessary to check methods defined in java.lang.Object */
for (method = TYPE_METHODS (class); method; method = TREE_CHAIN (method))
{
tree sig;
- tree method_wfl = DECL_NAME (method);
+ tree method_wfl = DECL_FUNCTION_WFL (method);
int aflags;
- /* If we previously found something and its name was saved,
- reinstall it now */
- if (found && saved_found_wfl)
- {
- DECL_NAME (found) = saved_found_wfl;
- saved_found_wfl = NULL_TREE;
- }
-
/* Check for redefinitions */
if (check_method_redefinition (class, method))
continue;
continue;
}
- /* If found wasn't verified, it's DECL_NAME won't be set properly.
- We set it temporarily for the sake of the error report. */
- saved_found_wfl = DECL_NAME (found);
- reset_method_name (found);
-
/* If `found' is declared in an interface, make sure the
modifier matches. */
if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (found)))
}
aflags = get_access_flags_from_decl (found);
- /* If the method has default, access in an other package, then
- issue a warning that the current method doesn't override the
- one that was found elsewhere. Do not issue this warning when
- the match was found in java.lang.Object. */
- if (DECL_CONTEXT (found) != object_type_node
- && ((aflags & ACC_VISIBILITY) == 0)
- && !class_in_current_package (DECL_CONTEXT (found))
- && !DECL_CLINIT_P (found)
- && flag_not_overriding)
- {
- parse_warning_context
- (method_wfl, "Method `%s' in class `%s' does not override the corresponding method in class `%s', which is private to a different package",
- lang_printable_name (found, 0),
- IDENTIFIER_POINTER (DECL_NAME (class_decl)),
- IDENTIFIER_POINTER (DECL_NAME
- (TYPE_NAME (DECL_CONTEXT (found)))));
- continue;
- }
/* Can't override final. Can't override static. */
if (METHOD_FINAL (found) || METHOD_STATIC (found))
/* Inheriting multiple methods with the same signature. FIXME */
}
- /* Don't forget eventual pending found and saved_found_wfl. Take
- into account that we might have exited because we saw an
- artificial method as the last entry. */
-
- if (found && !DECL_ARTIFICIAL (found) && saved_found_wfl)
- DECL_NAME (found) = saved_found_wfl;
-
if (!TYPE_NVIRTUALS (class))
TYPE_METHODS (class) = nreverse (TYPE_METHODS (class));
java_check_abstract_method_definitions (class_decl);
if (!saw_constructor)
- fatal ("No constructor found");
+ abort ();
}
/* Return a non zero value if the `throws' clause of METHOD (if any)
for (method = TYPE_METHODS (interface); method; method = TREE_CHAIN (method))
{
- tree method_wfl = DECL_NAME (method);
-
/* 2- Check for double definition inside the defining interface */
if (check_method_redefinition (interface, method))
continue;
if (found)
{
char *t;
- tree saved_found_wfl = DECL_NAME (found);
- reset_method_name (found);
t = xstrdup (lang_printable_name (TREE_TYPE (TREE_TYPE (found)), 0));
parse_error_context
- (method_wfl,
+ (DECL_FUNCTION_WFL (found),
"Method `%s' was defined with return type `%s' in class `%s'",
lang_printable_name (found, 0), t,
IDENTIFIER_POINTER
(DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
free (t);
- DECL_NAME (found) = saved_found_wfl;
continue;
}
}
sub_interface_method);
if (found && (found != sub_interface_method))
{
- tree saved_found_wfl = DECL_NAME (found);
- reset_method_name (found);
parse_error_context
(lookup_cl (sub_interface_method),
"Interface `%s' inherits method `%s' from interface `%s'. This method is redefined with a different return type in interface `%s'",
(DECL_CONTEXT (sub_interface_method)))),
IDENTIFIER_POINTER
(DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
- DECL_NAME (found) = saved_found_wfl;
}
}
}
for (import = ctxp->import_list; import; import = TREE_CHAIN (import))
{
tree to_be_found = EXPR_WFL_NODE (TREE_PURPOSE (import));
+ char *original_name;
+
+ obstack_grow0 (&temporary_obstack,
+ IDENTIFIER_POINTER (to_be_found),
+ IDENTIFIER_LENGTH (to_be_found));
+ original_name = obstack_finish (&temporary_obstack);
/* Don't load twice something already defined. */
if (IDENTIFIER_CLASS_VALUE (to_be_found))
{
parse_error_context (TREE_PURPOSE (import),
"Class or interface `%s' not found in import",
- IDENTIFIER_POINTER (to_be_found));
- return 1;
+ original_name);
+ error_found = 1;
}
+
+ obstack_free (&temporary_obstack, original_name);
if (error_found)
return 1;
}
loaded and not seen in source yet, the load */
if (!decl || (!CLASS_LOADED_P (TREE_TYPE (decl))
&& !CLASS_FROM_SOURCE_P (TREE_TYPE (decl))))
- load_class (node_to_use, 0);
+ {
+ load_class (node_to_use, 0);
+ decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
+ }
lineno = saved_lineno;
- return check_pkg_class_access (TYPE_NAME (class_type), cl);
+ if (! INNER_CLASS_P (TREE_TYPE (decl)))
+ return check_pkg_class_access (TYPE_NAME (class_type), cl);
+ else
+ /* 6.6.1: Inner classes are subject to member access rules. */
+ return 0;
}
else
return (seen_once < 0 ? 0 : seen_once); /* It's ok not to have found */
*next = EXPR_WFL_QUALIFICATION (pkg);
- /* Try the current package. */
- if (ctxp->package && !strncmp (name, IDENTIFIER_POINTER (ctxp->package),
- IDENTIFIER_LENGTH (ctxp->package)))
- {
- type_name =
- lookup_package_type_and_set_next (name,
- IDENTIFIER_LENGTH (ctxp->package),
- next );
- if (type_name)
- return type_name;
- }
-
- /* Search in imported package */
- for (current = ctxp->import_list; current; current = TREE_CHAIN (current))
- {
- tree current_pkg_name = EXPR_WFL_NODE (TREE_PURPOSE (current));
- int len = IDENTIFIER_LENGTH (current_pkg_name);
- if (!strncmp (name, IDENTIFIER_POINTER (current_pkg_name), len))
- {
- tree left, dummy;
-
- breakdown_qualified (&left, &dummy, current_pkg_name);
- len = IDENTIFIER_LENGTH (left);
- type_name = lookup_package_type_and_set_next (name, len, next);
- if (type_name)
- break;
- }
- }
-
/* Try to progressively construct a type name */
if (TREE_CODE (pkg) == EXPR_WITH_FILE_LOCATION)
for (acc = NULL_TREE, current = EXPR_WFL_QUALIFICATION (pkg);
}
static tree
-lookup_package_type_and_set_next (name, len, next)
- const char *name;
- int len;
- tree *next;
-{
- const char *ptr;
- tree type_name = lookup_package_type (name, len);
-
- if (!type_name)
- return NULL;
-
- ptr = IDENTIFIER_POINTER (type_name);
- while (ptr && (ptr = strchr (ptr, '.')))
- {
- *next = TREE_CHAIN (*next);
- ptr++;
- }
- return type_name;
-}
-
-static tree
lookup_package_type (name, from)
const char *name;
int from;
return get_identifier (subname);
}
+/* Check accessibility of inner classes according to member access rules.
+ DECL is the inner class, ENCLOSING_DECL is the class from which the
+ access is being attempted. */
+
static void
check_inner_class_access (decl, enclosing_decl, cl)
tree decl, enclosing_decl, cl;
{
- int access = 0;
+ const char *access;
+ tree enclosing_decl_type;
/* We don't issue an error message when CL is null. CL can be null
as a result of processing a JDEP crafted by source_start_java_method
if (!decl || !cl)
return;
- /* We grant access to private and protected inner classes if the
- location from where we're trying to access DECL is an enclosing
- context for DECL or if both have a common enclosing context. */
+ enclosing_decl_type = TREE_TYPE (enclosing_decl);
+
if (CLASS_PRIVATE (decl))
- access = 1;
- if (CLASS_PROTECTED (decl))
- access = 2;
- if (!access)
- return;
+ {
+ /* Access is permitted only within the body of the top-level
+ class in which DECL is declared. */
+ tree top_level = decl;
+ while (DECL_CONTEXT (top_level))
+ top_level = DECL_CONTEXT (top_level);
+ while (DECL_CONTEXT (enclosing_decl))
+ enclosing_decl = DECL_CONTEXT (enclosing_decl);
+ if (top_level == enclosing_decl)
+ return;
+ access = "private";
+ }
+ else if (CLASS_PROTECTED (decl))
+ {
+ tree decl_context;
+ /* Access is permitted from within the same package... */
+ if (in_same_package (decl, enclosing_decl))
+ return;
- if (common_enclosing_context_p (TREE_TYPE (enclosing_decl),
- TREE_TYPE (decl))
- || enclosing_context_p (TREE_TYPE (enclosing_decl),
- TREE_TYPE (decl)))
+ /* ... or from within the body of a subtype of the context in which
+ DECL is declared. */
+ decl_context = DECL_CONTEXT (decl);
+ while (enclosing_decl)
+ {
+ if (CLASS_INTERFACE (decl))
+ {
+ if (interface_of_p (TREE_TYPE (decl_context),
+ enclosing_decl_type))
+ return;
+ }
+ else
+ {
+ /* Eww. The order of the arguments is different!! */
+ if (inherits_from_p (enclosing_decl_type,
+ TREE_TYPE (decl_context)))
+ return;
+ }
+ enclosing_decl = DECL_CONTEXT (enclosing_decl);
+ }
+ access = "protected";
+ }
+ else if (! CLASS_PUBLIC (decl))
+ {
+ /* Access is permitted only from within the same package as DECL. */
+ if (in_same_package (decl, enclosing_decl))
+ return;
+ access = "non-public";
+ }
+ else
+ /* Class is public. */
return;
- parse_error_context (cl, "Can't access %s nested %s %s. Only public classes and interfaces in other packages can be accessed",
- (access == 1 ? "private" : "protected"),
+ parse_error_context (cl, "Nested %s %s is %s; cannot be accessed from here",
(CLASS_INTERFACE (decl) ? "interface" : "class"),
- lang_printable_name (decl, 0));
+ lang_printable_name (decl, 0), access);
}
-/* Check that CLASS_NAME refers to a PUBLIC class. Return 0 if no
- access violations were found, 1 otherwise. */
+/* Accessibility check for top-level classes. If CLASS_NAME is in a foreign
+ package, it must be PUBLIC. Return 0 if no access violations were found,
+ 1 otherwise. */
static int
check_pkg_class_access (class_name, cl)
{
tree type;
- if (!QUALIFIED_P (class_name) || !IDENTIFIER_CLASS_VALUE (class_name))
+ if (!IDENTIFIER_CLASS_VALUE (class_name))
return 0;
if (!(type = TREE_TYPE (IDENTIFIER_CLASS_VALUE (class_name))))
allowed. */
tree l, r;
breakdown_qualified (&l, &r, class_name);
+ if (!QUALIFIED_P (class_name) && !ctxp->package)
+ /* Both in the empty package. */
+ return 0;
if (l == ctxp->package)
+ /* Both in the same package. */
return 0;
parse_error_context
int final_p = 0;
/* Push a new block if statements were seen between the last time we
- pushed a block and now. Keep a cound of block to close */
+ pushed a block and now. Keep a count of blocks to close */
if (BLOCK_EXPR_BODY (GET_CURRENT_BLOCK (current_function_decl)))
{
- tree body = GET_CURRENT_BLOCK (current_function_decl);
tree b = enter_block ();
- BLOCK_EXPR_ORIGIN (b) = body;
+ BLOCK_IS_IMPLICIT (b) = 1;
}
if (modifier)
/* 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 ();
+ /* exit_block modifies DECL_FUNCTION_BODY (current_function_decl).
+ It has to be evaluated first. (if mdecl is current_function_decl,
+ we have an undefined behavior if no temporary variable is used.) */
+ tree b = exit_block ();
+ BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = b;
exit_block ();
}
-/* Called during expansion. Push decls formerly built from argument
- list so they're usable during expansion. */
-
-static void
-expand_start_java_method (fndecl)
- tree fndecl;
-{
- tree tem, *ptr;
-
- current_function_decl = fndecl;
-
- if (! quiet_flag)
- fprintf (stderr, " [%s.", lang_printable_name (DECL_CONTEXT (fndecl), 0));
- announce_function (fndecl);
- if (! quiet_flag)
- fprintf (stderr, "]");
-
- pushlevel (1); /* Prepare for a parameter push */
- ptr = &DECL_ARGUMENTS (fndecl);
- tem = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl));
- while (tem)
- {
- tree next = TREE_CHAIN (tem);
- tree type = TREE_TYPE (tem);
- if (PROMOTE_PROTOTYPES
- && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
- && INTEGRAL_TYPE_P (type))
- type = integer_type_node;
- DECL_ARG_TYPE (tem) = type;
- layout_decl (tem, 0);
- pushdecl (tem);
- *ptr = tem;
- ptr = &TREE_CHAIN (tem);
- tem = next;
- }
- *ptr = NULL_TREE;
- pushdecl_force_head (DECL_ARGUMENTS (fndecl));
- lineno = DECL_SOURCE_LINE_FIRST (fndecl);
-}
-
/* Terminate a function and expand its body. */
static void
source_end_java_method ()
{
tree fndecl = current_function_decl;
- int flag_asynchronous_exceptions = asynchronous_exceptions;
if (!fndecl)
return;
java_parser_context_save_global ();
lineno = ctxp->last_ccb_indent1;
- /* Set EH language codes */
- java_set_exception_lang_code ();
-
/* Turn function bodies with only a NOP expr null, so they don't get
generated at all and we won't get warnings when using the -W
-Wall flags. */
if (! flag_emit_class_files && ! flag_emit_xref)
{
lineno = DECL_SOURCE_LINE_LAST (fndecl);
- /* Emit catch-finally clauses */
- emit_handlers ();
expand_function_end (input_filename, lineno, 0);
- /* FIXME: If the current method contains any exception handlers,
- force asynchronous_exceptions: this is necessary because signal
- handlers in libjava may throw exceptions. This is far from being
- a perfect solution, but it's better than doing nothing at all.*/
- if (catch_clauses)
- asynchronous_exceptions = 1;
-
/* Run the optimizers and output assembler code for this function. */
rest_of_compilation (fndecl);
}
current_function_decl = NULL_TREE;
java_parser_context_restore_global ();
- asynchronous_exceptions = flag_asynchronous_exceptions;
}
/* Record EXPR in the current function block. Complements compound
initialized_p = 1;
}
- for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current))
+ for (current = gclass_list; current; current = TREE_CHAIN (current))
{
current_class = TREE_TYPE (TREE_VALUE (current));
}
}
}
- stop_reordering = TREE_TYPE (TREE_VALUE (ctxp->gclass_list));
+ stop_reordering = TREE_TYPE (TREE_VALUE (gclass_list));
}
-/* Layout the methods of all classes loaded in one way on an
- other. Check methods of source parsed classes. Then reorder the
+/* Layout the methods of all classes loaded in one way or another.
+ Check methods of source parsed classes. Then reorder the
fields and layout the classes or the type of all source parsed
classes */
all_class_list = NULL_TREE;
/* Then check the methods of all parsed classes */
- for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current))
+ for (current = gclass_list; current; current = TREE_CHAIN (current))
if (CLASS_FROM_SOURCE_P (TREE_TYPE (TREE_VALUE (current))))
java_check_methods (TREE_VALUE (current));
java_parse_abort_on_error ();
- for (current = ctxp->gclass_list; current; current = TREE_CHAIN (current))
+ for (current = gclass_list; current; current = TREE_CHAIN (current))
{
current_class = TREE_TYPE (TREE_VALUE (current));
layout_class (current_class);
- /* From now on, the class is considered completely loaded */
- CLASS_LOADED_P (current_class) = 1;
-
/* Error reported by the caller */
if (java_error_count)
return;
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;
}
}
/* Analyzes a method body and look for something that isn't a
- MODIFY_EXPR. */
+ MODIFY_EXPR with a constant value. */
static int
analyze_clinit_body (bbody)
break;
case MODIFY_EXPR:
- bbody = NULL_TREE;
- break;
+ /* Return 0 if the operand is constant, 1 otherwise. */
+ return ! TREE_CONSTANT (TREE_OPERAND (bbody, 1));
default:
- bbody = NULL_TREE;
return 1;
}
return 0;
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 fbody = DECL_FUNCTION_BODY (mdecl);
tree block_body = BLOCK_EXPR_BODY (fbody);
tree exception_copy = NULL_TREE;
- expand_start_java_method (mdecl);
+ tree tem, *ptr;
+
+ current_function_decl = mdecl;
+
+ if (! quiet_flag)
+ fprintf (stderr, " [%s.",
+ lang_printable_name (DECL_CONTEXT (mdecl), 0));
+ announce_function (mdecl);
+ if (! quiet_flag)
+ fprintf (stderr, "]");
+
+ pushlevel (1); /* Prepare for a parameter push */
+ ptr = &DECL_ARGUMENTS (mdecl);
+ tem = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl));
+ while (tem)
+ {
+ tree next = TREE_CHAIN (tem);
+ tree type = TREE_TYPE (tem);
+ if (PROMOTE_PROTOTYPES
+ && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
+ && INTEGRAL_TYPE_P (type))
+ type = integer_type_node;
+ DECL_ARG_TYPE (tem) = type;
+ layout_decl (tem, 0);
+ pushdecl (tem);
+ *ptr = tem;
+ ptr = &TREE_CHAIN (tem);
+ tem = next;
+ }
+ *ptr = NULL_TREE;
+ pushdecl_force_head (DECL_ARGUMENTS (mdecl));
+ lineno = DECL_SOURCE_LINE_FIRST (mdecl);
+
build_result_decl (mdecl);
current_this
/* Pop the exceptions and sanity check */
POP_EXCEPTIONS();
if (currently_caught_type_list)
- fatal ("Exception list non empty - java_complete_expand_method");
+ abort ();
if (flag_emit_xref)
DECL_FUNCTION_THROWS (mdecl) = exception_copy;
{
tree access = NULL_TREE;
tree ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
+ tree decl_ctx = DECL_CONTEXT (decl);
- /* If decl's class is the direct outer class of the current_class,
- build the access as `this$<n>.<field>'. Note that we will break
- the `private' barrier if we're not emitting bytecodes. */
- if (ctx == DECL_CONTEXT (decl)
+ /* If the immediate enclosing context of the current class is the
+ field decl's class or inherits from it; build the access as
+ `this$<n>.<field>'. Note that we will break the `private' barrier
+ if we're not emitting bytecodes. */
+ if ((ctx == decl_ctx || inherits_from_p (ctx, decl_ctx))
&& (!FIELD_PRIVATE (decl) || !flag_emit_class_files ))
{
tree thisn = build_current_thisn (current_class);
/* Now we chain the required number of calls to the access$0 to
get a hold to the enclosing instance we need, and then we
build the field access. */
- access = build_access_to_thisn (current_class, DECL_CONTEXT (decl), lc);
+ access = build_access_to_thisn (current_class, decl_ctx, lc);
/* If the field is private and we're generating bytecode, then
we generate an access method */
if (FIELD_PRIVATE (decl) && flag_emit_class_files )
{
tree name = build_outer_field_access_methods (decl);
- access = build_outer_field_access_expr (lc, DECL_CONTEXT (decl),
+ access = build_outer_field_access_expr (lc, decl_ctx,
name, access, NULL_TREE);
}
/* Otherwise we use `access$(this$<j>). ... access$(this$<i>).<field>'.
|| TREE_CODE (decl) != FIELD_DECL
|| DECL_CONTEXT (decl) == type)
return 0;
+
+ /* If the inner class extends the declaration context of the field
+ we're try to acces, then this isn't an outer field access */
+ if (inherits_from_p (type, DECL_CONTEXT (decl)))
+ return 0;
for (type = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))); ;
type = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type))))
{
if (type == DECL_CONTEXT (decl))
return 1;
+
if (!DECL_CONTEXT (TYPE_NAME (type)))
- break;
+ {
+ /* Before we give up, see whether the field is inherited from
+ the enclosing context we're considering. */
+ if (inherits_from_p (type, DECL_CONTEXT (decl)))
+ return 1;
+ break;
+ }
}
return 0;
{
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 */
access = build_method_invocation (access0_wfl, access);
access = make_qualified_primary (cn, access, lc);
}
-
- from = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (from)));
+
+ /* if FROM isn't an inter class, that's fine, we've done
+ enough. What we're looking for can be accessed from there. */
+ from = DECL_CONTEXT (TYPE_NAME (from));
+ if (!from)
+ break;
+ from = TREE_TYPE (from);
}
return access;
}
/* If TYPE is a top-level class, no access method is required.
If there already is such an access method, bail out. */
- if (CLASS_ACCESS0_GENERATED_P (type) || !INNER_CLASS_TYPE_P (type))
+ if (CLASS_ACCESS0_GENERATED_P (type) || !PURE_INNER_CLASS_TYPE_P (type))
return NULL_TREE;
/* We generate the method. The method looks like:
/* Create the "class$" function */
mdecl = create_artificial_method (class, ACC_STATIC,
build_pointer_type (class_type_node),
- get_identifier ("class$"), args);
+ classdollar_identifier_node, args);
DECL_FUNCTION_THROWS (mdecl) = build_tree_list (NULL_TREE,
no_class_def_found_error);
/* We initialize the variable with the exception handler. */
catch = build (MODIFY_EXPR, NULL_TREE, catch_clause_param,
- soft_exceptioninfo_call_node);
+ build (JAVA_EXC_OBJ_EXPR, ptr_type_node));
add_stmt_to_block (catch_block, NULL_TREE, catch);
/* We add the statement throwing the new exception */
s = build_string (IDENTIFIER_LENGTH (sig_id),
IDENTIFIER_POINTER (sig_id));
- return build_method_invocation (build_wfl_node (get_identifier ("class$")),
+ return build_method_invocation (build_wfl_node (classdollar_identifier_node),
build_tree_list (NULL_TREE, s));
}
tree thisn_assign, compound = NULL_TREE;
tree class_type = DECL_CONTEXT (mdecl);
+ if (DECL_FIXED_CONSTRUCTOR_P (mdecl))
+ return;
+ DECL_FIXED_CONSTRUCTOR_P (mdecl) = 1;
+
if (!body)
{
/* It is an error for the compiler to generate a default
/* We don't generate a super constructor invocation if we're
compiling java.lang.Object. build_super_invocation takes care
of that. */
- compound = java_method_add_stmt (mdecl, build_super_invocation (mdecl));
+ java_method_add_stmt (mdecl, build_super_invocation (mdecl));
/* Insert the instance initializer block right here, after the
super invocation. */
else
{
int found = 0;
+ tree found_call = NULL_TREE;
tree main_block = BLOCK_EXPR_BODY (body);
+ tree ii; /* Instance Initializer */
while (body)
switch (TREE_CODE (body))
break;
case COMPOUND_EXPR:
case EXPR_WITH_FILE_LOCATION:
+ found_call = body;
body = TREE_OPERAND (body, 0);
break;
case BLOCK:
+ found_call = body;
body = BLOCK_EXPR_BODY (body);
break;
default:
found = 0;
body = NULL_TREE;
}
+
+ /* Generate the assignment to this$<n>, if necessary */
+ if ((thisn_assign = build_thisn_assign ()))
+ compound = add_stmt_to_compound (compound, NULL_TREE, thisn_assign);
+
/* The constructor is missing an invocation of super() */
if (!found)
compound = add_stmt_to_compound (compound, NULL_TREE,
build_super_invocation (mdecl));
+ /* Explicit super() invokation should take place before the
+ instance initializer blocks. */
+ else
+ {
+ compound = add_stmt_to_compound (compound, NULL_TREE,
+ TREE_OPERAND (found_call, 0));
+ TREE_OPERAND (found_call, 0) = empty_stmt_node;
+ }
- /* Generate the assignment to this$<n>, if necessary */
- if ((thisn_assign = build_thisn_assign ()))
- compound = add_stmt_to_compound (compound, NULL_TREE, thisn_assign);
-
- /* Insert the instance initializer block right here, after the
- super invocation. */
- add_instance_initializer (mdecl);
+ /* Insert the instance initializer block right after. */
+ if ((ii = build_instance_initializer (mdecl)))
+ compound = add_stmt_to_compound (compound, NULL_TREE, ii);
/* Fix the constructor main block if we're adding extra stmts */
if (compound)
java_expand_classes ()
{
int save_error_count = 0;
- static struct parser_ctxt *saved_ctxp = NULL;
+ static struct parser_ctxt *cur_ctxp = NULL;
java_parse_abort_on_error ();
if (!(ctxp = ctxp_for_generation))
java_layout_classes ();
java_parse_abort_on_error ();
- saved_ctxp = ctxp_for_generation;
- for (; ctxp_for_generation; ctxp_for_generation = ctxp_for_generation->next)
+ cur_ctxp = ctxp_for_generation;
+ for (; cur_ctxp; cur_ctxp = cur_ctxp->next)
{
- ctxp = ctxp_for_generation;
+ ctxp = cur_ctxp;
+ input_filename = ctxp->filename;
lang_init_source (2); /* Error msgs have method prototypes */
java_complete_expand_classes (); /* Complete and expand classes */
java_parse_abort_on_error ();
}
+ input_filename = main_input_filename;
/* Find anonymous classes and expand their constructor, now they
have been fixed. */
- for (ctxp_for_generation = saved_ctxp;
- ctxp_for_generation; ctxp_for_generation = ctxp_for_generation->next)
+ for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
{
tree current;
- ctxp = ctxp_for_generation;
+ ctxp = cur_ctxp;
for (current = ctxp->class_list; current; current = TREE_CHAIN (current))
{
current_class = TREE_TYPE (current);
if (DECL_CONSTRUCTOR_P (d))
{
restore_line_number_status (1);
- reset_method_name (d);
java_complete_expand_method (d);
restore_line_number_status (0);
break; /* We now there are no other ones */
return;
/* Now things are stable, go for generation of the class data. */
- for (ctxp_for_generation = saved_ctxp;
- ctxp_for_generation; ctxp_for_generation = ctxp_for_generation->next)
+ for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
{
tree current;
- ctxp = ctxp_for_generation;
+ ctxp = cur_ctxp;
for (current = ctxp->class_list; current; current = TREE_CHAIN (current))
{
current_class = TREE_TYPE (current);
if (!TREE_CHAIN (q))
{
if (!previous)
- fatal ("Operating on a non qualified qualified WFL - cut_identifier_in_qualified");
+ /* Operating on a non qualified qualified WFL. */
+ abort ();
+
TREE_CHAIN (previous) = NULL_TREE;
return TREE_PURPOSE (q);
}
}
/* Instance variables can't appear as an argument of
an explicit constructor invocation */
- if (!fs && ctxp->explicit_constructor_p)
+ if (!fs && ctxp->explicit_constructor_p
+ && !enclosing_context_p (DECL_CONTEXT (decl), current_class))
{
parse_error_context
(id, "Can't reference `%s' before the superclass constructor has been called", IDENTIFIER_POINTER (name));
to access a field belonging to an outer class, build
the access to the field */
if (!fs && outer_field_access_p (current_class, decl))
- return build_outer_field_access (id, decl);
+ {
+ if (CLASS_STATIC (TYPE_NAME (current_class)))
+ {
+ static_ref_err (id, DECL_NAME (decl), current_class);
+ return error_mark_node;
+ }
+ return build_outer_field_access (id, decl);
+ }
/* Otherwise build what it takes to access the field */
access = build_field_ref ((fs ? NULL_TREE : current_this),
DECL_CONTEXT (decl), name);
- if (fs && !flag_emit_class_files && !flag_emit_xref)
- access = build_class_init (DECL_CONTEXT (access), access);
+ if (fs)
+ access = maybe_build_class_init_for_field (decl, access);
/* We may be asked to save the real field access node */
if (orig)
*orig = access;
&& ! flag_emit_class_files && ! flag_emit_xref)
{
tree length = build_java_array_length_access (where_found);
- field_ref =
- build_java_arraynull_check (type_found, length, int_type_node);
+ field_ref = length;
/* In case we're dealing with a static array, we need to
initialize its class before the array length can be fetched.
field_ref = decl;
else if (JDECL_P (decl))
{
- int static_final_found = 0;
if (!type_found)
type_found = DECL_CONTEXT (decl);
- is_static = JDECL_P (decl) && FIELD_STATIC (decl);
- if (FIELD_FINAL (decl) && FIELD_STATIC (decl)
- && JPRIMITIVE_TYPE_P (TREE_TYPE (decl))
- && DECL_INITIAL (decl))
- {
- /* When called on a FIELD_DECL of the right (primitive)
- type, java_complete_tree will try to substitue the decl
- for it's initial value. */
- field_ref = java_complete_tree (decl);
- static_final_found = 1;
- }
- else
- field_ref = build_field_ref ((is_static && !flag_emit_xref?
- NULL_TREE : where_found),
- type_found, DECL_NAME (decl));
+ is_static = FIELD_STATIC (decl);
+ field_ref = build_field_ref ((is_static && !flag_emit_xref?
+ NULL_TREE : where_found),
+ type_found, DECL_NAME (decl));
if (field_ref == error_mark_node)
return error_mark_node;
- if (is_static && !static_final_found
- && !flag_emit_class_files && !flag_emit_xref)
- field_ref = build_class_init (DECL_CONTEXT (decl), field_ref);
+ if (is_static)
+ field_ref = maybe_build_class_init_for_field (decl, field_ref);
}
else
field_ref = decl;
CALL_USING_SUPER (qual_wfl) = 1;
location = (TREE_CODE (qual_wfl) == CALL_EXPR ?
EXPR_WFL_LINECOL (TREE_OPERAND (qual_wfl, 0)) : 0);
- *where_found = patch_method_invocation (qual_wfl, decl, type,
+ *where_found = patch_method_invocation (qual_wfl, decl, type,
+ from_super,
&is_static, &ret_decl);
if (*where_found == error_mark_node)
{
if (decl == error_mark_node)
return 1;
*type_found = type = QUAL_DECL_TYPE (decl);
- CLASS_LOADED_P (type) = 1;
continue;
case CONVERT_EXPR:
previous_call_static = 0;
/* It can be the keyword THIS */
- if (EXPR_WFL_NODE (qual_wfl) == this_identifier_node)
+ if (TREE_CODE (qual_wfl) == EXPR_WITH_FILE_LOCATION
+ && EXPR_WFL_NODE (qual_wfl) == this_identifier_node)
{
if (!current_this)
{
(wfl, "Keyword `this' used outside allowed context");
return 1;
}
- if (ctxp->explicit_constructor_p)
+ if (ctxp->explicit_constructor_p
+ && type == current_class)
{
parse_error_context (wfl, "Can't reference `this' before the superclass constructor has been called");
return 1;
}
/* 15.10.2 Accessing Superclass Members using SUPER */
- if (EXPR_WFL_NODE (qual_wfl) == super_identifier_node)
+ if (TREE_CODE (qual_wfl) == EXPR_WITH_FILE_LOCATION
+ && EXPR_WFL_NODE (qual_wfl) == super_identifier_node)
{
tree node;
/* Check on the restricted use of SUPER */
return 1;
}
- if (not_accessible_p (TREE_TYPE (decl), decl, 0))
+ if (not_accessible_p (TREE_TYPE (decl), decl, type, 0))
{
parse_error_context
(qual_wfl, "Can't access %s field `%s.%s' from `%s'",
field_decl = lookup_field_wrapper (type,
EXPR_WFL_NODE (qual_wfl));
- /* Maybe what we're trying to access an inner class. */
- if (!field_decl)
+ /* Maybe what we're trying to access to is an inner
+ class, only if decl is a TYPE_DECL. */
+ if (!field_decl && TREE_CODE (decl) == TYPE_DECL)
{
tree ptr, inner_decl;
&& !CLASS_LOADED_P (field_decl_type)
&& !TYPE_ARRAY_P (field_decl_type))
resolve_and_layout (field_decl_type, NULL_TREE);
- if (TYPE_ARRAY_P (field_decl_type))
- CLASS_LOADED_P (field_decl_type) = 1;
/* Check on accessibility here */
- if (not_accessible_p (type, field_decl, from_super))
+ if (not_accessible_p (current_class, field_decl,
+ DECL_CONTEXT (field_decl), from_super))
{
parse_error_context
(qual_wfl,
}
/* 6.6 Qualified name and access control. Returns 1 if MEMBER (a decl)
- can't be accessed from REFERENCE (a record type). This should be
- used when decl is a field or a method.*/
+ can't be accessed from REFERENCE (a record type). If MEMBER
+ features a protected access, we then use WHERE which, if non null,
+ holds the type of MEMBER's access that is checked against
+ 6.6.2.1. This function should be used when decl is a field or a
+ method. */
static int
-not_accessible_p (reference, member, from_super)
+not_accessible_p (reference, member, where, from_super)
tree reference, member;
+ tree where;
int from_super;
{
int access_flag = get_access_flags_from_decl (member);
if (from_super)
return 0;
+ /* If where is active, access was made through a
+ qualifier. Access is granted if the type of the qualifier is
+ or is a sublass of the type the access made from (6.6.2.1.) */
+ if (where && !inherits_from_p (reference, where))
+ return 1;
+
/* Otherwise, access is granted if occuring from the class where
member is declared or a subclass of it. Find the right
context to perform the check */
}
/* Check access on private members. Access is granted only if it
- occurs from within the class in which it is declared. Exceptions
- are accesses from inner-classes. */
+ occurs from within the class in which it is declared -- that does
+ it for innerclasses too. */
if (access_flag & ACC_PRIVATE)
- return (current_class == DECL_CONTEXT (member) ? 0 :
- (INNER_CLASS_TYPE_P (current_class) ? 0 : 1));
+ {
+ if (reference == DECL_CONTEXT (member))
+ return 0;
+ if (enclosing_context_p (reference, DECL_CONTEXT (member)))
+ return 0;
+ return 1;
+ }
/* Default access are permitted only when occuring within the
package in which the type (REFERENCE) is declared. In other words,
strcpy (the, "class");
break;
default:
- fatal ("unexpected DECL code - check_deprecation");
+ abort ();
}
parse_warning_context
(wfl, "The %s `%s' in class `%s' has been deprecated",
used. IS_STATIC is set to 1 if the invoked function is static. */
static tree
-patch_method_invocation (patch, primary, where, is_static, ret_decl)
+patch_method_invocation (patch, primary, where, from_super,
+ is_static, ret_decl)
tree patch, primary, where;
+ int from_super;
int *is_static;
tree *ret_decl;
{
int is_static_flag = 0;
int is_super_init = 0;
tree this_arg = NULL_TREE;
+ int is_array_clone_call = 0;
/* Should be overriden if everything goes well. Otherwise, if
something fails, it should keep this value. It stop the
else
this_arg = primary = resolved;
+ if (TYPE_ARRAY_P (type) && identifier == get_identifier ("clone"))
+ is_array_clone_call = 1;
+
/* IDENTIFIER_WFL will be used to report any problem further */
wfl = identifier_wfl;
}
alternate class is specified. */
else
{
- class_to_search = (where ? where : current_class);
+ if (where != NULL_TREE)
+ class_to_search = where;
+ else if (QUALIFIED_P (name))
+ class_to_search = current_class;
+ else
+ {
+ class_to_search = current_class;
+
+ for (;;)
+ {
+ if (has_method (class_to_search, name))
+ break;
+ if (! INNER_CLASS_TYPE_P (class_to_search))
+ {
+ parse_error_context (wfl,
+ "No method named `%s' in scope",
+ IDENTIFIER_POINTER (name));
+ PATCH_METHOD_RETURN_ERROR ();
+ }
+ class_to_search
+ = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (class_to_search)));
+ }
+ }
lc = 0;
}
can't be executed then. */
if (!list)
PATCH_METHOD_RETURN_ERROR ();
+
+ if (TYPE_ARRAY_P (class_to_search)
+ && DECL_NAME (list) == get_identifier ("clone"))
+ is_array_clone_call = 1;
/* Check for static reference if non static methods */
if (check_for_static_method_reference (wfl, patch, list,
/* Check accessibility, position the is_static flag, build and
return the call */
- if (not_accessible_p (DECL_CONTEXT (current_function_decl), list, 0))
- {
- char *fct_name = xstrdup (lang_printable_name (list, 0));
- parse_error_context
- (wfl, "Can't access %s method `%s %s.%s' from `%s'",
- java_accstring_lookup (get_access_flags_from_decl (list)),
- lang_printable_name (TREE_TYPE (TREE_TYPE (list)), 0),
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (list)))),
- fct_name, IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))));
- free (fct_name);
+ if (not_accessible_p (DECL_CONTEXT (current_function_decl), list,
+ (primary ? TREE_TYPE (TREE_TYPE (primary)) :
+ NULL_TREE), from_super)
+ /* Calls to clone() on array types are permitted as a special-case. */
+ && !is_array_clone_call)
+ {
+ const char *fct_name = IDENTIFIER_POINTER (DECL_NAME (list));
+ const char *access =
+ java_accstring_lookup (get_access_flags_from_decl (list));
+ const char *klass =
+ IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (list))));
+ const char *refklass =
+ IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)));
+ const char *what = (DECL_CONSTRUCTOR_P (list)
+ ? "constructor" : "method");
+ /* FIXME: WFL yields the wrong message here but I don't know
+ what else to use. */
+ parse_error_context (wfl,
+ "Can't access %s %s `%s.%s' from `%s'",
+ access, what, klass, fct_name, refklass);
PATCH_METHOD_RETURN_ERROR ();
}
check_deprecation (wfl, list);
/* Secretly pass the current_this/primary as a second argument */
if (primary || current_this)
- args = tree_cons (NULL_TREE, (primary ? primary : current_this), args);
+ {
+ tree extra_arg;
+ tree this_type = (current_this ?
+ TREE_TYPE (TREE_TYPE (current_this)) : NULL_TREE);
+ /* Method's (list) enclosing context */
+ tree mec = DECL_CONTEXT (TYPE_NAME (DECL_CONTEXT (list)));
+ /* If we have a primary, use it. */
+ if (primary)
+ extra_arg = primary;
+ /* The current `this' is an inner class but isn't a direct
+ enclosing context for the inner class we're trying to
+ create. Build an access to the proper enclosing context
+ and use it. */
+ else if (current_this && PURE_INNER_CLASS_TYPE_P (this_type)
+ && this_type != TREE_TYPE (mec))
+ {
+
+ extra_arg = build_access_to_thisn (current_class,
+ TREE_TYPE (mec), 0);
+ extra_arg = java_complete_tree (extra_arg);
+ }
+ /* Otherwise, just use the current `this' as an enclosing
+ context. */
+ else
+ extra_arg = current_this;
+ args = tree_cons (NULL_TREE, extra_arg, args);
+ }
else
args = tree_cons (NULL_TREE, integer_zero_node, args);
}
/* Prepare to pass hidden parameters to finit$, if any. */
finit_parms = build_alias_initializer_parameter_list
(AIPL_FUNCTION_FINIT_INVOCATION, current_class, NULL_TREE, NULL);
-
+
finit_call =
build_method_invocation (build_wfl_node (finit_identifier_node),
finit_parms);
{
tree dtable, func;
tree original_call, t, ta;
- tree cond = NULL_TREE;
+ tree check = NULL_TREE;
/* Last step for args: convert build-in types. If we're dealing with
a new TYPE() type call, the first argument to the constructor
optimization pass to eliminate redundant checks. */
if (TREE_VALUE (args) != current_this)
{
- /* We use a SAVE_EXPR here to make sure we only evaluate
+ /* We use a save_expr here to make sure we only evaluate
the new `self' expression once. */
tree save_arg = save_expr (TREE_VALUE (args));
TREE_VALUE (args) = save_arg;
- cond = build (EQ_EXPR, boolean_type_node, save_arg,
- null_pointer_node);
+ check = java_check_reference (save_arg, 1);
}
/* Fall through. */
break;
default:
- fatal ("internal error - unknown invocation_mode result");
+ abort ();
}
/* Ensure self_type is initialized, (invokestatic). FIXME */
patch = build (COMPOUND_EXPR, TREE_TYPE (new), patch, saved_new);
}
- /* If COND is set, then we are building a check to see if the object
+ /* If CHECK is set, then we are building a check to see if the object
is NULL. */
- if (cond != NULL_TREE)
- {
- /* We have to make the `then' branch a compound expression to
- make the types turn out right. This seems bizarre. */
- patch = build (COND_EXPR, TREE_TYPE (patch), cond,
- build (COMPOUND_EXPR, TREE_TYPE (patch),
- build (CALL_EXPR, void_type_node,
- build_address_of (soft_nullpointer_node),
- NULL_TREE, NULL_TREE),
- (FLOAT_TYPE_P (TREE_TYPE (patch))
- ? build_real (TREE_TYPE (patch), dconst0)
- : build1 (CONVERT_EXPR, TREE_TYPE (patch),
- integer_zero_node))),
- patch);
+ if (check != NULL_TREE)
+ {
+ patch = build (COMPOUND_EXPR, TREE_TYPE (patch), check, patch);
TREE_SIDE_EFFECTS (patch) = 1;
}
{
tree cm = TREE_VALUE (current);
char string [4096];
- if (!cm || not_accessible_p (class, cm, 0))
+ if (!cm || not_accessible_p (class, cm, NULL_TREE, 0))
continue;
sprintf
(string, " `%s' in `%s'%s",
/* Search classes */
else
{
- tree sc = class;
- int seen_inner_class = 0;
search_applicable_methods_list (lc, TYPE_METHODS (class),
name, arglist, &list, &all_list);
+ /* When looking finit$ or class$, we turn LC to 1 so that we
+ only search in class. Note that we should have found
+ something at this point. */
+ if (ID_FINIT_P (name) || ID_CLASSDOLLAR_P (name))
+ {
+ lc = 1;
+ if (!list)
+ abort ();
+ }
+
/* We must search all interfaces of this class */
if (!lc)
{
- tree basetype_vec = TYPE_BINFO_BASETYPES (sc);
+ tree basetype_vec = TYPE_BINFO_BASETYPES (class);
int n = TREE_VEC_LENGTH (basetype_vec), i;
for (i = 1; i < n; i++)
{
}
}
- /* Search enclosing context of inner classes before looking
- ancestors up. */
- while (!lc && INNER_CLASS_TYPE_P (class))
- {
- tree rlist;
- seen_inner_class = 1;
- class = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (class)));
- rlist = find_applicable_accessible_methods_list (lc, class,
- name, arglist);
- list = chainon (rlist, list);
- }
-
- if (!lc && seen_inner_class
- && TREE_TYPE (DECL_CONTEXT (TYPE_NAME (sc))) == CLASSTYPE_SUPER (sc))
- class = CLASSTYPE_SUPER (sc);
- else
- class = sc;
-
/* Search superclass */
if (!lc && CLASSTYPE_SUPER (class) != NULL_TREE)
{
if (lc && !DECL_CONSTRUCTOR_P (method))
continue;
else if (!lc && (DECL_CONSTRUCTOR_P (method)
- || (GET_METHOD_NAME (method) != name)))
+ || (DECL_NAME (method) != name)))
continue;
-
+
if (argument_types_convertible (method, arglist))
{
/* Retain accessible methods only */
if (!not_accessible_p (DECL_CONTEXT (current_function_decl),
- method, 0))
+ method, NULL_TREE, 0))
*list = tree_cons (NULL_TREE, method, *list);
else
/* Also retain all selected method here */
else if (code == INTEGER_CST)
name = qual_wfl;
+ else if (code == CONVERT_EXPR &&
+ TREE_CODE (TREE_OPERAND (qual_wfl, 0)) == EXPR_WITH_FILE_LOCATION)
+ name = TREE_OPERAND (qual_wfl, 0);
+
else if ((code == ARRAY_REF || code == CALL_EXPR || code == MODIFY_EXPR) &&
TREE_CODE (TREE_OPERAND (qual_wfl, 0)) == EXPR_WITH_FILE_LOCATION)
name = EXPR_WFL_NODE (TREE_OPERAND (qual_wfl, 0));
qual_wfl = QUAL_WFL (qual);
again = 1;
}
- else
+ else
{
name = EXPR_WFL_NODE (qual_wfl);
if (!name)
qual_wfl = QUAL_WFL (qual);
if (TREE_CODE (qual_wfl) == CALL_EXPR)
again = 1;
- else
+ else if (TREE_CODE (qual_wfl) == EXPR_WITH_FILE_LOCATION)
name = EXPR_WFL_NODE (qual_wfl);
+ else if (TREE_CODE (qual_wfl) == NEW_CLASS_EXPR)
+ name = TREE_OPERAND (qual_wfl, 0);
this_found = 1;
}
/* If we have a SUPER, we set the context accordingly */
expression name. If we saw a NEW_ARRAY_EXPR before and want to
address length, it is OK. */
else if ((decl = lookup_field_wrapper (ptr_type, name))
- || (new_array_found && name == length_identifier_node))
+ || name == length_identifier_node)
{
RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
QUAL_RESOLUTION (qual) = (new_array_found ? NULL_TREE : decl);
/* Method call, array references and cast are expression name */
else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR
|| TREE_CODE (QUAL_WFL (qual)) == ARRAY_REF
- || TREE_CODE (QUAL_WFL (qual)) == CONVERT_EXPR)
+ || TREE_CODE (QUAL_WFL (qual)) == CONVERT_EXPR
+ || TREE_CODE (QUAL_WFL (qual)) == MODIFY_EXPR)
RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
/* Check here that NAME isn't declared by more than one
return 0;
}
+/* Return TRUE if two classes are from the same package. */
+
+static int
+in_same_package (name1, name2)
+ tree name1, name2;
+{
+ tree tmp;
+ tree pkg1;
+ tree pkg2;
+
+ if (TREE_CODE (name1) == TYPE_DECL)
+ name1 = DECL_NAME (name1);
+ if (TREE_CODE (name2) == TYPE_DECL)
+ name2 = DECL_NAME (name2);
+
+ if (QUALIFIED_P (name1) != QUALIFIED_P (name2))
+ /* One in empty package. */
+ return 0;
+
+ if (QUALIFIED_P (name1) == 0 && QUALIFIED_P (name2) == 0)
+ /* Both in empty package. */
+ return 1;
+
+ breakdown_qualified (&pkg1, &tmp, name1);
+ breakdown_qualified (&pkg2, &tmp, name2);
+
+ return (pkg1 == pkg2);
+}
+
/* Patch tree nodes in a function body. When a BLOCK is found, push
local variable decls if present.
Same as java_complete_lhs, but does resolve static finals to values. */
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;
}
case TRY_FINALLY_EXPR:
COMPLETE_CHECK_OP_0 (node);
COMPLETE_CHECK_OP_1 (node);
+ if (TREE_OPERAND (node, 0) == empty_stmt_node)
+ return TREE_OPERAND (node, 1);
+ if (TREE_OPERAND (node, 1) == empty_stmt_node)
+ return TREE_OPERAND (node, 0);
CAN_COMPLETE_NORMALLY (node)
= (CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0))
&& CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1)));
EXPR_WFL_NODE (node) = body;
TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (body);
CAN_COMPLETE_NORMALLY (node) = CAN_COMPLETE_NORMALLY (body);
- if (body == empty_stmt_node)
+ if (body == empty_stmt_node || TREE_CONSTANT (body))
{
- /* Optimization; makes it easier to detect empty bodies. */
+ /* Makes it easier to constant fold, detect empty bodies. */
return body;
}
if (body == error_mark_node)
{
tree decl, wfl = TREE_OPERAND (node, 0);
int in_this = CALL_THIS_CONSTRUCTOR_P (node);
+ int from_super = (EXPR_WFL_NODE (TREE_OPERAND (node, 0)) ==
+ super_identifier_node);
- node = patch_method_invocation (node, NULL_TREE,
- NULL_TREE, 0, &decl);
+ node = patch_method_invocation (node, NULL_TREE, NULL_TREE,
+ from_super, 0, &decl);
if (node == error_mark_node)
return error_mark_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);
class. TESTME, FIXME */
tree lvalue = java_stabilize_reference (TREE_OPERAND (node, 0));
- /* Hand stablize the lhs on both places */
+ /* Hand stabilize the lhs on both places */
TREE_OPERAND (node, 0) = lvalue;
TREE_OPERAND (TREE_OPERAND (node, 1), 0) =
(flag_emit_class_files ? lvalue : save_expr (lvalue));
nn = java_complete_tree (build_cast (EXPR_WFL_LINECOL (wfl_op2),
TREE_TYPE (lvalue), nn));
+ /* If the assignment is compound and has reference type,
+ then ensure the LHS has type String and nothing else. */
+ if (JREFERENCE_TYPE_P (TREE_TYPE (lvalue))
+ && ! JSTRING_TYPE_P (TREE_TYPE (lvalue)))
+ parse_error_context (wfl_op2,
+ "Incompatible type for `+='. Can't convert `%s' to `java.lang.String'",
+ lang_printable_name (TREE_TYPE (lvalue), 0));
+
/* 15.25.2.b: Left hand is an array access. FIXME */
}
return field;
}
else
- fatal ("unimplemented java_complete_tree for COMPONENT_REF");
+ abort ();
break;
case THIS_EXPR:
if ((nn = patch_string (node)))
node = nn;
else
- fatal ("No case for tree code `%s' - java_complete_tree\n",
- tree_code_name [TREE_CODE (node)]);
+ internal_error ("No case for %s", tree_code_name [TREE_CODE (node)]);
}
return node;
}
static tree
enter_block ()
{
- return (enter_a_block (build_expr_block (NULL_TREE, NULL_TREE)));
-}
+ tree b = build_expr_block (NULL_TREE, NULL_TREE);
-/* Link block B supercontext to the previous block. The current
- function DECL is used as supercontext when enter_a_block is called
- for the first time for a given function. The current function body
- (DECL_FUNCTION_BODY) is set to be block B. */
+ /* Link block B supercontext to the previous block. The current
+ function DECL is used as supercontext when enter_a_block is called
+ for the first time for a given function. The current function body
+ (DECL_FUNCTION_BODY) is set to be block B. */
-static tree
-enter_a_block (b)
- tree b;
-{
tree fndecl = current_function_decl;
if (!fndecl) {
/* Paranoid sanity check. To be removed */
if (TREE_CODE (b) != BLOCK)
- fatal ("non block expr function body - lookup_name_in_blocks");
+ abort ();
for (current = BLOCK_EXPR_DECLS (b); current;
current = TREE_CHAIN (current))
static void
maybe_absorb_scoping_blocks ()
{
- while (BLOCK_EXPR_ORIGIN (GET_CURRENT_BLOCK (current_function_decl)))
+ while (BLOCK_IS_IMPLICIT (GET_CURRENT_BLOCK (current_function_decl)))
{
tree b = exit_block ();
java_method_add_stmt (current_function_decl, b);
are completing them. */
/* Wrap a non WFL node around a WFL. */
+
static tree
build_wfl_wrap (node, location)
tree node;
return wfl;
}
-
/* Build a super() constructor invocation. Returns empty_stmt_node if
we're currently dealing with the class java.lang.Object. */
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 been 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)
+ abort ();
+ 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
if (TREE_CODE (n) == VAR_DECL
&& DECL_NAME (n) == TYPE_identifier_node
&& rhs_type == class_ptr_type
+ && TREE_CODE (wfl) == EXPR_WITH_FILE_LOCATION
&& TREE_CODE (EXPR_WFL_NODE (wfl)) == IDENTIFIER_NODE)
{
const char *self_name = IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl));
tree check;
tree base = lvalue;
- /* We need to retrieve the right argument for _Jv_CheckArrayStore */
+ /* We need to retrieve the right argument for
+ _Jv_CheckArrayStore. This is somewhat complicated by bounds
+ and null pointer checks, both of which wrap the operand in
+ one layer of COMPOUND_EXPR. */
if (TREE_CODE (lvalue) == COMPOUND_EXPR)
base = TREE_OPERAND (lvalue, 0);
else
{
- if (flag_bounds_check)
- base = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (base, 0), 1), 0);
- else
- base = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
+ tree op = TREE_OPERAND (base, 0);
+
+ /* We can have a SAVE_EXPR here when doing String +=. */
+ if (TREE_CODE (op) == SAVE_EXPR)
+ op = TREE_OPERAND (op, 0);
+ if (flag_bounds_check)
+ base = TREE_OPERAND (TREE_OPERAND (op, 1), 0);
+ else
+ base = TREE_OPERAND (op, 0);
}
/* Build the invocation of _Jv_CheckArrayStore */
TREE_OPERAND (lvalue, 1) = build (COMPOUND_EXPR, lhs_type,
check, TREE_OPERAND (lvalue, 1));
}
- else
+ else if (flag_bounds_check)
{
+ tree hook = lvalue;
+ tree compound = TREE_OPERAND (lvalue, 0);
+ tree bound_check, new_compound;
+
+ if (TREE_CODE (compound) == SAVE_EXPR)
+ {
+ compound = TREE_OPERAND (compound, 0);
+ hook = TREE_OPERAND (hook, 0);
+ }
+
+ /* Find the array bound check, hook the original array access. */
+ bound_check = TREE_OPERAND (compound, 0);
+ TREE_OPERAND (hook, 0) = TREE_OPERAND (compound, 1);
+
/* Make sure the bound check will happen before the store check */
- if (flag_bounds_check)
- TREE_OPERAND (TREE_OPERAND (lvalue, 0), 0) =
- build (COMPOUND_EXPR, void_type_node,
- TREE_OPERAND (TREE_OPERAND (lvalue, 0), 0), check);
- else
- lvalue = build (COMPOUND_EXPR, lhs_type, check, lvalue);
- }
+ new_compound =
+ build (COMPOUND_EXPR, void_type_node, bound_check, check);
+
+ /* Re-assemble the augmented array access. */
+ lvalue = build (COMPOUND_EXPR, lhs_type, new_compound, lvalue);
+ }
+ else
+ lvalue = build (COMPOUND_EXPR, lhs_type, check, lvalue);
}
/* 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))
else if (valid_ref_assignconv_cast_p (rhs_type, lhs_type, 0))
new_rhs = rhs;
/* This is a magic assignment that we process differently */
- else if (rhs == soft_exceptioninfo_call_node)
+ else if (TREE_CODE (rhs) == JAVA_EXC_OBJ_EXPR)
new_rhs = rhs;
}
return new_rhs;
source = TREE_TYPE (source);
if (TREE_CODE (dest) == POINTER_TYPE)
dest = TREE_TYPE (dest);
+
+ /* If source and dest are being compiled from bytecode, they may need to
+ be loaded. */
+ if (CLASS_P (source) && !CLASS_LOADED_P (source))
+ {
+ load_class (source, 1);
+ safe_layout_class (source);
+ }
+ if (CLASS_P (dest) && !CLASS_LOADED_P (dest))
+ {
+ load_class (dest, 1);
+ safe_layout_class (dest);
+ }
+
/* Case where SOURCE is a class type */
if (TYPE_CLASS_P (source))
{
case PREDECREMENT_EXPR: /* Fall through */
case POSTDECREMENT_EXPR: BUILD_OPERATOR_STRING ("--");
default:
- fatal ("unregistered operator %s - operator_string",
- tree_code_name [TREE_CODE (node)]);
+ internal_error ("unregistered operator %s",
+ tree_code_name [TREE_CODE (node)]);
}
return NULL;
#undef BUILD_OPERATOR_STRING
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
+ /* If either op<n>_type are NULL, this might be early signs of an
+ error situation, unless it's too early to tell (in case we're
+ handling a `+', `==', `!=' or `instanceof'.) We want to set op<n>_type
+ correctly so the error can be later on reported accurately. */
+ if (! (code == PLUS_EXPR || code == NE_EXPR
+ || code == EQ_EXPR || code == INSTANCEOF_EXPR))
+ {
+ tree n;
+ if (! op1_type)
+ {
+ n = java_complete_tree (op1);
+ op1_type = TREE_TYPE (n);
+ }
+ if (! op2_type)
+ {
+ n = java_complete_tree (op2);
+ op2_type = TREE_TYPE (n);
+ }
+ }
+
switch (code)
{
/* 15.16 Multiplicative operators */
case MINUS_TK: op = NEGATE_EXPR; break;
case NEG_TK: op = TRUTH_NOT_EXPR; break;
case NOT_TK: op = BIT_NOT_EXPR; break;
- default: fatal ("Unknown token `%d' for unary operator - build_unaryop",
- op_token);
+ default: abort ();
}
unaryop = build1 (op, NULL_TREE, op1);
if (!flag_emit_class_files || JPRIMITIVE_TYPE_P (ref_type))
{
+ tree dot = build_class_ref (ref_type);
/* A class referenced by `foo.class' is initialized. */
- return build_class_init (ref_type, build_class_ref (ref_type));
+ if (!flag_emit_class_files)
+ dot = build_class_init (ref_type, dot);
+ return java_complete_tree (dot);
}
/* If we're emitting class files and we have to deal with non
{
if (unresolved_type_p (type, NULL))
{
- tree type_decl = resolve_no_layout (EXPR_WFL_NODE (type), type);
+ tree type_decl = resolve_and_layout (EXPR_WFL_NODE (type), type);
if (!type_decl)
{
parse_error_context (type,
IDENTIFIER_POINTER (EXPR_WFL_NODE (type)));
return NULL_TREE;
}
- else
- {
- CLASS_LOADED_P (TREE_TYPE (type_decl)) = 1;
- return TREE_TYPE (type_decl);
- }
+ return TREE_TYPE (type_decl);
}
return type;
}
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)))
{
return node;
}
+/* Wrap EXPR with code to initialize DECL's class, if appropriate. */
+
+static tree
+maybe_build_class_init_for_field (decl, expr)
+ tree decl, expr;
+{
+ tree clas = DECL_CONTEXT (decl);
+ if (flag_emit_class_files || flag_emit_xref)
+ return expr;
+
+ if (TREE_CODE (decl) == VAR_DECL && FIELD_STATIC (decl)
+ && FIELD_FINAL (decl))
+ {
+ tree init = DECL_INITIAL (decl);
+ if (init != NULL_TREE)
+ init = fold_constant_for_init (init, decl);
+ if (init != NULL_TREE && CONSTANT_VALUE_P (init))
+ return expr;
+ }
+
+ return build_class_init (clas, expr);
+}
+
/* Try to constant fold NODE.
If NODE is not a constant expression, return NULL_EXPR.
CONTEXT is a static final VAR_DECL whose initializer we are folding. */
tree op0, op1, val;
enum tree_code code = TREE_CODE (node);
- if (code == STRING_CST || code == INTEGER_CST || code == REAL_CST)
- return node;
-
switch (code)
{
+ case STRING_CST:
+ case INTEGER_CST:
+ case REAL_CST:
+ return node;
+
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_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:
ggc_mark_tree (pc->class_type);
ggc_mark_tree (pc->function_decl);
ggc_mark_tree (pc->package);
- ggc_mark_tree (pc->incomplete_class);
- ggc_mark_tree (pc->gclass_list);
ggc_mark_tree (pc->class_list);
ggc_mark_tree (pc->current_parsed_class);
ggc_mark_tree (pc->current_parsed_class_un);
if (pc->next)
mark_parser_ctxt (&pc->next);
}
+
+void
+init_src_parse ()
+{
+ /* Register roots with the garbage collector. */
+ ggc_add_tree_root (src_parse_roots, sizeof (src_parse_roots) / sizeof(tree));
+}