? gcc/testsuite/objc.dg/missing-interface.m ? gcc/testsuite/objc.dg/prototype-1.m ? gcc/testsuite/objc.dg/prototype-2.m ? gcc/testsuite/objc.dg/prototype-3.m ? gcc/testsuite/objc.dg/prototype-4.m ? gcc/testsuite/objc.dg/prototype-5.m Index: gcc/c-common.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/c-common.c,v retrieving revision 1.461 diff -u -r1.461 c-common.c --- gcc/c-common.c 25 Sep 2003 01:25:43 -0000 1.461 +++ gcc/c-common.c 29 Sep 2003 19:48:25 -0000 @@ -497,6 +497,11 @@ int warn_protocol = 1; +/* Warn if multiple prototypes are found when sending a message to a receiver + with a known type. */ + +int warn_conflicting_prototypes = 1; + /* C++ language option variables. */ Index: gcc/c-common.h =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/c-common.h,v retrieving revision 1.209 diff -u -r1.209 c-common.h --- gcc/c-common.h 25 Sep 2003 01:25:45 -0000 1.209 +++ gcc/c-common.h 29 Sep 2003 19:48:25 -0000 @@ -660,6 +660,11 @@ extern int warn_protocol; +/* Warn if multiple prototypes are found when sending a message to a receiver + with a known type. */ + +extern int warn_conflicting_prototypes; + /* C++ language option variables. */ Index: gcc/c-opts.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/c-opts.c,v retrieving revision 1.90 diff -u -r1.90 c-opts.c --- gcc/c-opts.c 25 Sep 2003 01:25:46 -0000 1.90 +++ gcc/c-opts.c 29 Sep 2003 19:48:27 -0000 @@ -406,6 +406,10 @@ cpp_opts->warn_comments = value; break; + case OPT_Wconflicting_prototypes: + warn_conflicting_prototypes = value; + break; + case OPT_Wconversion: warn_conversion = value; break; Index: gcc/c.opt =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/c.opt,v retrieving revision 1.17 diff -u -r1.17 c.opt --- gcc/c.opt 25 Sep 2003 01:25:50 -0000 1.17 +++ gcc/c.opt 29 Sep 2003 19:48:29 -0000 @@ -172,6 +172,10 @@ C ObjC C++ ObjC++ Synonym for -Wcomment +Wconflicting-prototypes +ObjC ObjC++ +Warn if multiple conflicting prototypes are found for a message to a typed receiver + Wconversion C ObjC C++ ObjC++ Warn about possibly confusing type conversions Index: gcc/doc/invoke.texi =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/doc/invoke.texi,v retrieving revision 1.339 diff -u -r1.339 invoke.texi --- gcc/doc/invoke.texi 25 Sep 2003 01:25:52 -0000 1.339 +++ gcc/doc/invoke.texi 29 Sep 2003 19:48:37 -0000 @@ -1954,6 +1954,15 @@ compilation. This also enforces the coding style convention that methods and selectors must be declared before being used. +@item -Wno-conflicting-prototypes +@opindex Wno-conflicting-prototypes +When sending a message to a receiver whose type is known, that type is +searched for a method prototype for the message. If multiple conflicting +prototypes are found, a warning is issued. This can happen if, e.g., a class +and its superclass both declare a method, but with different return or +argument types. If you use the @code{Wno-conflicting-prototypes} option, no +warnings are issued. + @c not documented because only avail via -Wp @c @item -print-objc-runtime-info Index: gcc/objc/objc-act.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.c,v retrieving revision 1.194 diff -u -r1.194 objc-act.c --- gcc/objc/objc-act.c 25 Sep 2003 17:53:41 -0000 1.194 +++ gcc/objc/objc-act.c 29 Sep 2003 19:48:41 -0000 @@ -182,7 +182,6 @@ static hash hash_lookup (hash *, tree); static void hash_add_attr (hash, tree); static tree lookup_method (tree, tree); -static tree lookup_method_static (tree, tree, int); static tree add_class (tree); static void add_category (tree, tree); @@ -198,6 +197,29 @@ static tree build_objc_string_decl (enum string_section); static tree build_selector_reference_decl (void); +/* Searching for a prototype for a selector. */ + +/* These methods are used to search for a suitable prototype for a receiver + of a known type. Currently, these are used in finish_message_expr() and + really_start_method(). */ + +/* The prototype found in the prototype search. If multiple prototypes + were found, this will be the first found prototype. */ +static GTY(()) tree current_found_prototype; +static int num_found_prototypes; + +/* If warnings about conflicting prototypes are turned off, this will be set + to 1 as soon as a prototype is found, indicating that the search does not + need to proceed. (Finding additional prototypes does no harm, but it's + a waste of time.) */ +static int prototype_search_done; + +static void prototype_search_start (const char *); +static void prototype_search_end (void); +static void prototype_found (tree); +static void lookup_method_static (tree, tree, int); +static void lookup_method_in_protocol_list (tree, tree, int); + /* Protocol additions. */ static tree add_protocol (tree); @@ -239,7 +261,6 @@ /* Everything else. */ static tree define_decl (tree, tree); -static tree lookup_method_in_protocol_list (tree, tree, int); static tree lookup_protocol_in_reflist (tree, tree); static tree create_builtin_decl (enum tree_code, tree, const char *); static void setup_string_decl (void); @@ -559,39 +580,6 @@ } static tree -lookup_method_in_protocol_list (tree rproto_list, tree sel_name, - int class_meth) -{ - tree rproto, p; - tree fnd = 0; - - for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) - { - p = TREE_VALUE (rproto); - - if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) - { - if ((fnd = lookup_method (class_meth - ? PROTOCOL_CLS_METHODS (p) - : PROTOCOL_NST_METHODS (p), sel_name))) - ; - else if (PROTOCOL_LIST (p)) - fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p), - sel_name, class_meth); - } - else - { - ; /* An identifier...if we could not find a protocol. */ - } - - if (fnd) - return fnd; - } - - return 0; -} - -static tree lookup_protocol_in_reflist (tree rproto_list, tree lproto) { tree rproto, p; @@ -5663,6 +5651,10 @@ tree selector, retval, is_class; int self, super, have_cast; + /* A description of the receiver's type we use when reporting + errors/warnings. Currently, will always point at errbuf. */ + char *report_type; + /* Extract the receiver of the message, as well as its type (where the latter may take the form of a cast or be inferred from the implementation context). */ @@ -5680,15 +5672,25 @@ && !IS_SUPER (rtype))); /* If the receiver is a class object, retrieve the corresponding - @interface, if one exists. */ + @interface, if one exists. */ is_class = receiver_is_class_object (receiver, self, super); - - /* Now determine the receiver type (if an explicit cast has not been - provided). */ - if (!have_cast) + + /* Now determine the receiver type if an explicit cast has not been + provided. Generate a description of the receiver's type and place + it in report_type. */ + if (!have_cast) { if (is_class) - rtype = lookup_interface (is_class); + { + rtype = lookup_interface (is_class); + if (!rtype) + warning ("no interface seen for `%s'", + IDENTIFIER_POINTER (is_class)); + + report_type = errbuf; + sprintf (report_type, "%s", + IDENTIFIER_POINTER (is_class)); + } /* Handle `self' and `super'. */ else if (super) { @@ -5699,40 +5701,51 @@ return error_mark_node; } rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template)); + + report_type = errbuf; + sprintf (report_type, "%s", + IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template))); } else if (self) - rtype = lookup_interface (CLASS_NAME (implementation_template)); - } - - /* If receiver is of type `id' or `Class' (or if the @interface for a - class is not visible), we shall be satisfied with the existence of - any instance or class method. */ - if (!rtype || IS_ID (rtype) - || TREE_TYPE (rtype) == TREE_TYPE (objc_class_type)) - { - if (!rtype) - rtype = xref_tag (RECORD_TYPE, is_class); - else if (IS_ID (rtype)) { - rprotos = TYPE_PROTOCOL_LIST (rtype); - rtype = NULL_TREE; + rtype = lookup_interface (CLASS_NAME (implementation_template)); + + report_type = errbuf; + sprintf (report_type, "%s", + IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); } else - is_class = TYPE_NAME (rtype) = get_identifier ("Class"); - - if (rprotos) - method_prototype - = lookup_method_in_protocol_list (rprotos, sel_name, - is_class != NULL_TREE); - if (!method_prototype && !rprotos) - method_prototype - = (is_class - ? check_duplicates (hash_lookup (cls_method_hash_list, sel_name), 1) - : lookup_method_in_hash_lists (sel_name)); + report_type = gen_declaration (rtype, errbuf); } else + report_type = gen_declaration (rtype, errbuf); + + /* Search for a suitable prototype. If we can't find one, we use our + fallback prototype: id (*)(id,SEL,...). + + First we check if the type information known for the receiver gives any + prototypes. If this gives us a unique prototype, we use it. If it gives + several prototypes, we warn and use the "derived-most" prototype. + + If the type information does not provide any prototypes, we search for + one among all known prototypes. However, if the receiver is a class + object according to the type information, we only search among prototypes + for class methods, and instance methods in root classes. + + If this gives us one unique prototype, we use it. If the receiver wasn't + of type 'id' or 'Class', we issue a warning. + + If this gives us more than one prototype, or no prototype, we issue an + appropriate warning and use one of them. */ + + prototype_search_start (report_type); + + /* Search for a prototype given by the class part of the receiver's type, + if any. */ + if (rtype && !IS_ID (rtype) + && TREE_TYPE (rtype) != TREE_TYPE (objc_class_type)) { - tree orig_rtype = rtype, saved_rtype; + tree saved_rtype; if (TREE_CODE (rtype) == POINTER_TYPE) rtype = TREE_TYPE (rtype); @@ -5741,73 +5754,141 @@ && TREE_CODE (TYPE_NAME (rtype)) == TYPE_DECL && DECL_ORIGINAL_TYPE (TYPE_NAME (rtype))) rtype = DECL_ORIGINAL_TYPE (TYPE_NAME (rtype)); + saved_rtype = rtype; if (TYPED_OBJECT (rtype)) { rprotos = TYPE_PROTOCOL_LIST (rtype); rtype = lookup_interface (OBJC_TYPE_NAME (rtype)); } + /* If we could not find an @interface declaration, we must have only seen a @class declaration; so, we cannot say anything more intelligent about which methods the receiver will understand. */ if (!rtype) - rtype = saved_rtype; + { + rtype = saved_rtype; + warning ("no interface seen for `%s'", + IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype))); + } else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE) { /* We have a valid ObjC class name. Look up the method name - in the published @interface for the class (and its + in the published @interface(s) for the class (and its superclasses). */ - method_prototype - = lookup_method_static (rtype, sel_name, is_class != NULL_TREE); + lookup_method_static (rtype, sel_name, is_class != NULL_TREE); - /* If the method was not found in the @interface, it may still - exist locally as part of the @implementation. */ - if (!method_prototype && objc_implementation_context + /* The method may also exist locally as part of the + @implementation. */ + if (!prototype_search_done + && objc_implementation_context && CLASS_NAME (objc_implementation_context) - == OBJC_TYPE_NAME (rtype)) - method_prototype - = lookup_method - ((is_class - ? CLASS_CLS_METHODS (objc_implementation_context) - : CLASS_NST_METHODS (objc_implementation_context)), - sel_name); - - /* If we haven't found a candidate method by now, try looking for - it in the protocol list. */ - if (!method_prototype && rprotos) - method_prototype - = lookup_method_in_protocol_list (rprotos, sel_name, - is_class != NULL_TREE); + == OBJC_TYPE_NAME (rtype)) + { + tree possible_prototype; + + if (is_class) + { + possible_prototype + = lookup_method + (CLASS_CLS_METHODS (objc_implementation_context), + sel_name); + if (possible_prototype) + prototype_found (possible_prototype); + + /* If we are a root class, the instance methods also apply + to the class. */ + if (!prototype_search_done && !CLASS_SUPER_NAME (rtype)) + { + possible_prototype + = lookup_method + (CLASS_NST_METHODS (objc_implementation_context), + sel_name); + if (possible_prototype) + prototype_found (possible_prototype); + } + } + else + { + possible_prototype + = lookup_method + (CLASS_NST_METHODS (objc_implementation_context), + sel_name); + if (possible_prototype) + prototype_found (possible_prototype); + } + } } else { - warning ("invalid receiver type `%s'", - gen_declaration (orig_rtype, errbuf)); - rtype = rprotos = NULL_TREE; + warning ("invalid receiver type `%s'", report_type); + rtype = rprotos = is_class = NULL_TREE; } - } + } + else if (rtype && IS_ID (rtype)) + { + rprotos = TYPE_PROTOCOL_LIST (rtype); + } - if (!method_prototype) + /* Now look in the protocol list. */ + if (!prototype_search_done && rprotos) + lookup_method_in_protocol_list (rprotos, sel_name, + is_class != NULL_TREE); + + prototype_search_end (); + + if (num_found_prototypes == 1) + { + /* We found exactly one. Use it. */ + method_prototype = current_found_prototype; + } + else if (num_found_prototypes > 1) + { + /* We found more than one. prototype_found() will already have issued + warnings. We set method_prototype to the first one, which will + be the "derived-most" prototype. */ + method_prototype = current_found_prototype; + } + else { - static bool warn_missing_methods = false; + /* The type information didn't give us any prototypes. Thus, we check + if there are any known prototypes at all. */ - if (rtype) - warning ("`%s' may not respond to `%c%s'", - IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)), - (is_class ? '+' : '-'), - IDENTIFIER_POINTER (sel_name)); - if (rprotos) - warning ("`%c%s' not implemented by protocol(s)", - (is_class ? '+' : '-'), + if (rtype && TREE_TYPE (rtype) == TREE_TYPE (objc_class_type) + && !IS_ID (rtype)) + is_class = get_identifier ("Class"); + + /* If the object is "typed", ie. not just 'id' or 'Class', issue a + warning. */ + if (rprotos || !rtype + || (!IS_ID (rtype) + && TREE_TYPE (rtype) != TREE_TYPE (objc_class_type))) + warning ("receiver of type `%s' may not respond to `%c%s'", + report_type, (is_class ? '+' : '-'), IDENTIFIER_POINTER (sel_name)); - if (!warn_missing_methods) + + method_prototype + = (is_class + ? check_duplicates (hash_lookup (cls_method_hash_list, sel_name), 1) + : lookup_method_in_hash_lists (sel_name)); + + if (!method_prototype) { - warning ("(Messages without a matching method signature"); - warning ("will be assumed to return `id' and accept"); - warning ("`...' as arguments.)"); - warn_missing_methods = true; + static bool warn_missing_methods = false; + + warning ("no prototype found for `%c%s'", + (is_class ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + + if (!warn_missing_methods) + { + warning ("(Messages without a matching method prototype"); + warning ("will be assumed to return `id' and accept"); + warning ("`...' as arguments.)"); + warn_missing_methods = true; + } } } @@ -6177,27 +6258,74 @@ entry->list = obj; /* append to front */ } -static tree -lookup_method (tree mchain, tree method) +static GTY(()) const char *prototype_search_type; + +/* Start a prototype search. type is a string describing the receiver's + type, and is used when issuing warnings. */ +static void +prototype_search_start (const char *type) { - tree key; + prototype_search_type = type; + num_found_prototypes = 0; + current_found_prototype = 0; + prototype_search_done = 0; +} - if (TREE_CODE (method) == IDENTIFIER_NODE) - key = method; - else - key = METHOD_SEL_NAME (method); +static void +prototype_search_end (void) +{ + prototype_search_type = 0; +} - while (mchain) +/* Called when a prototype is found. Will check if it's compatible with + the prototype already found, issue warnings if necessary, and update + current_found_prototype and num_found_prototypes as necessary. */ +static void +prototype_found (tree prototype) +{ + if (!warn_conflicting_prototypes) { - if (METHOD_SEL_NAME (mchain) == key) - return mchain; + /* This might be called several times even if warnings are turned off. + If so, we ignore all calls except the first. */ + if (num_found_prototypes == 0) + current_found_prototype = prototype; + num_found_prototypes = 1; + prototype_search_done = 1; + return; + } - mchain = TREE_CHAIN (mchain); + /* If we've found exactly one prototype, and the new prototype is + compatible, do nothing. */ + if (num_found_prototypes == 1 + && comp_proto_with_proto (prototype, current_found_prototype)) + return; + + num_found_prototypes++; + if (num_found_prototypes > 1) + { + char type = (TREE_CODE (prototype) == INSTANCE_METHOD_DECL) ? '-' : '+'; + + if (num_found_prototypes == 2) + { + warning ("multiple methods named `%c%s' found for receiver of type `%s'", + type, + IDENTIFIER_POINTER (METHOD_SEL_NAME (prototype)), + prototype_search_type); + warn_with_method ("using", type, + current_found_prototype); + warn_with_method ("instead of", type, prototype); + } + else + warn_with_method ("or", type, prototype); } - return NULL_TREE; + else + current_found_prototype = prototype; } -static tree +/* Look for prototypes for a selector in an interface (including all + categories and protocols, and then all superclasses, for that interface). + Any prototypes found are passed to prototype_found(). */ +static void lookup_method_static (tree interface, tree ident, int is_class) { tree meth = NULL_TREE, root_inter = NULL_TREE; @@ -6208,54 +6336,144 @@ tree chain = is_class ? CLASS_CLS_METHODS (inter) : CLASS_NST_METHODS (inter); tree category = inter; - /* First, look up the method in the class itself. */ + /* Look up the method in the class itself. */ if ((meth = lookup_method (chain, ident))) - return meth; + { + prototype_found (meth); + if (prototype_search_done) + return; + } - /* Failing that, look for the method in each category of the class. */ + /* Look for the method in each category of the class. */ while ((category = CLASS_CATEGORY_LIST (category))) { chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category); /* Check directly in each category. */ if ((meth = lookup_method (chain, ident))) - return meth; + { + prototype_found (meth); + if (prototype_search_done) + return; + } - /* Failing that, check in each category's protocols. */ + /* Check in each category's protocols. */ if (CLASS_PROTOCOL_LIST (category)) { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (category), ident, is_class)))) - return meth; + lookup_method_in_protocol_list + (CLASS_PROTOCOL_LIST (category), ident, is_class); + if (prototype_search_done) + return; } } - /* If not found in categories, check in protocols of the main class. */ + /* Check in protocols of the main class. */ if (CLASS_PROTOCOL_LIST (inter)) { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (inter), ident, is_class)))) - return meth; + lookup_method_in_protocol_list + (CLASS_PROTOCOL_LIST (inter), ident, is_class); + if (prototype_search_done) + return; } - /* Failing that, climb up the inheritance hierarchy. */ + /* Climb up the inheritance hierarchy. */ root_inter = inter; inter = lookup_interface (CLASS_SUPER_NAME (inter)); } while (inter); - /* If no class (factory) method was found, check if an _instance_ + /* If the receiver is a class object, check if an _instance_ method of the same name exists in the root class. This is what - the Objective-C runtime will do. If an instance method was not - found, return 0. */ - return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE; + the Objective-C runtime will do. */ + if (is_class) + lookup_method_static (root_inter, ident, 0); +} + +/* Look for prototypes for a selector in a set of protocols (including + protocols the protocols inherit from). Any prototypes that are found + will be passed to prototype_found(). */ +static void +lookup_method_in_protocol_list (tree rproto_list, tree sel_name, int class_meth) +{ + tree rproto, p; + tree fnd; + + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) + { + p = TREE_VALUE (rproto); + + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + { + /* Check the protocol itself. */ + if ((fnd = lookup_method (class_meth + ? PROTOCOL_CLS_METHODS (p) + : PROTOCOL_NST_METHODS (p), sel_name))) + { + prototype_found (fnd); + if (prototype_search_done) + return; + } + /* Check the protocols this protocol inherits from. */ + if (PROTOCOL_LIST (p)) + { + lookup_method_in_protocol_list (PROTOCOL_LIST (p), + sel_name, class_meth); + if (prototype_search_done) + return; + } + } + } +} + +static tree +lookup_method (tree mchain, tree method) +{ + tree key; + + if (TREE_CODE (method) == IDENTIFIER_NODE) + key = method; + else + key = METHOD_SEL_NAME (method); + + while (mchain) + { + if (METHOD_SEL_NAME (mchain) == key) + return mchain; + + mchain = TREE_CHAIN (mchain); + } + return NULL_TREE; +} + + +/* Add the method to the hash list if it doesn't contain an identical + method already. */ +static void +add_method_to_hash_list (hash *hash_list, tree method) +{ + hash hsh; + + if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method)))) + { + /* Install on a global chain. */ + hash_enter (hash_list, method); + } + else + { + /* Check types against those; if different, add to a list. */ + attr loop; + int already_there = comp_proto_with_proto (method, hsh->key); + for (loop = hsh->list; !already_there && loop; loop = loop->next) + already_there |= comp_proto_with_proto (method, loop->value); + if (!already_there) + hash_add_attr (hsh, method); + } } tree add_method (tree class, tree method, int is_class) { tree mth; - hash hsh; if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), method))) { @@ -6273,10 +6491,11 @@ } else { - /* When processing an @interface for a class or category, give hard errors on methods with - identical selectors but differing argument and/or return types. We do not do this for - @implementations, because C/C++ will do it for us (i.e., there will be - duplicate function definition errors). */ + /* When processing an @interface for a class or category, give hard + errors on methods with identical selectors but differing argument + and/or return types. We do not do this for @implementations, because + C/C++ will do it for us (i.e., there will be duplicate function + definition errors). */ if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE || TREE_CODE (class) == CATEGORY_INTERFACE_TYPE) && !comp_proto_with_proto (method, mth)) @@ -6284,23 +6503,21 @@ is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); } - if (!(hsh = hash_lookup (is_class - ? cls_method_hash_list - : nst_method_hash_list, METHOD_SEL_NAME (method)))) - { - /* Install on a global chain. */ - hash_enter (is_class ? cls_method_hash_list : nst_method_hash_list, method); - } + if (is_class) + add_method_to_hash_list (cls_method_hash_list, method); else { - /* Check types against those; if different, add to a list. */ - attr loop; - int already_there = comp_proto_with_proto (method, hsh->key); - for (loop = hsh->list; !already_there && loop; loop = loop->next) - already_there |= comp_proto_with_proto (method, loop->value); - if (!already_there) - hash_add_attr (hsh, method); + add_method_to_hash_list (nst_method_hash_list, method); + + /* Instance methods in root classes are inherited by class objects, + so we add those methods to the class method list, too. + + TODO: We should do this for categories of root classes as well. */ + if (TREE_CODE (class) == CLASS_INTERFACE_TYPE + && !CLASS_SUPER_NAME (class)) + add_method_to_hash_list (cls_method_hash_list, method); } + return method; } @@ -7768,17 +7985,24 @@ if (implementation_template != objc_implementation_context) { - tree proto - = lookup_method_static (implementation_template, - METHOD_SEL_NAME (method), - TREE_CODE (method) == CLASS_METHOD_DECL); - - if (proto && ! comp_method_with_proto (method, proto)) + prototype_search_start + (IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); + lookup_method_static (implementation_template, + METHOD_SEL_NAME (method), + TREE_CODE (method) == CLASS_METHOD_DECL); + prototype_search_end (); + + /* If we found exactly one prototype, check that the implementation + matches it (if there's more than one, warnings will already have + been issued during the search). */ + if (num_found_prototypes == 1 + && !comp_method_with_proto (method, current_found_prototype)) { char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); warn_with_method ("conflicting types for", type, method); - warn_with_method ("previous declaration of", type, proto); + warn_with_method ("previous declaration of", type, + current_found_prototype); } } } Index: gcc/testsuite/objc.dg/call-super-2.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/call-super-2.m,v retrieving revision 1.2 diff -u -r1.2 call-super-2.m --- gcc/testsuite/objc.dg/call-super-2.m 25 Sep 2003 01:26:00 -0000 1.2 +++ gcc/testsuite/objc.dg/call-super-2.m 29 Sep 2003 19:48:48 -0000 @@ -44,11 +44,8 @@ @implementation Derived + (int) class_func1 { - int i = (int)[self class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ - /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 47 } */ - /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 47 } */ - /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 47 } */ - return i + (int)[super class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ + int i = (int)[self class_func0]; /* { dg-warning "receiver of type .Derived. may not respond to .\\+class_func0." } */ + return i + (int)[super class_func0]; /* { dg-warning "receiver of type .Object. may not respond to .\\+class_func0." } */ } + (int) class_func2 { @@ -65,12 +62,12 @@ } + (int) class_func5 { - int i = (int)[Derived class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ - return i + (int)[Object class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ + int i = (int)[Derived class_func0]; /* { dg-warning "receiver of type .Derived. may not respond to .\\+class_func0." } */ + return i + (int)[Object class_func0]; /* { dg-warning "receiver of type .Object. may not respond to .\\+class_func0." } */ } + (int) class_func6 { - return (int)[OBJC_GETCLASS("Object") class_func1]; /* { dg-warning ".Object. may not respond to .\\+class_func1." } */ + return (int)[OBJC_GETCLASS("Object") class_func1]; /* { dg-warning "receiver of type .Object. may not respond to .\\+class_func1." } */ } + (int) class_func7 { @@ -78,8 +75,8 @@ } - (int) instance_func1 { - int i = (int)[self instance_func0]; /* { dg-warning ".Derived. may not respond to .\\-instance_func0." } */ - return i + (int)[super instance_func0]; /* { dg-warning ".Object. may not respond to .\\-instance_func0." } */ + int i = (int)[self instance_func0]; /* { dg-warning "receiver of type .Derived. may not respond to .\\-instance_func0." } */ + return i + (int)[super instance_func0]; /* { dg-warning "receiver of type .Object. may not respond to .\\-instance_func0." } */ } - (int) instance_func2 { @@ -95,12 +92,17 @@ } - (int) instance_func5 { - int i = (int)[Derived instance_func1]; /* { dg-warning ".Derived. may not respond to .\\+instance_func1." } */ - return i + (int)[Object instance_func1]; /* { dg-warning ".Object. may not respond to .\\+instance_func1." } */ + int i = (int)[Derived instance_func1]; /* { dg-warning "receiver of type .Derived. may not respond to .\\+instance_func1." } */ + /* { dg-warning "no prototype found for .\\+instance_func1." "" { target *-*-* } 95 } */ + /* { dg-warning "\\(Messages without a matching method prototype" "" { target *-*-* } 95 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 95 } */ + /* { dg-warning ".\.\.\.. as arguments\.\\)" "" { target *-*-* } 95 } */ + return i + (int)[Object instance_func1]; /* { dg-warning "receiver of type .Object. may not respond to .\\+instance_func1." } */ + /* { dg-warning "no prototype found for .\\+instance_func1." "" { target *-*-* } 100 } */ } - (int) instance_func6 { - return (int)[OBJC_GETCLASS("Object") class_func1]; /* { dg-warning ".Object. may not respond to .\\+class_func1." } */ + return (int)[OBJC_GETCLASS("Object") class_func1]; /* { dg-warning "receiver of type .Object. may not respond to .\\+class_func1." } */ } - (int) instance_func7 { @@ -111,11 +113,12 @@ @implementation Derived (Categ) + (int) categ_class_func1 { - int i = (int)[self class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ + int i = (int)[self class_func0]; /* { dg-warning "receiver of type .Derived. may not respond to .\\+class_func0." } */ i += [self class_func1]; i += [self categ_class_func2]; - i += (int)[self categ_instance_func1]; /* { dg-warning ".Derived. may not respond to .\\+categ_instance_func1." } */ - return i + (int)[super class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ + i += (int)[self categ_instance_func1]; /* { dg-warning "receiver of type .Derived. may not respond to .\\+categ_instance_func1." } */ + /* { dg-warning "no prototype found for .\\+categ_instance_func1." "" { target *-*-* } 119 } */ + return i + (int)[super class_func0]; /* { dg-warning "receiver of type .Object. may not respond to .\\+class_func0." } */ } + (int) categ_class_func2 { @@ -124,13 +127,12 @@ } - (int) categ_instance_func1 { - int i = (int)[self instance_func0]; /* { dg-warning ".Derived. may not respond to .\\-instance_func0." } */ + int i = (int)[self instance_func0]; /* { dg-warning "receiver of type .Derived. may not respond to .\\-instance_func0." } */ i += [(Derived *)self categ_instance_func2]; - i += (int)[(Object *)self categ_instance_func2]; /* { dg-warning ".Object. may not respond to .\\-categ_instance_func2." } */ - /* { dg-warning ".\\-categ_instance_func2. not implemented by protocol" "" { target *-*-* } 129 } */ - i += (int)[(id )self categ_instance_func2]; /* { dg-warning ".\\-categ_instance_func2. not implemented by protocol" } */ + i += (int)[(Object *)self categ_instance_func2]; /* { dg-warning "receiver of type .Object \\*. may not respond to .\\-categ_instance_func2." } */ + i += (int)[(id )self categ_instance_func2]; /* { dg-warning "receiver of type .id . may not respond to .\\-categ_instance_func2." } */ i += [(id)self categ_instance_func2]; - return i + (int)[super instance_func0]; /* { dg-warning ".Object. may not respond to .\\-instance_func0." } */ + return i + (int)[super instance_func0]; /* { dg-warning "receiver of type .Object. may not respond to .\\-instance_func0." } */ } - (int) categ_instance_func2 { Index: gcc/testsuite/objc.dg/desig-init-1.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/desig-init-1.m,v retrieving revision 1.2 diff -u -r1.2 desig-init-1.m --- gcc/testsuite/objc.dg/desig-init-1.m 25 Sep 2003 01:26:00 -0000 1.2 +++ gcc/testsuite/objc.dg/desig-init-1.m 29 Sep 2003 19:48:48 -0000 @@ -22,10 +22,8 @@ 0, [Cls meth1], [2 + 1] = 3, - [2 * 2 ... 5] = (int)[0 meth2], /* { dg-warning "invalid receiver type" } */ - /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 25 } */ - /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 25 } */ - /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 25 } */ + [2 * 2 ... 5] = (int)[0 meth2], /* { dg-warning "invalid receiver type .int ." } */ + /* { dg-warning "receiver of type .int . may not respond to .\\-meth2." "" { target *-*-* } 25 } */ [2] [Cls meth2] }; Index: gcc/testsuite/objc.dg/method-2.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/method-2.m,v retrieving revision 1.2 diff -u -r1.2 method-2.m --- gcc/testsuite/objc.dg/method-2.m 25 Sep 2003 01:26:01 -0000 1.2 +++ gcc/testsuite/objc.dg/method-2.m 29 Sep 2003 19:48:48 -0000 @@ -22,11 +22,13 @@ [self rootInstanceMethod]; /* class is searched for an instance method */ [MyIntermediate rootInstanceMethod]; /* with the same name. */ - [self instanceMethod]; /* { dg-warning ".MyDerived. may not respond to .\\+instanceMethod." } */ - /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 25 } */ + [self instanceMethod]; /* { dg-warning "receiver of type .MyDerived. may not respond to .\\+instanceMethod." } */ + /* { dg-warning "no prototype found for .\\+instanceMethod." "" { target *-*-* } 25 } */ + /* { dg-warning "\\(Messages without a matching method prototype" "" { target *-*-* } 25 } */ /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 25 } */ - /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 25 } */ + /* { dg-warning ".\.\.\.. as arguments\\.\\)" "" { target *-*-* } 25 } */ [MyDerived instanceMethod]; /* { dg-warning ".MyDerived. may not respond to .\\+instanceMethod." } */ + /* { dg-warning "no prototype found for .\\+instanceMethod." "" { target *-*-* } 30 } */ } @end Index: gcc/testsuite/objc.dg/method-5.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/method-5.m,v retrieving revision 1.2 diff -u -r1.2 method-5.m --- gcc/testsuite/objc.dg/method-5.m 25 Sep 2003 01:26:01 -0000 1.2 +++ gcc/testsuite/objc.dg/method-5.m 29 Sep 2003 19:48:48 -0000 @@ -8,11 +8,17 @@ } NotAClass; void foo(UnderSpecified *u, NotAClass *n) { - [n nonexistent_method]; /* { dg-warning "invalid receiver type" } */ - /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 11 } */ + [n nonexistent_method]; /* { dg-warning "invalid receiver type .untagged struct \\*." } */ + /* { dg-warning "receiver of type .untagged struct \\*. may not respond to .\\-nonexistent_method." "" { target *-*-* } 11 } */ + /* { dg-warning "no prototype found for .\\-nonexistent_method." "" { target *-*-* } 11 } */ + /* { dg-warning "\\(Messages without a matching method prototype" "" { target *-*-* } 11 } */ /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 11 } */ - /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 11 } */ + /* { dg-warning ".\.\.\.. as arguments\\.\\)" "" { target *-*-* } 11 } */ [NotAClass nonexistent_method]; /* { dg-error ".NotAClass. is not an Objective\\-C class name or alias" } */ - [u nonexistent_method]; /* { dg-warning ".UnderSpecified. may not respond to .\\-nonexistent_method." } */ - [UnderSpecified nonexistent_method]; /* { dg-warning ".UnderSpecified. may not respond to .\\+nonexistent_method." } */ + [u nonexistent_method]; /* { dg-warning "no interface seen for .UnderSpecified." } */ + /* { dg-warning "receiver of type .UnderSpecified \\*. may not respond to .\\-nonexistent_method." "" { target *-*-* } 18 } */ + /* { dg-warning "no prototype found for .\\-nonexistent_method." "" { target *-*-* } 18 } */ + [UnderSpecified nonexistent_method]; /* { dg-warning "no interface seen for .UnderSpecified." } */ + /* { dg-warning "receiver of type .UnderSpecified. may not respond to .\\+nonexistent_method." "" { target *-*-* } 21 } */ + /* { dg-warning "no prototype found for .\\+nonexistent_method." "" { target *-*-* } 21 } */ } Index: gcc/testsuite/objc.dg/method-6.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/method-6.m,v retrieving revision 1.2 diff -u -r1.2 method-6.m --- gcc/testsuite/objc.dg/method-6.m 25 Sep 2003 01:26:01 -0000 1.2 +++ gcc/testsuite/objc.dg/method-6.m 29 Sep 2003 19:48:48 -0000 @@ -1,26 +1,38 @@ -/* Check that sending messages to variables of type 'Class' does not involve instance methods. */ +/* Check that sending messages to variables of type 'Class' does not involve instance methods not in root classes. */ /* Author: Ziemowit Laski */ /* { dg-do compile } */ #include @interface Base -- (unsigned)port; +- (unsigned)port1; - (id)starboard; @end @interface Derived: Base -- (Object *)port; -+ (Protocol *)port; +- (Object *)port1; ++ (Protocol *)port1; +- (Object *)port2; ++ (Protocol *)port2; +- (Object *)port3; @end id foo(void) { Class receiver; - id p = [receiver port]; /* there should be no warnings here! */ - p = [receiver starboard]; /* { dg-warning ".Class. may not respond to .\\+starboard." } */ - /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 20 } */ - /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 20 } */ - /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 20 } */ - p = [Class port]; /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */ - return p; + id p1 = [receiver port1]; /* { dg-warning "multiple methods named .\\-port1. found" } */ + /* { dg-warning "using .\\-\\(unsigned\\)port1." "" { target *-*-* } 8 } */ + /* { dg-warning "also found .\\-\\(Protocol \\*\\)port1." "" { target *-*-* } 14 } */ + /* { dg-warning "initialization makes pointer from integer without a cast" "" { target *-*-* } 22 } */ + id p2 = [receiver port2]; /* there should be no warnings here! */ + id p3 = [receiver port3]; /* { dg-warning "no prototype found for .\\+port3." } */ + /* { dg-warning "\\(Messages without a matching method prototype" "" { target *-*-* } 27 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 27 } */ + /* { dg-warning ".\.\.\.. as arguments\.\\)" "" { target *-*-* } 27 } */ + p1 = [receiver starboard]; /* No warning here as Class is treated like id (i.e. all class methods are matched) */ + p1 = [Base port1]; /* { dg-warning "assignment makes pointer from integer without a cast" } */ + p1 = [Derived port1]; /* { dg-warning "multiple methods named .\\-port1. found for receiver of type .Derived." } */ + /* { dg-warning "using .\\-\\(Protocol \\*\\)port1." "" { target *-*-* } 14 } */ + /* { dg-warning "instead of .\\-\\(unsigned\\)port1." "" { target *-*-* } 8 } */ + p2 = [Derived port2]; /* No warning, using class method */ + return p1; } Index: gcc/testsuite/objc.dg/method-7.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/method-7.m,v retrieving revision 1.2 diff -u -r1.2 method-7.m --- gcc/testsuite/objc.dg/method-7.m 25 Sep 2003 01:26:01 -0000 1.2 +++ gcc/testsuite/objc.dg/method-7.m 29 Sep 2003 19:48:48 -0000 @@ -15,13 +15,11 @@ id foo(void) { Object *obj = [[Object alloc] init]; id obj2 = obj; - [obj setWindow:nil]; /* { dg-warning ".Object. may not respond to .\\-setWindow:." } */ - /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 18 } */ - /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 18 } */ - /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 18 } */ - [obj2 setWindow:nil]; /* { dg-warning "multiple methods named .\\-setWindow:. found" } */ + [obj setWindow:nil]; /* { dg-warning "receiver of type .Object \\*. may not respond to .\\-setWindow:." } */ + /* { dg-warning "multiple methods named .\\-setWindow:. found" "" { target *-*-* } 18 } */ /* { dg-warning "using .\\-\\(void\\)setWindow:\\(Object \\*\\)wdw." "" { target *-*-* } 8 } */ /* { dg-warning "also found .\\-\\(void\\)setWindow:\\(Class1 \\*\\)window." "" { target *-*-* } 12 } */ + [obj2 setWindow:nil]; /* { dg-warning "multiple methods named .\\-setWindow:. found" } */ return obj; } Index: gcc/testsuite/objc.dg/proto-hier-1.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/proto-hier-1.m,v retrieving revision 1.2 diff -u -r1.2 proto-hier-1.m --- gcc/testsuite/objc.dg/proto-hier-1.m 25 Sep 2003 01:26:01 -0000 1.2 +++ gcc/testsuite/objc.dg/proto-hier-1.m 29 Sep 2003 19:48:49 -0000 @@ -48,8 +48,9 @@ id stupidVar; [stupidVar boo]; [stupidVar foo]; - [stupidVar anotherMsg]; /* { dg-warning ".\-anotherMsg. not implemented by protocol" } */ - /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 51 } */ + [stupidVar anotherMsg]; /* { dg-warning "receiver of type .id . may not respond to .\-anotherMsg." } */ + /* { dg-warning "no prototype found for .\-anotherMsg." "" { target *-*-* } 51 } */ + /* { dg-warning "Messages without a matching method prototype" "" { target *-*-* } 51 } */ /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 51 } */ /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 51 } */ return 0; Index: gcc/testsuite/objc.dg/proto-lossage-1.m =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/objc.dg/proto-lossage-1.m,v retrieving revision 1.2 diff -u -r1.2 proto-lossage-1.m --- gcc/testsuite/objc.dg/proto-lossage-1.m 25 Sep 2003 01:26:01 -0000 1.2 +++ gcc/testsuite/objc.dg/proto-lossage-1.m 29 Sep 2003 19:48:49 -0000 @@ -35,11 +35,7 @@ return (id )plate1; /* { dg-bogus "does not conform" } */ } - (int) getValue { - int i = [plate1 someValue]; /* { dg-warning ".\\-someValue. not implemented by protocol\\(s\\)" } */ - /* { dg-warning "\\(Messages without a matching method signature" "" { target *-*-* } 38 } */ - /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 38 } */ - /* { dg-warning ".\.\.\.. as arguments\.\\)" "" { target *-*-* } 38 } */ - /* { dg-warning "initialization makes integer from pointer without a cast" "" { target *-*-* } 38 } */ + int i = [plate1 someValue]; /* { dg-warning "receiver of type .id . may not respond to .\\-someValue." } */ int j = [(id )plate1 someValue]; /* { dg-bogus "not implemented by protocol" } */ int k = [(id)plate1 someValue]; /* { dg-bogus "not implemented by protocol" } */