This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: Find more ObjC methods


This patch builds on Alex Malmberg's recent work, and accomplishes
the following:
  - If no class method is found to call, it considers instance methods
    of root classes as a last resort.  This already works for typed
    receivers; this patch restores the same behavior for 'id' and
    'Class'.
  - If a method appears only in an @implementation, also add it to
    the corresponding @interface.  Since method lookup works with
    @interfaces rather than @implementations, it will now be able to
    locate more methods successfully.

This will hopefully do for now. It occurred to me that, in the long run,
the compiler should stop distinguishing @interfaces from @implementations
(since the former are merely forward declarations for the latter).


I'm currently bootstrapping TOT with this patch. If no regressions are found,
I shall commit.


[gcc]
2003-10-02  Alexander Malmberg  <alexander@malmberg.org>
            Ziemowit Laski  <zlaski@apple.com>

        * objc/objc-act.c (add_method_to_hash_list, lookup_category):
        New functions.
        (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).

[gcc/testsuite]
2003-10-02  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.
        * objc.dg/method-12.m: Include <objc/objc.h> instead of
        <objc/objc-api.h> (needed on NeXT).
        * objc.dg/method-13.m: New test.


Index: gcc/objc/objc-act.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v retrieving revision 1.198 diff -c -3 -p -r1.198 objc-act.c *** gcc/objc/objc-act.c 30 Sep 2003 21:49:01 -0000 1.198 --- gcc/objc/objc-act.c 3 Oct 2003 00:48:55 -0000 *************** static hash hash_lookup (hash *, tree); *** 184,191 **** --- 184,193 ---- 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
  {
*************** build_shared_structure_initializer (tree
*** 5064,5069 ****
--- 5066,5083 ----
    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
*************** generate_category (tree cat)
*** 5078,5092 ****

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);
! }


    if (category && CLASS_PROTOCOL_LIST (category))
      {
--- 5092,5099 ----

class_name_expr = add_objc_string (CLASS_NAME (cat), class_names);

!   category = lookup_category (implementation_template,
!                               CLASS_SUPER_NAME (cat));

if (category && CLASS_PROTOCOL_LIST (category))
{
*************** lookup_method_static (tree interface, tr
*** 6251,6261 ****
return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE;
}


  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)))
{
--- 6258,6291 ----
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;


if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), method)))
{
*************** add_method (tree class, tree method, int
*** 6273,6282 ****
}
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). */
if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE
|| TREE_CODE (class) == CATEGORY_INTERFACE_TYPE)
&& !comp_proto_with_proto (method, mth))
--- 6303,6313 ----
}
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). */
if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE
|| TREE_CODE (class) == CATEGORY_INTERFACE_TYPE)
&& !comp_proto_with_proto (method, mth))
*************** add_method (tree class, tree method, int
*** 6284,6306 ****
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);
! }
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);
}
return method;
}


--- 6315,6337 ----
is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
}


!   if (is_class)
!     add_method_to_hash_list (cls_method_hash_list, method);
    else
      {
!       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;
  }

*************** static void
*** 6317,6339 ****
  add_category (tree class, tree category)
  {
    /* Put categories on list in reverse order.  */
!   tree cat = CLASS_CATEGORY_LIST (class);

! while (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);
}
-
- CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
- CLASS_CATEGORY_LIST (class) = category;
}


/* Called after parsing each instance variable declaration. Necessary to
--- 6348,6366 ----
add_category (tree class, tree category)
{
/* Put categories on list in reverse order. */
! tree cat = lookup_category (class, CLASS_SUPER_NAME (category));


! if (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;
}
}


/* Called after parsing each instance variable declaration. Necessary to
*************** finish_class (tree class)
*** 6951,6965 ****


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);
! }


        if (category)
        {
--- 6978,6984 ----

else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
{
! tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class));


if (category)
{
*************** really_start_method (tree method, tree p
*** 7753,7764 ****
METHOD_SEL_NAME (method),
TREE_CODE (method) == CLASS_METHOD_DECL);


! if (proto && ! 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);
}
}
}
--- 7772,7805 ----
METHOD_SEL_NAME (method),
TREE_CODE (method) == CLASS_METHOD_DECL);


! if (proto)
{
! 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);
! }
! }
! 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);
}
}
}
Index: gcc/testsuite/objc.dg/method-12.m
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/objc.dg/method-12.m,v
retrieving revision 1.2
diff -c -3 -p -r1.2 method-12.m
*** gcc/testsuite/objc.dg/method-12.m 25 Sep 2003 01:26:01 -0000 1.2
--- gcc/testsuite/objc.dg/method-12.m 3 Oct 2003 00:49:02 -0000
***************
*** 1,7 ****
/* Contributed by Igor Seleznev <selez@mail.ru>. */
/* This used to be broken. */


! #include <objc/objc-api.h>

  @interface A
  + (A *)currentContext;
--- 1,7 ----
  /* Contributed by Igor Seleznev <selez@mail.ru>.  */
  /* This used to be broken.  */

! #include <objc/objc.h>

@interface A
+ (A *)currentContext;
Index: gcc/testsuite/objc.dg/method-13.m
===================================================================
RCS file: gcc/testsuite/objc.dg/method-13.m
diff -N gcc/testsuite/objc.dg/method-13.m
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/objc.dg/method-13.m 3 Oct 2003 00:49:02 -0000
***************
*** 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;
+ }
Index: gcc/testsuite/objc.dg/method-6.m
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/objc.dg/method-6.m,v
retrieving revision 1.2
diff -c -3 -p -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 3 Oct 2003 00:49:02 -0000
***************
*** 6,17 ****


  @interface Base
  - (unsigned)port;
- - (id)starboard;
  @end

  @interface Derived: Base
  - (Object *)port;
  + (Protocol *)port;
  @end

  id foo(void) {
--- 6,17 ----

  @interface Base
  - (unsigned)port;
  @end

  @interface Derived: Base
  - (Object *)port;
  + (Protocol *)port;
+ - (id)starboard;
  @end

id foo(void) {

--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]