aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAlexander Malmberg <alexander@malmberg.org>2003-10-03 22:24:03 +0000
committerZiemowit Laski <zlaski@gcc.gnu.org>2003-10-03 22:24:03 +0000
commit81ff723b4ecccafb5aa6e4f5ce910d9f45064dbc (patch)
treee37abdb5f9046a1b3c2c5a65570f0a9f40582a2b /gcc
parent875eda9c345e57676c4f21f753274ee51025fa41 (diff)
downloadgcc-81ff723b4ecccafb5aa6e4f5ce910d9f45064dbc.zip
gcc-81ff723b4ecccafb5aa6e4f5ce910d9f45064dbc.tar.gz
gcc-81ff723b4ecccafb5aa6e4f5ce910d9f45064dbc.tar.bz2
objc-act.c (add_method_to_hash_list, [...]): New functions.
[gcc] 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(). [gcc/testsuite] 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. Co-Authored-By: Ziemowit Laski <zlaski@apple.com> From-SVN: r72080
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/objc/objc-act.c204
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/objc.dg/method-12.m2
-rw-r--r--gcc/testsuite/objc.dg/method-13.m77
-rw-r--r--gcc/testsuite/objc.dg/method-6.m25
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" } */
}