RFA: Objective-c prototype search cleanups
Alexander Malmberg
alexander@malmberg.org
Mon Sep 29 20:20:00 GMT 2003
Alexander Malmberg wrote:
> Hi,
>
> Here is the message sending prototype search patch again, now against
> mainline.
[...]
And of course, I send an old diff. Sorry about that. A correct version
of the diff is attached. (The test cases were correct in the previous
mail.)
- Alexander Malmberg
-------------- next part --------------
? 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 <Func> *)self categ_instance_func2];
- i += (int)[(Object <Func> *)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 <Func>)self categ_instance_func2]; /* { dg-warning ".\\-categ_instance_func2. not implemented by protocol" } */
+ i += (int)[(Object <Func> *)self categ_instance_func2]; /* { dg-warning "receiver of type .Object <Func> \\*. may not respond to .\\-categ_instance_func2." } */
+ i += (int)[(id <Func>)self categ_instance_func2]; /* { dg-warning "receiver of type .id <Func>. 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 <zlaski@apple.com> */
/* { dg-do compile } */
#include <objc/Protocol.h>
@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<Booing, Fooing> 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 <Booing, Fooing>. 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 <NSObject>)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 <PlateMethods>. may not respond to .\\-someValue." } */
int j = [(id <NSObject>)plate1 someValue]; /* { dg-bogus "not implemented by protocol" } */
int k = [(id)plate1 someValue]; /* { dg-bogus "not implemented by protocol" } */
More information about the Gcc-patches
mailing list