aboutsummaryrefslogtreecommitdiff
path: root/gcc/java/parse.y
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2003-08-12 20:34:51 +0000
committerTom Tromey <tromey@gcc.gnu.org>2003-08-12 20:34:51 +0000
commitaecf41099bac0258050c052bdc1892e8b4a5d145 (patch)
treeb0eccc2bad8dc4ad0fc0c2540ee347467640fdec /gcc/java/parse.y
parentb9172475adce3fec9e36fe6b98eeedba31c0d1f0 (diff)
downloadgcc-aecf41099bac0258050c052bdc1892e8b4a5d145.zip
gcc-aecf41099bac0258050c052bdc1892e8b4a5d145.tar.gz
gcc-aecf41099bac0258050c052bdc1892e8b4a5d145.tar.bz2
parse.y (java_check_regular_methods): Typo fixes.
* parse.y (java_check_regular_methods): Typo fixes. Call check_interface_throws_clauses. Use check_concrete_throws_clauses. (check_interface_throws_clauses): New function. (check_concrete_throws_clauses): New function. (hack_is_accessible_p): New function. (find_most_specific_methods_list): Added FIXME. * typeck.c (lookup_do): Use `flags' argument to decide what to do. Reimplemented. (lookup_argument_method_generic): New function. (lookup_argument_method2): Removed. * jcf.h (ACC_INVISIBLE): New define. * jcf-write.c (generate_classfile): Skip invisible methods. * class.c (add_miranda_methods): New function. (layout_class_methods): Use it. (get_access_flags_from_decl): Use ACC_INVISIBLE. * java-tree.h (METHOD_INVISIBLE): New define. (lang_decl_func) [invisible]: New field. (lookup_argument_method_generic): Declare. (SEARCH_INTERFACE): New define. (SEARCH_SUPER): Likewise. (SEARCH_ONLY_INTERFACE): Likewise. (SEARCH_VISIBLE): Likewise. (lookup_argument_method2): Removed declaration. From-SVN: r70388
Diffstat (limited to 'gcc/java/parse.y')
-rw-r--r--gcc/java/parse.y156
1 files changed, 134 insertions, 22 deletions
diff --git a/gcc/java/parse.y b/gcc/java/parse.y
index 6ca734a..a9f8d6e 100644
--- a/gcc/java/parse.y
+++ b/gcc/java/parse.y
@@ -224,6 +224,7 @@ static void check_thrown_exceptions (int, tree, tree);
static int check_thrown_exceptions_do (tree);
static void purge_unchecked_exceptions (tree);
static bool ctors_unchecked_throws_clause_p (tree);
+static void check_concrete_throws_clauses (tree, tree, tree, tree);
static void check_throws_clauses (tree, tree, tree);
static void finish_method_declaration (tree);
static tree build_super_invocation (tree);
@@ -244,7 +245,9 @@ static void start_artificial_method_body (tree);
static void end_artificial_method_body (tree);
static int check_method_redefinition (tree, tree);
static int check_method_types_complete (tree);
+static bool hack_is_accessible_p (tree, tree);
static void java_check_regular_methods (tree);
+static void check_interface_throws_clauses (tree, tree);
static void java_check_abstract_methods (tree);
static void unreachable_stmt_error (tree);
static tree find_expr_with_wfl (tree);
@@ -6244,11 +6247,35 @@ java_check_methods (tree class_decl)
CLASS_METHOD_CHECKED_P (TREE_TYPE (class_decl)) = 1;
}
+/* Like not_accessible_p, but doesn't refer to the current class at
+ all. */
+static bool
+hack_is_accessible_p (tree member, tree from_where)
+{
+ int flags = get_access_flags_from_decl (member);
+
+ if (from_where == DECL_CONTEXT (member)
+ || (flags & ACC_PUBLIC))
+ return true;
+
+ if ((flags & ACC_PROTECTED))
+ {
+ if (inherits_from_p (from_where, DECL_CONTEXT (member)))
+ return true;
+ }
+
+ if ((flags & ACC_PRIVATE))
+ return false;
+
+ /* Package private, or protected. */
+ return in_same_package (TYPE_NAME (from_where),
+ TYPE_NAME (DECL_CONTEXT (member)));
+}
+
/* Check all the methods of CLASS_DECL. Methods are first completed
then checked according to regular method existence rules. If no
constructor for CLASS_DECL were encountered, then build its
declaration. */
-
static void
java_check_regular_methods (tree class_decl)
{
@@ -6298,7 +6325,8 @@ java_check_regular_methods (tree class_decl)
}
sig = build_java_argument_signature (TREE_TYPE (method));
- found = lookup_argument_method2 (class, DECL_NAME (method), sig);
+ found = lookup_argument_method_generic (class, DECL_NAME (method), sig,
+ SEARCH_SUPER | SEARCH_INTERFACE);
/* Inner class can't declare static methods */
if (METHOD_STATIC (method) && !TOPLEVEL_CLASS_DECL_P (class_decl))
@@ -6357,7 +6385,7 @@ java_check_regular_methods (tree class_decl)
continue;
parse_error_context
(method_wfl,
- "%s methods can't be overriden. Method `%s' is %s in class `%s'",
+ "%s methods can't be overridden. Method `%s' is %s in class `%s'",
(METHOD_FINAL (found) ? "Final" : "Static"),
lang_printable_name (found, 0),
(METHOD_FINAL (found) ? "final" : "static"),
@@ -6371,7 +6399,7 @@ java_check_regular_methods (tree class_decl)
{
parse_error_context
(method_wfl,
- "Instance methods can't be overriden by a static method. Method `%s' is an instance method in class `%s'",
+ "Instance methods can't be overridden by a static method. Method `%s' is an instance method in class `%s'",
lang_printable_name (found, 0),
IDENTIFIER_POINTER
(DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
@@ -6380,7 +6408,7 @@ java_check_regular_methods (tree class_decl)
/* - Overriding/hiding public must be public
- Overriding/hiding protected must be protected or public
- - If the overriden or hidden method has default (package)
+ - If the overridden or hidden method has default (package)
access, then the overriding or hiding method must not be
private; otherwise, a compile-time error occurs. If
`found' belongs to an interface, things have been already
@@ -6402,13 +6430,20 @@ java_check_regular_methods (tree class_decl)
continue;
}
- /* Overriding methods must have compatible `throws' clauses on checked
- exceptions, if any */
- check_throws_clauses (method, method_wfl, found);
-
- /* Inheriting multiple methods with the same signature. FIXME */
+ /* Check this method against all the other implementations it
+ overrides. Here we only check the class hierarchy; the rest
+ of the checking is done later. If this method is just a
+ Miranda method, we can skip the check. */
+ if (! METHOD_INVISIBLE (method))
+ check_concrete_throws_clauses (class, method, DECL_NAME (method), sig);
}
+ /* The above throws clause check only looked at superclasses. Now
+ we must also make sure that all methods declared in interfaces
+ have compatible throws clauses. FIXME: there are more efficient
+ ways to organize this checking; we should implement one. */
+ check_interface_throws_clauses (class, class);
+
if (!TYPE_NVIRTUALS (class))
TYPE_METHODS (class) = nreverse (TYPE_METHODS (class));
@@ -6420,13 +6455,83 @@ java_check_regular_methods (tree class_decl)
abort ();
}
-/* Return a nonzero value if the `throws' clause of METHOD (if any)
- is incompatible with the `throws' clause of FOUND (if any). */
+/* Check to make sure that all the methods in all the interfaces
+ implemented by CLASS_DECL are compatible with the concrete
+ implementations available in CHECK_CLASS_DECL. */
+static void
+check_interface_throws_clauses (tree check_class_decl, tree class_decl)
+{
+ for (; class_decl != NULL_TREE; class_decl = CLASSTYPE_SUPER (class_decl))
+ {
+ tree bases = TYPE_BINFO_BASETYPES (class_decl);
+ int iface_len = TREE_VEC_LENGTH (bases) - 1;
+ int i;
+
+ for (i = iface_len; i > 0; --i)
+ {
+ tree interface = BINFO_TYPE (TREE_VEC_ELT (bases, i));
+ tree iface_method;
+ for (iface_method = TYPE_METHODS (interface);
+ iface_method != NULL_TREE;
+ iface_method = TREE_CHAIN (iface_method))
+ {
+ tree sig, method;
+
+ /* First look for a concrete method implemented or
+ inherited by this class. No need to search
+ interfaces here, since we're already looking through
+ all of them. */
+ sig = build_java_argument_signature (TREE_TYPE (iface_method));
+ method
+ = lookup_argument_method_generic (check_class_decl,
+ DECL_NAME (iface_method),
+ sig, SEARCH_VISIBLE);
+ /* If we don't find an implementation, that is ok. Any
+ potential errors from that are diagnosed elsewhere.
+ Also, multiple inheritance with conflicting throws
+ clauses is fine in the absence of a concrete
+ implementation. */
+ if (method != NULL_TREE && !METHOD_ABSTRACT (method))
+ {
+ tree method_wfl = DECL_FUNCTION_WFL (method);
+ check_throws_clauses (method, method_wfl, iface_method);
+ }
+ }
+
+ /* Now check superinterfaces. */
+ check_interface_throws_clauses (check_class_decl, interface);
+ }
+ }
+}
+
+/* Check throws clauses of a method against the clauses of all the
+ methods it overrides. We do this by searching up the class
+ hierarchy, examining all matching accessible methods. */
+static void
+check_concrete_throws_clauses (tree class, tree self_method,
+ tree name, tree signature)
+{
+ tree method = lookup_argument_method_generic (class, name, signature,
+ SEARCH_SUPER | SEARCH_VISIBLE);
+ while (method != NULL_TREE)
+ {
+ if (! METHOD_INVISIBLE (method) && hack_is_accessible_p (method, class))
+ check_throws_clauses (self_method, DECL_FUNCTION_WFL (self_method),
+ method);
+
+ method = lookup_argument_method_generic (DECL_CONTEXT (method),
+ name, signature,
+ SEARCH_SUPER | SEARCH_VISIBLE);
+ }
+}
+
+/* Generate an error if the `throws' clause of METHOD (if any) is
+ incompatible with the `throws' clause of FOUND (if any). */
static void
check_throws_clauses (tree method, tree method_wfl, tree found)
{
- tree mthrows, fthrows;
+ tree mthrows;
/* Can't check these things with class loaded from bytecode. FIXME */
if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (found)))
@@ -6435,28 +6540,31 @@ check_throws_clauses (tree method, tree method_wfl, tree found)
for (mthrows = DECL_FUNCTION_THROWS (method);
mthrows; mthrows = TREE_CHAIN (mthrows))
{
+ tree fthrows;
+
/* We don't verify unchecked expressions */
if (IS_UNCHECKED_EXCEPTION_P (TREE_VALUE (mthrows)))
continue;
/* Checked expression must be compatible */
for (fthrows = DECL_FUNCTION_THROWS (found);
fthrows; fthrows = TREE_CHAIN (fthrows))
- if (inherits_from_p (TREE_VALUE (mthrows), TREE_VALUE (fthrows)))
- break;
+ {
+ if (inherits_from_p (TREE_VALUE (mthrows), TREE_VALUE (fthrows)))
+ break;
+ }
if (!fthrows)
{
parse_error_context
- (method_wfl, "Invalid checked exception class `%s' in `throws' clause. The exception must be a subclass of an exception thrown by `%s' from class `%s'",
+ (method_wfl, "Invalid checked exception class `%s' in `throws' clause. The exception must be a subclass of an exception thrown by `%s' from class `%s'",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (TREE_VALUE (mthrows)))),
lang_printable_name (found, 0),
IDENTIFIER_POINTER
- (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
+ (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))));
}
}
}
/* Check abstract method of interface INTERFACE */
-
static void
java_check_abstract_methods (tree interface_decl)
{
@@ -6470,8 +6578,7 @@ java_check_abstract_methods (tree interface_decl)
if (check_method_redefinition (interface, method))
continue;
- /* 3- Overriding is OK as far as we preserve the return type and
- the thrown exceptions (FIXME) */
+ /* 3- Overriding is OK as far as we preserve the return type. */
found = lookup_java_interface_method2 (interface, method);
if (found)
{
@@ -10100,7 +10207,7 @@ patch_method_invocation (tree patch, tree primary, tree where, int from_super,
tree this_arg = NULL_TREE;
int is_array_clone_call = 0;
- /* Should be overriden if everything goes well. Otherwise, if
+ /* Should be overridden if everything goes well. Otherwise, if
something fails, it should keep this value. It stop the
evaluation of a bogus assignment. See java_complete_tree,
MODIFY_EXPR: for the reasons why we sometimes want to keep on
@@ -11057,10 +11164,15 @@ find_most_specific_methods_list (tree list)
/* If we have several and they're all abstract, just pick the
closest one. */
- if (candidates > 0 && (candidates == abstract))
+ if (candidates > 0 && candidates == abstract)
{
+ /* FIXME: merge the throws clauses. There is no convenient way
+ to do this in gcj right now, since ideally we'd like to
+ introduce a new METHOD_DECL here, but that is really not
+ possible. */
new_list = nreverse (new_list);
TREE_CHAIN (new_list) = NULL_TREE;
+ return new_list;
}
/* We have several (we couldn't find a most specific), all but one