Commit 81ff723b by Alexander Malmberg Committed by Ziemowit Laski

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
parent 875eda9c
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> 2003-10-03 Roger Sayle <roger@eyesopen.com>
PR optimization/9325, PR java/6391 PR optimization/9325, PR java/6391
......
...@@ -149,7 +149,7 @@ static tree build_private_template (tree); ...@@ -149,7 +149,7 @@ static tree build_private_template (tree);
static void build_class_template (void); static void build_class_template (void);
static void build_selector_template (void); static void build_selector_template (void);
static void build_category_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 void build_super_template (void);
static tree build_category_initializer (tree, tree, tree, tree, tree, tree); static tree build_category_initializer (tree, tree, tree, tree, tree, tree);
static tree build_protocol_initializer (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); ...@@ -184,8 +184,10 @@ static hash hash_lookup (hash *, tree);
static void hash_add_attr (hash, tree); static void hash_add_attr (hash, tree);
static tree lookup_method (tree, tree); static tree lookup_method (tree, tree);
static tree lookup_method_static (tree, tree, int); static tree lookup_method_static (tree, tree, int);
static void add_method_to_hash_list (hash *, tree);
static tree add_class (tree); static tree add_class (tree);
static void add_category (tree, tree); static void add_category (tree, tree);
static tree lookup_category (tree, tree);
enum string_section enum string_section
{ {
...@@ -280,7 +282,7 @@ static tree build_shared_structure_initializer (tree, tree, tree, tree, ...@@ -280,7 +282,7 @@ static tree build_shared_structure_initializer (tree, tree, tree, tree,
static void generate_category (tree); static void generate_category (tree);
static int is_objc_type_qualifier (tree); static int is_objc_type_qualifier (tree);
static tree adjust_type_for_id_default (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 tree receiver_is_class_object (tree, int, int);
static int check_methods (tree, tree, int); static int check_methods (tree, tree, int);
static int conforms_to_protocol (tree, tree); static int conforms_to_protocol (tree, tree);
...@@ -5064,6 +5066,18 @@ build_shared_structure_initializer (tree type, tree isa, tree super, ...@@ -5064,6 +5066,18 @@ build_shared_structure_initializer (tree type, tree isa, tree super,
return objc_build_constructor (type, nreverse (initlist)); 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 struct objc_category _OBJC_CATEGORY_<name> = { ... }; */
static void static void
...@@ -5078,15 +5092,8 @@ generate_category (tree cat) ...@@ -5078,15 +5092,8 @@ generate_category (tree cat)
class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); class_name_expr = add_objc_string (CLASS_NAME (cat), class_names);
category = CLASS_CATEGORY_LIST (implementation_template); category = lookup_category (implementation_template,
CLASS_SUPER_NAME (cat));
/* 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);
}
if (category && CLASS_PROTOCOL_LIST (category)) if (category && CLASS_PROTOCOL_LIST (category))
{ {
...@@ -5481,7 +5488,7 @@ get_arg_type_list (tree meth, int context, int superflag) ...@@ -5481,7 +5488,7 @@ get_arg_type_list (tree meth, int context, int superflag)
} }
static tree static tree
check_duplicates (hash hsh, int methods) check_duplicates (hash hsh, int methods, int is_class)
{ {
tree meth = NULL_TREE; tree meth = NULL_TREE;
...@@ -5494,15 +5501,23 @@ check_duplicates (hash hsh, int methods) ...@@ -5494,15 +5501,23 @@ check_duplicates (hash hsh, int methods)
/* We have two or more methods with the same name but /* We have two or more methods with the same name but
different types. */ different types. */
attr loop; attr loop;
char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+';
warning ("multiple %s named `%c%s' found", warning ("multiple %s named `%c%s' found",
methods ? "methods" : "selectors", type, methods ? "methods" : "selectors",
(is_class ? '+' : '-'),
IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); 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) 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; return meth;
...@@ -5638,17 +5653,27 @@ build_message_expr (tree mess) ...@@ -5638,17 +5653,27 @@ build_message_expr (tree mess)
return finish_message_expr (receiver, sel_name, method_params); 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 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, hash method_prototype = NULL;
if (!is_class)
method_prototype = hash_lookup (nst_method_hash_list,
sel_name); sel_name);
if (!method_prototype) if (!method_prototype)
{
method_prototype = hash_lookup (cls_method_hash_list, method_prototype = hash_lookup (cls_method_hash_list,
sel_name); 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 /* The 'finish_message_expr' routine is called from within
...@@ -5726,9 +5751,8 @@ finish_message_expr (tree receiver, tree sel_name, tree method_params) ...@@ -5726,9 +5751,8 @@ finish_message_expr (tree receiver, tree sel_name, tree method_params)
is_class != NULL_TREE); is_class != NULL_TREE);
if (!method_prototype && !rprotos) if (!method_prototype && !rprotos)
method_prototype method_prototype
= (is_class = lookup_method_in_hash_lists (sel_name,
? check_duplicates (hash_lookup (cls_method_hash_list, sel_name), 1) is_class != NULL_TREE);
: lookup_method_in_hash_lists (sel_name));
} }
else else
{ {
...@@ -6251,11 +6275,34 @@ lookup_method_static (tree interface, tree ident, int is_class) ...@@ -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; 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 tree
add_method (tree class, tree method, int is_class) add_method (tree class, tree method, int is_class)
{ {
tree mth; tree mth;
hash hsh;
if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), method))) 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) ...@@ -6273,10 +6320,11 @@ add_method (tree class, tree method, int is_class)
} }
else else
{ {
/* When processing an @interface for a class or category, give hard errors on methods with /* When processing an @interface for a class or category, give hard
identical selectors but differing argument and/or return types. We do not do this for errors on methods with identical selectors but differing argument
@implementations, because C/C++ will do it for us (i.e., there will be and/or return types. We do not do this for @implementations, because
duplicate function definition errors). */ C/C++ will do it for us (i.e., there will be duplicate function
definition errors). */
if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE
|| TREE_CODE (class) == CATEGORY_INTERFACE_TYPE) || TREE_CODE (class) == CATEGORY_INTERFACE_TYPE)
&& !comp_proto_with_proto (method, mth)) && !comp_proto_with_proto (method, mth))
...@@ -6284,23 +6332,23 @@ add_method (tree class, tree method, int is_class) ...@@ -6284,23 +6332,23 @@ add_method (tree class, tree method, int is_class)
is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
} }
if (!(hsh = hash_lookup (is_class if (is_class)
? cls_method_hash_list add_method_to_hash_list (cls_method_hash_list, method);
: 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);
}
else else
{ {
/* Check types against those; if different, add to a list. */ add_method_to_hash_list (nst_method_hash_list, method);
attr loop;
int already_there = comp_proto_with_proto (method, hsh->key); /* Instance methods in root classes (and categories thereof)
for (loop = hsh->list; !already_there && loop; loop = loop->next) may acts as class methods as a last resort. */
already_there |= comp_proto_with_proto (method, loop->value); if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE
if (!already_there) || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
hash_add_attr (hsh, method); 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; return method;
} }
...@@ -6317,23 +6365,19 @@ static void ...@@ -6317,23 +6365,19 @@ static void
add_category (tree class, tree category) add_category (tree class, tree category)
{ {
/* Put categories on list in reverse order. */ /* 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)'", warning ("duplicate interface declaration for category `%s(%s)'",
#endif
IDENTIFIER_POINTER (CLASS_NAME (class)), IDENTIFIER_POINTER (CLASS_NAME (class)),
IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); IDENTIFIER_POINTER (CLASS_SUPER_NAME (category)));
cat = CLASS_CATEGORY_LIST (cat);
} }
else
{
CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
CLASS_CATEGORY_LIST (class) = category; CLASS_CATEGORY_LIST (class) = category;
}
} }
/* Called after parsing each instance variable declaration. Necessary to /* Called after parsing each instance variable declaration. Necessary to
...@@ -6951,15 +6995,7 @@ finish_class (tree class) ...@@ -6951,15 +6995,7 @@ finish_class (tree class)
else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
{ {
tree category = CLASS_CATEGORY_LIST (implementation_template); tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class));
/* 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);
}
if (category) if (category)
{ {
...@@ -7753,7 +7789,9 @@ really_start_method (tree method, tree parmlist) ...@@ -7753,7 +7789,9 @@ really_start_method (tree method, tree parmlist)
METHOD_SEL_NAME (method), METHOD_SEL_NAME (method),
TREE_CODE (method) == CLASS_METHOD_DECL); TREE_CODE (method) == CLASS_METHOD_DECL);
if (proto && ! comp_method_with_proto (method, proto)) if (proto)
{
if (!comp_method_with_proto (method, proto))
{ {
char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+');
...@@ -7761,6 +7799,26 @@ really_start_method (tree method, tree parmlist) ...@@ -7761,6 +7799,26 @@ really_start_method (tree method, tree parmlist)
warn_with_method ("previous declaration of", type, proto); 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);
}
}
} }
/* The following routine is always called...this "architecture" is to /* The following routine is always called...this "architecture" is to
...@@ -8844,9 +8902,9 @@ finish_objc (void) ...@@ -8844,9 +8902,9 @@ finish_objc (void)
for (slot = 0; slot < SIZEHASHTABLE; slot++) for (slot = 0; slot < SIZEHASHTABLE; slot++)
{ {
for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) 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) for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
check_duplicates (hsh, 0); check_duplicates (hsh, 0, 1);
} }
} }
......
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> 2003-10-03 Roger Sayle <roger@eyesopen.com>
PR optimization/9325, PR java/6391 PR optimization/9325, PR java/6391
......
/* Contributed by Igor Seleznev <selez@mail.ru>. */ /* Contributed by Igor Seleznev <selez@mail.ru>. */
/* This used to be broken. */ /* This used to be broken. */
#include <objc/objc-api.h> #include <objc/objc.h>
@interface A @interface A
+ (A *)currentContext; + (A *)currentContext;
......
/* 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;
}
/* 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> */ /* Author: Ziemowit Laski <zlaski@apple.com> */
/* { dg-do compile } */ /* { dg-do compile } */
...@@ -6,21 +7,25 @@ ...@@ -6,21 +7,25 @@
@interface Base @interface Base
- (unsigned)port; - (unsigned)port;
- (id)starboard;
@end @end
@interface Derived: Base @interface Derived: Base
- (Object *)port; - (Object *)port;
+ (Protocol *)port; + (Protocol *)port;
- (id)starboard;
@end @end
id foo(void) { void foo(void) {
Class receiver; Class receiver;
id p = [receiver port]; /* there should be no warnings here! */
p = [receiver starboard]; /* { dg-warning ".Class. may not respond to .\\+starboard." } */ [receiver port]; /* { dg-warning "multiple methods named .\\+port. found" } */
/* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 20 } */ /* { dg-warning "using .\\-\\(unsigned\\)port." "" { target *-*-* } 9 } */
/* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 20 } */ /* { dg-warning "also found .\\+\\(Protocol \\*\\)port." "" { target *-*-* } 14 } */
/* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 20 } */
p = [Class port]; /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */ [receiver starboard]; /* { dg-warning ".Class. may not respond to .\\+starboard." } */
return p; /* { 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" } */
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment