X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fjava%2Ftypeck.c;h=1024b7a4de9ee744cf898bb68fb5227a8284c5db;hp=d52d7fdebc1a22aa04a011be926f6e4880afbed0;hb=f639fdbff97b434f0ee9d6d2f03b6c5483efbed2;hpb=5ce13bce4c31cc84cc6952e360335c714250e2be diff --git a/gcc/java/typeck.c b/gcc/java/typeck.c index d52d7fdebc1..1024b7a4de9 100644 --- a/gcc/java/typeck.c +++ b/gcc/java/typeck.c @@ -1,22 +1,22 @@ /* Handle types for the GNU compiler for the Java(TM) language. - Copyright (C) 1996, 97-98, 1999 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2007, 2008 + Free Software Foundation, Inc. -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify +GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. -GNU CC is distributed in the hope that it will be useful, +GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. +along with GCC; see the file COPYING3. If not see +. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. @@ -26,28 +26,36 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "tree.h" +#include "real.h" #include "obstack.h" #include "flags.h" #include "java-tree.h" #include "jcf.h" #include "convert.h" #include "toplev.h" +#include "ggc.h" + +static tree convert_ieee_real_to_integer (tree, tree); +static tree parse_signature_type (const unsigned char **, + const unsigned char *); +static tree lookup_do (tree, int, tree, tree, tree (*)(tree)); +static tree build_null_signature (tree); tree * type_map; -extern struct obstack permanent_obstack; /* Set the type of the local variable with index SLOT to TYPE. */ void -set_local_type (slot, type) - int slot; - tree type; +set_local_type (int slot, tree type) { int max_locals = DECL_MAX_LOCALS(current_function_decl); int nslots = TYPE_IS_WIDE (type) ? 2 : 1; - if (slot < 0 || slot + nslots - 1 >= max_locals) - fatal ("invalid local variable index"); + + gcc_assert (slot >= 0 && (slot + nslots - 1 < max_locals)); + type_map[slot] = type; while (--nslots > 0) type_map[++slot] = void_type_node; @@ -55,24 +63,44 @@ set_local_type (slot, type) /* Convert an IEEE real to an integer type. The result of such a conversion when the source operand is a NaN isn't defined by - IEEE754, but by the Java language standard: it must be zero. This - conversion produces something like: - - ({ double tmp = expr; (tmp != tmp) ? 0 : (int)tmp; }) - - */ + IEEE754, but by the Java language standard: it must be zero. Also, + overflows must be clipped to within range. This conversion + produces something like: + + ((expr >= (float)MAX_INT) + ? MAX_INT + : ((expr <= (float)MIN_INT) + ? MIN_INT + : ((expr != expr) + ? 0 + : (int)expr))) */ static tree -convert_ieee_real_to_integer (type, expr) - tree type, expr; +convert_ieee_real_to_integer (tree type, tree expr) { - tree assignment, expr_decl; + tree result; expr = save_expr (expr); - return build (COND_EXPR, type, - build (NE_EXPR, boolean_type_node, expr, expr), - convert (type, integer_zero_node), - convert_to_integer (type, expr)); + result = fold_build3 (COND_EXPR, type, + fold_build2 (NE_EXPR, boolean_type_node, expr, expr), + convert (type, integer_zero_node), + convert_to_integer (type, expr)); + + result = fold_build3 (COND_EXPR, type, + fold_build2 (LE_EXPR, boolean_type_node, expr, + convert (TREE_TYPE (expr), + TYPE_MIN_VALUE (type))), + TYPE_MIN_VALUE (type), + result); + + result = fold_build3 (COND_EXPR, type, + fold_build2 (GE_EXPR, boolean_type_node, expr, + convert (TREE_TYPE (expr), + TYPE_MAX_VALUE (type))), + TYPE_MAX_VALUE (type), + result); + + return result; } /* Create an expression whose value is that of EXPR, @@ -82,10 +110,12 @@ convert_ieee_real_to_integer (type, expr) not permitted by the language being compiled. */ tree -convert (type, expr) - tree type, expr; +convert (tree type, tree expr) { - register enum tree_code code = TREE_CODE (type); + enum tree_code code = TREE_CODE (type); + + if (!expr) + return error_mark_node; if (type == TREE_TYPE (expr) || TREE_CODE (expr) == ERROR_MARK) @@ -95,24 +125,27 @@ convert (type, expr) if (code == VOID_TYPE) return build1 (CONVERT_EXPR, type, expr); if (code == BOOLEAN_TYPE) - return fold (convert_to_boolean (type, expr)); + return fold_convert (type, expr); if (code == INTEGER_TYPE) { - if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE -#ifdef TARGET_SOFT_FLOAT - && !TARGET_SOFT_FLOAT -#endif - && !flag_emit_class_files - && !flag_fast_math - && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT) - return fold (convert_ieee_real_to_integer (type, expr)); + if (type == char_type_node || type == promoted_char_type_node) + return fold_convert (type, expr); + if ((really_constant_p (expr) || ! flag_unsafe_math_optimizations) + && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) + return convert_ieee_real_to_integer (type, expr); else - return fold (convert_to_integer (type, expr)); + { + /* fold very helpfully sets the overflow status if a type + overflows in a narrowing integer conversion, but Java + doesn't care. */ + tree tmp = fold (convert_to_integer (type, expr)); + if (TREE_CODE (tmp) == INTEGER_CST) + TREE_OVERFLOW (tmp) = 0; + return tmp; + } } if (code == REAL_TYPE) return fold (convert_to_real (type, expr)); - if (code == CHAR_TYPE) - return fold (convert_to_char (type, expr)); if (code == POINTER_TYPE) return fold (convert_to_pointer (type, expr)); error ("conversion to non-scalar type requested"); @@ -120,40 +153,12 @@ convert (type, expr) } -tree -convert_to_char (type, expr) - tree type, expr; -{ - return build1 (NOP_EXPR, type, expr); -} - -tree -convert_to_boolean (type, expr) - tree type, expr; -{ - return build1 (NOP_EXPR, type, expr); -} - -/* Print an error message for invalid use of an incomplete type. - VALUE is the expression that was used (or 0 if that isn't known) - and TYPE is the type that was invalid. */ - -void -incomplete_type_error (value, type) - tree value ATTRIBUTE_UNUSED; - tree type ATTRIBUTE_UNUSED; -{ - error ("internal error - use of undefined type"); -} - /* Return a data type that has machine mode MODE. If the mode is an integer, then UNSIGNEDP selects between signed and unsigned types. */ tree -type_for_mode (mode, unsignedp) - enum machine_mode mode; - int unsignedp; +java_type_for_mode (enum machine_mode mode, int unsignedp) { if (mode == TYPE_MODE (int_type_node)) return unsignedp ? unsigned_int_type_node : int_type_node; @@ -175,9 +180,7 @@ type_for_mode (mode, unsignedp) that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ tree -type_for_size (bits, unsignedp) - unsigned bits; - int unsignedp; +java_type_for_size (unsigned bits, int unsignedp) { if (bits <= TYPE_PRECISION (byte_type_node)) return unsignedp ? unsigned_byte_type_node : byte_type_node; @@ -190,117 +193,10 @@ type_for_size (bits, unsignedp) return 0; } -/* Return a type the same as TYPE except unsigned or - signed according to UNSIGNEDP. */ - -tree -signed_or_unsigned_type (unsignedp, type) - int unsignedp; - tree type; -{ - if (! INTEGRAL_TYPE_P (type)) - return type; - if (TYPE_PRECISION (type) == TYPE_PRECISION (int_type_node)) - return unsignedp ? unsigned_int_type_node : int_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (byte_type_node)) - return unsignedp ? unsigned_byte_type_node : byte_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (short_type_node)) - return unsignedp ? unsigned_short_type_node : short_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (long_type_node)) - return unsignedp ? unsigned_long_type_node : long_type_node; - return type; -} - -/* Return a signed type the same as TYPE in other respects. */ - -tree -signed_type (type) - tree type; -{ - return signed_or_unsigned_type (0, type); -} - -/* Return an unsigned type the same as TYPE in other respects. */ - -tree -unsigned_type (type) - tree type; -{ - return signed_or_unsigned_type (1, type); - -} - -/* Mark EXP saying that we need to be able to take the - address of it; it should not be allocated in a register. - Value is 1 if successful. */ - -int -mark_addressable (exp) - tree exp; -{ - register tree x = exp; - while (1) - switch (TREE_CODE (x)) - { - case ADDR_EXPR: - case COMPONENT_REF: - case ARRAY_REF: - case REALPART_EXPR: - case IMAGPART_EXPR: - x = TREE_OPERAND (x, 0); - break; - - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case COMPOUND_EXPR: - x = TREE_OPERAND (x, 1); - break; - - case COND_EXPR: - return mark_addressable (TREE_OPERAND (x, 1)) - & mark_addressable (TREE_OPERAND (x, 2)); - - case CONSTRUCTOR: - TREE_ADDRESSABLE (x) = 1; - return 1; - - case INDIRECT_REF: - /* We sometimes add a cast *(TYPE*)&FOO to handle type and mode - incompatibility problems. Handle this case by marking FOO. */ - if (TREE_CODE (TREE_OPERAND (x, 0)) == NOP_EXPR - && TREE_CODE (TREE_OPERAND (TREE_OPERAND (x, 0), 0)) == ADDR_EXPR) - { - x = TREE_OPERAND (TREE_OPERAND (x, 0), 0); - break; - } - if (TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR) - { - x = TREE_OPERAND (x, 0); - break; - } - return 1; - - case VAR_DECL: - case CONST_DECL: - case PARM_DECL: - case RESULT_DECL: - case FUNCTION_DECL: - TREE_ADDRESSABLE (x) = 1; -#if 0 /* poplevel deals with this now. */ - if (DECL_CONTEXT (x) == 0) - TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; -#endif - /* drops through */ - default: - return 1; - } -} - /* Thorough checking of the arrayness of TYPE. */ int -is_array_type_p (type) - tree type; +is_array_type_p (tree type) { return TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE @@ -311,8 +207,7 @@ is_array_type_p (type) Return -1 if the length is unknown or non-constant. */ HOST_WIDE_INT -java_array_type_length (array_type) - tree array_type; +java_array_type_length (tree array_type) { tree arfld; if (TREE_CODE (array_type) == POINTER_TYPE) @@ -321,21 +216,32 @@ java_array_type_length (array_type) if (arfld != NULL_TREE) { tree index_type = TYPE_DOMAIN (TREE_TYPE (arfld)); - tree high = TYPE_MAX_VALUE (index_type); - if (TREE_CODE (high) == INTEGER_CST) - return TREE_INT_CST_LOW (high) + 1; + if (index_type != NULL_TREE) + { + tree high = TYPE_MAX_VALUE (index_type); + if (TREE_CODE (high) == INTEGER_CST) + return TREE_INT_CST_LOW (high) + 1; + } } return -1; } +/* An array of unknown length will be ultimately given a length of + -2, so that we can still have `length' producing a negative value + even if found. This was part of an optimization aiming at removing + `length' from static arrays. We could restore it, FIXME. */ + tree -build_prim_array_type (element_type, length) - tree element_type; - HOST_WIDE_INT length; +build_prim_array_type (tree element_type, HOST_WIDE_INT length) { - tree max_index = build_int_2 (length - 1, 0); - TREE_TYPE (max_index) = sizetype; - return build_array_type (element_type, build_index_type (max_index)); + tree index = NULL; + + if (length != -1) + { + tree max_index = build_int_cst (sizetype, length - 1); + index = build_index_type (max_index); + } + return build_array_type (element_type, index); } /* Return a Java array type with a given ELEMENT_TYPE and LENGTH. @@ -343,15 +249,17 @@ build_prim_array_type (element_type, length) The LENGTH is -1 if the length is unknown. */ tree -build_java_array_type (element_type, length) - tree element_type; - HOST_WIDE_INT length; +build_java_array_type (tree element_type, HOST_WIDE_INT length) { - tree sig, t, fld; - char buf[12]; + tree sig, t, fld, atype, arfld; + char buf[23]; tree elsig = build_java_signature (element_type); tree el_name = element_type; - sprintf (buf, length >= 0 ? "[%d" : "[", length); + buf[0] = '['; + if (length >= 0) + sprintf (buf+1, HOST_WIDE_INT_PRINT_DEC, length); + else + buf[1] = '\0'; sig = ident_subst (IDENTIFIER_POINTER (elsig), IDENTIFIER_LENGTH (elsig), buf, 0, 0, ""); t = IDENTIFIER_SIGNATURE_TYPE (sig); @@ -366,7 +274,19 @@ build_java_array_type (element_type, length) el_name = TYPE_NAME (el_name); if (TREE_CODE (el_name) == TYPE_DECL) el_name = DECL_NAME (el_name); - TYPE_NAME (t) = identifier_subst (el_name, "", '.', '.', "[]"); + { + char suffix[23]; + if (length >= 0) + sprintf (suffix, "[%d]", (int)length); + else + strcpy (suffix, "[]"); + TYPE_NAME (t) + = TYPE_STUB_DECL (t) + = build_decl (input_location, TYPE_DECL, + identifier_subst (el_name, "", '.', '.', suffix), + t); + TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (t)) = true; + } set_java_signature (t, sig); set_super_info (0, t, object_type_node, 0); @@ -375,23 +295,20 @@ build_java_array_type (element_type, length) TYPE_ARRAY_ELEMENT (t) = element_type; /* Add length pseudo-field. */ - push_obstacks (&permanent_obstack, &permanent_obstack); - fld = build_decl (FIELD_DECL, get_identifier ("length"), int_type_node); + fld = build_decl (input_location, + FIELD_DECL, get_identifier ("length"), int_type_node); TYPE_FIELDS (t) = fld; DECL_CONTEXT (fld) = t; FIELD_PUBLIC (fld) = 1; FIELD_FINAL (fld) = 1; + TREE_READONLY (fld) = 1; - if (length >= 0) - { - tree atype = build_prim_array_type (element_type, length); - tree arfld = build_decl (FIELD_DECL, get_identifier ("data"), atype); - DECL_CONTEXT (arfld) = t; - TREE_CHAIN (fld) = arfld; - } - else - TYPE_ALIGN (t) = TYPE_ALIGN (element_type); - pop_obstacks (); + atype = build_prim_array_type (element_type, length); + arfld = build_decl (input_location, + FIELD_DECL, get_identifier ("data"), atype); + DECL_CONTEXT (arfld) = t; + TREE_CHAIN (fld) = arfld; + DECL_ALIGN (arfld) = TYPE_ALIGN (element_type); /* We could layout_class, but that loads java.lang.Object prematurely. * This is called by the parser, and it is a bad idea to do load_class @@ -405,22 +322,19 @@ build_java_array_type (element_type, length) /* Promote TYPE to the type actually used for fields and parameters. */ tree -promote_type (type) - tree type; +promote_type (tree type) { switch (TREE_CODE (type)) { case RECORD_TYPE: - return build_pointer_type (CLASS_TO_HANDLE_TYPE (type)); + return build_pointer_type (type); case BOOLEAN_TYPE: if (type == boolean_type_node) return promoted_boolean_type_node; goto handle_int; - case CHAR_TYPE: + case INTEGER_TYPE: if (type == char_type_node) return promoted_char_type_node; - goto handle_int; - case INTEGER_TYPE: handle_int: if (TYPE_PRECISION (type) < TYPE_PRECISION (int_type_node)) { @@ -440,13 +354,12 @@ promote_type (type) Return the seen TREE_TYPE, updating *PTR. */ static tree -parse_signature_type (ptr, limit) - const unsigned char **ptr, *limit; +parse_signature_type (const unsigned char **ptr, const unsigned char *limit) { tree type; - if ((*ptr) >= limit) - fatal ("bad signature string"); - switch (*(*ptr)) + gcc_assert (*ptr < limit); + + switch (**ptr) { case 'B': (*ptr)++; return byte_type_node; case 'C': (*ptr)++; return char_type_node; @@ -465,20 +378,19 @@ parse_signature_type (ptr, limit) case 'L': { const unsigned char *start = ++(*ptr); - register const unsigned char *str = start; + const unsigned char *str = start; for ( ; ; str++) { - if (str >= limit) - fatal ("bad signature string"); + gcc_assert (str < limit); if (*str == ';') break; } *ptr = str+1; - type = lookup_class (unmangle_classname (start, str - start)); + type = lookup_class (unmangle_classname ((const char *) start, str - start)); break; } default: - fatal ("unrecognized signature string"); + gcc_unreachable (); } return promote_type (type); } @@ -488,15 +400,12 @@ parse_signature_type (ptr, limit) Return a gcc type node. */ tree -parse_signature_string (sig_string, sig_length) - const unsigned char *sig_string; - int sig_length; +parse_signature_string (const unsigned char *sig_string, int sig_length) { tree result_type; const unsigned char *str = sig_string; const unsigned char *limit = str + sig_length; - push_obstacks (&permanent_obstack, &permanent_obstack); if (str < limit && str[0] == '(') { tree argtype_list = NULL_TREE; @@ -507,7 +416,7 @@ parse_signature_string (sig_string, sig_length) argtype_list = tree_cons (NULL_TREE, argtype, argtype_list); } if (str++, str >= limit) - fatal ("bad signature string"); + abort (); result_type = parse_signature_type (&str, limit); argtype_list = chainon (nreverse (argtype_list), end_params_node); result_type = build_function_type (result_type, argtype_list); @@ -516,7 +425,6 @@ parse_signature_string (sig_string, sig_length) result_type = parse_signature_type (&str, limit); if (str != limit) error ("junk at end of signature string"); - pop_obstacks (); return result_type; } @@ -527,7 +435,7 @@ parse_signature_string (sig_string, sig_length) tree get_type_from_signature (tree signature) { - unsigned char *sig = (unsigned char *) IDENTIFIER_POINTER (signature); + const unsigned char *sig = (const unsigned char *) IDENTIFIER_POINTER (signature); int len = IDENTIFIER_LENGTH (signature); tree type; /* Primitive types aren't cached. */ @@ -542,11 +450,18 @@ get_type_from_signature (tree signature) return type; } +/* Ignore signature and always return null. Used by has_method. */ + +static tree +build_null_signature (tree type ATTRIBUTE_UNUSED) +{ + return NULL_TREE; +} + /* Return the signature string for the arguments of method type TYPE. */ tree -build_java_argument_signature (type) - tree type; +build_java_argument_signature (tree type) { extern struct obstack temporary_obstack; tree sig = TYPE_ARGUMENT_SIGNATURE (type); @@ -573,28 +488,26 @@ build_java_argument_signature (type) /* Return the signature of the given TYPE. */ tree -build_java_signature (type) - tree type; +build_java_signature (tree type) { tree sig, t; - push_obstacks (&permanent_obstack, &permanent_obstack); while (TREE_CODE (type) == POINTER_TYPE) type = TREE_TYPE (type); - if (TYPE_LANG_SPECIFIC (type) == NULL) - { - TYPE_LANG_SPECIFIC (type) = (struct lang_type *) - perm_calloc (1, sizeof (struct lang_type)); - } - sig = TYPE_LANG_SPECIFIC (type)->signature; + MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type); + sig = TYPE_SIGNATURE (type); if (sig == NULL_TREE) { char sg[2]; switch (TREE_CODE (type)) { case BOOLEAN_TYPE: sg[0] = 'Z'; goto native; - case CHAR_TYPE: sg[0] = 'C'; goto native; case VOID_TYPE: sg[0] = 'V'; goto native; case INTEGER_TYPE: + if (type == char_type_node || type == promoted_char_type_node) + { + sg[0] = 'C'; + goto native; + } switch (TYPE_PRECISION (type)) { case 8: sg[0] = 'B'; goto native; @@ -649,98 +562,222 @@ build_java_signature (type) break; bad_type: default: - fatal ("internal error - build_java_signature passed invalid type"); + gcc_unreachable (); } - TYPE_LANG_SPECIFIC (type)->signature = sig; + TYPE_SIGNATURE (type) = sig; } - pop_obstacks (); return sig; } /* Save signature string SIG (an IDENTIFIER_NODE) in TYPE for future use. */ void -set_java_signature (type, sig) - tree type; - tree sig; +set_java_signature (tree type, tree sig) { tree old_sig; while (TREE_CODE (type) == POINTER_TYPE) type = TREE_TYPE (type); - if (TYPE_LANG_SPECIFIC (type) == NULL) - { - TYPE_LANG_SPECIFIC (type) = (struct lang_type *) - perm_calloc (1, sizeof (struct lang_type)); - - } - old_sig = TYPE_LANG_SPECIFIC (type)->signature; + MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type); + old_sig = TYPE_SIGNATURE (type); if (old_sig != NULL_TREE && old_sig != sig) - fatal ("internal error - set_java_signature"); - TYPE_LANG_SPECIFIC (type)->signature = sig; + abort (); + TYPE_SIGNATURE (type) = sig; #if 0 /* careful about METHOD_TYPE */ if (IDENTIFIER_SIGNATURE_TYPE (sig) == NULL_TREE && TREE_PERMANENT (type)) IDENTIFIER_SIGNATURE_TYPE (sig) = type; #endif } -/* Search in class CLAS (and its superclasses) for a method - matching METHOD_NAME and argument signature METHOD_SIGNATURE. - Return a FUNCTION_DECL on success, or NULL_TREE if none found. - (Contrast lookup_java_method, which takes into account return type.) */ +/* Search in SEARCHED_CLASS and its superclasses for a method matching + METHOD_NAME and signature METHOD_SIGNATURE. This function will + only search for methods declared in the class hierarchy; interfaces + will not be considered. Returns NULL_TREE if the method is not + found. */ +tree +lookup_argument_method (tree searched_class, tree method_name, + tree method_signature) +{ + return lookup_do (searched_class, 0, + method_name, method_signature, + build_java_argument_signature); +} +/* Like lookup_argument_method, but lets the caller set any flags + desired. */ tree -lookup_argument_method (clas, method_name, method_signature) - tree clas, method_name, method_signature; +lookup_argument_method_generic (tree searched_class, tree method_name, + tree method_signature, int flags) +{ + return lookup_do (searched_class, flags, + method_name, method_signature, + build_java_argument_signature); +} + + +/* Search in class SEARCHED_CLASS (and its superclasses) for a method + matching METHOD_NAME and signature METHOD_SIGNATURE. Return a + FUNCTION_DECL on success, or NULL_TREE if none found. (Contrast + lookup_argument_method, which ignores return type.) If + SEARCHED_CLASS is an interface, search it too. */ +tree +lookup_java_method (tree searched_class, tree method_name, + tree method_signature) +{ + return lookup_do (searched_class, SEARCH_INTERFACE, method_name, + method_signature, build_java_signature); +} + +/* Return true iff KLASS (or its ancestors) has a method METHOD_NAME.  */ +int +has_method (tree klass, tree method_name) +{ + return lookup_do (klass, SEARCH_INTERFACE, + method_name, NULL_TREE, + build_null_signature) != NULL_TREE; +} + +/* Search in class SEARCHED_CLASS, but not its superclasses, for a + method matching METHOD_NAME and signature SIGNATURE. A private + helper for lookup_do. */ +static tree +shallow_find_method (tree searched_class, int flags, tree method_name, + tree signature, tree (*signature_builder) (tree)) { tree method; - while (clas != NULL_TREE) + for (method = TYPE_METHODS (searched_class); + method != NULL_TREE; method = TREE_CHAIN (method)) { - for (method = TYPE_METHODS (clas); - method != NULL_TREE; method = TREE_CHAIN (method)) + tree method_sig = (*signature_builder) (TREE_TYPE (method)); + if (DECL_NAME (method) == method_name && method_sig == signature) { - tree method_sig = build_java_argument_signature (TREE_TYPE (method)); - tree name = DECL_NAME (method); - if ((TREE_CODE (name) == EXPR_WITH_FILE_LOCATION ? - EXPR_WFL_NODE (name) : name) == method_name - && method_sig == method_signature) + /* If the caller requires a visible method, then we + skip invisible methods here. */ + if (! (flags & SEARCH_VISIBLE) + || ! METHOD_INVISIBLE (method)) return method; } - clas = CLASSTYPE_SUPER (clas); } return NULL_TREE; } -/* Search in class CLAS (and its superclasses) for a method - matching METHOD_NAME and signature METHOD_SIGNATURE. - Return a FUNCTION_DECL on success, or NULL_TREE if none found. - (Contrast lookup_argument_method, which ignores return type.) */ +/* Search in the superclasses of SEARCHED_CLASS for a method matching + METHOD_NAME and signature SIGNATURE. A private helper for + lookup_do. */ +static tree +find_method_in_superclasses (tree searched_class, int flags, + tree method_name, tree signature, + tree (*signature_builder) (tree)) +{ + tree klass; + for (klass = CLASSTYPE_SUPER (searched_class); klass != NULL_TREE; + klass = CLASSTYPE_SUPER (klass)) + { + tree method; + method = shallow_find_method (klass, flags, method_name, + signature, signature_builder); + if (method != NULL_TREE) + return method; + } -tree -lookup_java_method (clas, method_name, method_signature) - tree clas, method_name, method_signature; + return NULL_TREE; +} + +/* Search in the interfaces of SEARCHED_CLASS and its superinterfaces + for a method matching METHOD_NAME and signature SIGNATURE. A + private helper for lookup_do. */ +static tree +find_method_in_interfaces (tree searched_class, int flags, tree method_name, + tree signature, tree (*signature_builder) (tree)) { - tree method; - while (clas != NULL_TREE) + int i; + tree binfo, base_binfo; + + for (binfo = TYPE_BINFO (searched_class), i = 1; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { - for (method = TYPE_METHODS (clas); - method != NULL_TREE; method = TREE_CHAIN (method)) - { - tree method_sig = build_java_signature (TREE_TYPE (method)); - if (DECL_NAME (method) == method_name - && method_sig == method_signature) - return method; - } - clas = CLASSTYPE_SUPER (clas); + tree iclass = BINFO_TYPE (base_binfo); + tree method; + + /* If the superinterface hasn't been loaded yet, do so now. */ + if (!CLASS_LOADED_P (iclass)) + load_class (iclass, 1); + + /* First, we look in ICLASS. If that doesn't work we'll + recursively look through all its superinterfaces. */ + method = shallow_find_method (iclass, flags, method_name, + signature, signature_builder); + if (method != NULL_TREE) + return method; + + method = find_method_in_interfaces + (iclass, flags, method_name, signature, signature_builder); + if (method != NULL_TREE) + return method; } + return NULL_TREE; } + +/* Search in class SEARCHED_CLASS (and its superclasses) for a method + matching METHOD_NAME and signature SIGNATURE. FLAGS control some + parameters of the search. + + SEARCH_INTERFACE means also search interfaces and superinterfaces + of SEARCHED_CLASS. + + SEARCH_SUPER means skip SEARCHED_CLASS and start with its + superclass. + + SEARCH_VISIBLE means skip methods for which METHOD_INVISIBLE is + set. + + Return the matched method DECL or NULL_TREE. SIGNATURE_BUILDER is + used on method candidates to build their (sometimes partial) + signature. */ +static tree +lookup_do (tree searched_class, int flags, tree method_name, + tree signature, tree (*signature_builder) (tree)) +{ + tree method; + tree orig_class = searched_class; + + if (searched_class == NULL_TREE) + return NULL_TREE; + + if (flags & SEARCH_SUPER) + { + searched_class = CLASSTYPE_SUPER (searched_class); + if (searched_class == NULL_TREE) + return NULL_TREE; + } + + /* First look in our own methods. */ + method = shallow_find_method (searched_class, flags, method_name, + signature, signature_builder); + if (method) + return method; + + /* Then look in our superclasses. */ + if (! CLASS_INTERFACE (TYPE_NAME (searched_class))) + method = find_method_in_superclasses (searched_class, flags, method_name, + signature, signature_builder); + if (method) + return method; + + /* If that doesn't work, look in our interfaces. */ + if (flags & SEARCH_INTERFACE) + method = find_method_in_interfaces (orig_class, flags, method_name, + signature, signature_builder); + + return method; +} + /* Search in class CLAS for a constructor matching METHOD_SIGNATURE. Return a FUNCTION_DECL on success, or NULL_TREE if none found. */ tree -lookup_java_constructor (clas, method_signature) - tree clas, method_signature; +lookup_java_constructor (tree clas, tree method_signature) { tree method = TYPE_METHODS (clas); for ( ; method != NULL_TREE; method = TREE_CHAIN (method)) @@ -754,14 +791,10 @@ lookup_java_constructor (clas, method_signature) /* Return a type which is the Binary Numeric Promotion of the pair T1, T2 and convert EXP1 and/or EXP2. See 5.6.2 Binary Numeric - Promotion. It assumes that both T1 and T2 are elligible to BNP. */ + Promotion. It assumes that both T1 and T2 are eligible to BNP. */ tree -binary_numeric_promotion (t1, t2, exp1, exp2) - tree t1; - tree t2; - tree *exp1; - tree *exp2; +binary_numeric_promotion (tree t1, tree t2, tree *exp1, tree *exp2) { if (t1 == double_type_node || t2 == double_type_node) {