diff options
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 204 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/method-12.m | 2 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/method-13.m | 77 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/method-6.m | 25 |
6 files changed, 253 insertions, 84 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 123cb3f..2a742ac 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2003-10-03 Alexander Malmberg <alexander@malmberg.org> + Ziemowit Laski <zlaski@apple.com> + + * objc/objc-act.c (add_method_to_hash_list, lookup_category): + New functions. + (lookup_method_in_hash_lists): New parameter indicating whether + we are messaging 'Class' or 'id'. + (check_duplicates): Likewise; do not assume all methods will + be either class or instance methods. + (generate_category, finish_class): Use lookup_category(). + (add_method): Use add_method_to_hash_list(); insert instance + methods of root classes into the global class method hash table. + (add_category): Use lookup_category(); avoid constructing + duplicate categories. + (really_start_method): Add method to corresponding @interface, + if not already there (and if the @interface exists). + (finish_message_expr, finish_objc): Adjust calls to + check_duplicates(). + 2003-10-03 Roger Sayle <roger@eyesopen.com> PR optimization/9325, PR java/6391 diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 42141a4..6b6d2f1 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -149,7 +149,7 @@ static tree build_private_template (tree); static void build_class_template (void); static void build_selector_template (void); static void build_category_template (void); -static tree lookup_method_in_hash_lists (tree); +static tree lookup_method_in_hash_lists (tree, int); static void build_super_template (void); static tree build_category_initializer (tree, tree, tree, tree, tree, tree); static tree build_protocol_initializer (tree, tree, tree, tree, tree); @@ -184,8 +184,10 @@ 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 void add_method_to_hash_list (hash *, tree); static tree add_class (tree); static void add_category (tree, tree); +static tree lookup_category (tree, tree); enum string_section { @@ -280,7 +282,7 @@ static tree build_shared_structure_initializer (tree, tree, tree, tree, static void generate_category (tree); static int is_objc_type_qualifier (tree); static tree adjust_type_for_id_default (tree); -static tree check_duplicates (hash, int); +static tree check_duplicates (hash, int, int); static tree receiver_is_class_object (tree, int, int); static int check_methods (tree, tree, int); static int conforms_to_protocol (tree, tree); @@ -5064,6 +5066,18 @@ build_shared_structure_initializer (tree type, tree isa, tree super, return objc_build_constructor (type, nreverse (initlist)); } +/* Retrieve category interface CAT_NAME (if any) associated with CLASS. */ + +static tree +lookup_category (tree class, tree cat_name) +{ + tree category = CLASS_CATEGORY_LIST (class); + + while (category && CLASS_SUPER_NAME (category) != cat_name) + category = CLASS_CATEGORY_LIST (category); + return category; +} + /* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */ static void @@ -5078,15 +5092,8 @@ generate_category (tree cat) class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); - category = CLASS_CATEGORY_LIST (implementation_template); - - /* find the category interface from the class it is associated with */ - while (category) - { - if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) - break; - category = CLASS_CATEGORY_LIST (category); - } + category = lookup_category (implementation_template, + CLASS_SUPER_NAME (cat)); if (category && CLASS_PROTOCOL_LIST (category)) { @@ -5481,7 +5488,7 @@ get_arg_type_list (tree meth, int context, int superflag) } static tree -check_duplicates (hash hsh, int methods) +check_duplicates (hash hsh, int methods, int is_class) { tree meth = NULL_TREE; @@ -5494,15 +5501,23 @@ check_duplicates (hash hsh, int methods) /* We have two or more methods with the same name but different types. */ attr loop; - char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+'; warning ("multiple %s named `%c%s' found", - methods ? "methods" : "selectors", type, + methods ? "methods" : "selectors", + (is_class ? '+' : '-'), IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method (methods ? "using" : "found", type, meth); + warn_with_method (methods ? "using" : "found", + ((TREE_CODE (meth) == INSTANCE_METHOD_DECL) + ? '-' + : '+'), + meth); for (loop = hsh->list; loop; loop = loop->next) - warn_with_method ("also found", type, loop->value); + warn_with_method ("also found", + ((TREE_CODE (loop->value) == INSTANCE_METHOD_DECL) + ? '-' + : '+'), + loop->value); } } return meth; @@ -5638,17 +5653,27 @@ build_message_expr (tree mess) return finish_message_expr (receiver, sel_name, method_params); } +/* Look up method SEL_NAME that would be suitable for receiver + of type 'id' (if IS_CLASS is zero) or 'Class' (if IS_CLASS is + non-zero), and report on any duplicates. */ + static tree -lookup_method_in_hash_lists (tree sel_name) +lookup_method_in_hash_lists (tree sel_name, int is_class) { - hash method_prototype = hash_lookup (nst_method_hash_list, - sel_name); + hash method_prototype = NULL; + + if (!is_class) + method_prototype = hash_lookup (nst_method_hash_list, + sel_name); if (!method_prototype) - method_prototype = hash_lookup (cls_method_hash_list, - sel_name); + { + method_prototype = hash_lookup (cls_method_hash_list, + sel_name); + is_class = 1; + } - return check_duplicates (method_prototype, 1); + return check_duplicates (method_prototype, 1, is_class); } /* The 'finish_message_expr' routine is called from within @@ -5726,9 +5751,8 @@ finish_message_expr (tree receiver, tree sel_name, tree method_params) 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)); + = lookup_method_in_hash_lists (sel_name, + is_class != NULL_TREE); } else { @@ -6251,11 +6275,34 @@ lookup_method_static (tree interface, tree ident, int is_class) return is_class ? lookup_method_static (root_inter, ident, 0): 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 +6320,11 @@ add_method (tree class, tree method, int is_class) } 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 +6332,23 @@ add_method (tree class, tree method, int is_class) 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 (and categories thereof) + may acts as class methods as a last resort. */ + if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE + || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) + class = lookup_interface (CLASS_NAME (class)); + + if (TREE_CODE (class) != PROTOCOL_INTERFACE_TYPE + && !CLASS_SUPER_NAME (class)) + add_method_to_hash_list (cls_method_hash_list, method); } + return method; } @@ -6317,23 +6365,19 @@ static void add_category (tree class, tree category) { /* Put categories on list in reverse order. */ - tree cat = CLASS_CATEGORY_LIST (class); + tree cat = lookup_category (class, CLASS_SUPER_NAME (category)); - while (cat) + if (cat) { - if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) -#ifdef OBJCPLUS - error ("duplicate interface declaration for category `%s(%s)'", -#else - warning ("duplicate interface declaration for category `%s(%s)'", -#endif - IDENTIFIER_POINTER (CLASS_NAME (class)), - IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); - cat = CLASS_CATEGORY_LIST (cat); + warning ("duplicate interface declaration for category `%s(%s)'", + IDENTIFIER_POINTER (CLASS_NAME (class)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); + } + else + { + CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); + CLASS_CATEGORY_LIST (class) = category; } - - CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); - CLASS_CATEGORY_LIST (class) = category; } /* Called after parsing each instance variable declaration. Necessary to @@ -6951,15 +6995,7 @@ finish_class (tree class) else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) { - tree category = CLASS_CATEGORY_LIST (implementation_template); - - /* Find the category interface from the class it is associated with. */ - while (category) - { - if (CLASS_SUPER_NAME (class) == CLASS_SUPER_NAME (category)) - break; - category = CLASS_CATEGORY_LIST (category); - } + tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class)); if (category) { @@ -7753,12 +7789,34 @@ really_start_method (tree method, tree parmlist) METHOD_SEL_NAME (method), TREE_CODE (method) == CLASS_METHOD_DECL); - if (proto && ! comp_method_with_proto (method, proto)) + if (proto) { - char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); + if (!comp_method_with_proto (method, proto)) + { + 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 ("conflicting types for", type, method); + warn_with_method ("previous declaration of", type, proto); + } + } + else + { + /* We have a method @implementation even though we did not + see a corresponding @interface declaration (which is allowed + by Objective-C rules). Go ahead and place the method in + the @interface anyway, so that message dispatch lookups + will see it. */ + tree interface = implementation_template; + + if (TREE_CODE (objc_implementation_context) + == CATEGORY_IMPLEMENTATION_TYPE) + interface = lookup_category + (interface, + CLASS_SUPER_NAME (objc_implementation_context)); + + if (interface) + add_method (interface, copy_node (method), + TREE_CODE (method) == CLASS_METHOD_DECL); } } } @@ -8844,9 +8902,9 @@ finish_objc (void) for (slot = 0; slot < SIZEHASHTABLE; slot++) { for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) - check_duplicates (hsh, 0); + check_duplicates (hsh, 0, 1); for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) - check_duplicates (hsh, 0); + check_duplicates (hsh, 0, 1); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7e10c01..66151d4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2003-10-03 Alexander Malmberg <alexander@malmberg.org> + Ziemowit Laski <zlaski@apple.com> + + * objc.dg/method-6.m ('starboard'): Move prototype from 'Base' to + 'Derived', so that it is never considered a class method; add + new warning for '+port' method ambiguity. + * objc.dg/method-12.m: Include <objc/objc.h> instead of + <objc/objc-api.h> (needed on Mac OS X). + * objc.dg/method-13.m: New test. + 2003-10-03 Roger Sayle <roger@eyesopen.com> PR optimization/9325, PR java/6391 diff --git a/gcc/testsuite/objc.dg/method-12.m b/gcc/testsuite/objc.dg/method-12.m index d6e6ce5..411caac 100644 --- a/gcc/testsuite/objc.dg/method-12.m +++ b/gcc/testsuite/objc.dg/method-12.m @@ -1,7 +1,7 @@ /* Contributed by Igor Seleznev <selez@mail.ru>. */ /* This used to be broken. */ -#include <objc/objc-api.h> +#include <objc/objc.h> @interface A + (A *)currentContext; diff --git a/gcc/testsuite/objc.dg/method-13.m b/gcc/testsuite/objc.dg/method-13.m new file mode 100644 index 0000000..c824398 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-13.m @@ -0,0 +1,77 @@ +/* Test if instance methods of root classes are used as class methods, if no + "real" methods are found. For receivers of type 'id' and 'Class', all + root classes must be considered. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ + +#include <objc/objc.h> + +#ifdef __NEXT_RUNTIME__ +#define OBJC_GETCLASS objc_getClass +#else +#define OBJC_GETCLASS objc_get_class +#endif + +extern void abort(void); +extern int strcmp(const char *, const char *); +#define CHECK_IF(expr) if(!(expr)) abort() + +@protocol Proto +- (const char *) method4; +@end + +@interface Root +{ Class isa; } ++ (const char *) method2; +@end + +@interface Derived: Root +- (const char *) method1; +- (const char *) method2; +- (const char *) method3; +@end + +@interface Root (Categ) +- (const char *) method3; +@end + +@implementation Root (Categ) +- (const char *) method3 { return "Root(Categ)::-method3"; } +- (const char *) method4 { return "Root(Categ)::-method4"; } +@end + +@implementation Derived +- (const char *) method1 { return "Derived::-method1"; } +- (const char *) method2 { return "Derived::-method2"; } +- (const char *) method3 { return "Derived::-method3"; } +@end + +@implementation Root +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif +- (const char *) method1 { return "Root::-method1"; } ++ (const char *) method2 { return "Root::+method2"; } +@end + +int main(void) +{ + Class obj = OBJC_GETCLASS("Derived"); + + /* None of the following should elicit compiler-time warnings. */ + + CHECK_IF(!strcmp([Root method1], "Root::-method1")); + CHECK_IF(!strcmp([Root method2], "Root::+method2")); + CHECK_IF(!strcmp([Root method3], "Root(Categ)::-method3")); + CHECK_IF(!strcmp([Root method4], "Root(Categ)::-method4")); + CHECK_IF(!strcmp([Derived method1], "Root::-method1")); + CHECK_IF(!strcmp([Derived method2], "Root::+method2")); + CHECK_IF(!strcmp([Derived method3], "Root(Categ)::-method3")); + CHECK_IF(!strcmp([Derived method4], "Root(Categ)::-method4")); + CHECK_IF(!strcmp([obj method1], "Root::-method1")); + CHECK_IF(!strcmp([obj method2], "Root::+method2")); + CHECK_IF(!strcmp([obj method3], "Root(Categ)::-method3")); + CHECK_IF(!strcmp([obj method4], "Root(Categ)::-method4")); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/method-6.m b/gcc/testsuite/objc.dg/method-6.m index 212958b..a4ca787 100644 --- a/gcc/testsuite/objc.dg/method-6.m +++ b/gcc/testsuite/objc.dg/method-6.m @@ -1,4 +1,5 @@ -/* 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, + unless they reside in root classes. */ /* Author: Ziemowit Laski <zlaski@apple.com> */ /* { dg-do compile } */ @@ -6,21 +7,25 @@ @interface Base - (unsigned)port; -- (id)starboard; @end @interface Derived: Base - (Object *)port; + (Protocol *)port; +- (id)starboard; @end -id foo(void) { +void 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; + + [receiver port]; /* { dg-warning "multiple methods named .\\+port. found" } */ + /* { dg-warning "using .\\-\\(unsigned\\)port." "" { target *-*-* } 9 } */ + /* { dg-warning "also found .\\+\\(Protocol \\*\\)port." "" { target *-*-* } 14 } */ + + [receiver starboard]; /* { dg-warning ".Class. may not respond to .\\+starboard." } */ + /* { 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 } */ + + [Class port]; /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */ } |