diff options
author | Tom Tromey <tromey@redhat.com> | 2003-08-12 20:34:51 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2003-08-12 20:34:51 +0000 |
commit | aecf41099bac0258050c052bdc1892e8b4a5d145 (patch) | |
tree | b0eccc2bad8dc4ad0fc0c2540ee347467640fdec /gcc/java/parse.y | |
parent | b9172475adce3fec9e36fe6b98eeedba31c0d1f0 (diff) | |
download | gcc-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.y | 156 |
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 |