This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
objc.dg/method-2.m fix with the GNU runtime
- To: Stan Shebs <shebs at apple dot com>
- Subject: objc.dg/method-2.m fix with the GNU runtime
- From: Nicola Pero <n dot pero at mi dot flashnet dot it>
- Date: Fri, 26 Oct 2001 19:48:46 +0100 (BST)
- cc: Ovidiu Predescu <ovidiu at cup dot hp dot com>, Ziemowit Laski <zlaski at apple dot com>, gcc-patches at gcc dot gnu dot org
- Reply-To: Nicola Pero <n dot pero at mi dot flashnet dot it>
Hi,
here is a patch which fixes the objc.dg/method-2.m testcase with the GNU
runtime (I think adapting/porting what was done by apple for the next
runtime).
One comment on the fix so it's recorded on the mailing list - the fix
statically types `self' in a class method to be the class the method is
part of. This maximes error checking in normal situations, but gets in
the way if you want to redefine self in a class method to be something
else. But in that case, you can still get the old behaviour of having
self to be untyped id by simply casting self to id.
I wrote some testcases while playing with it, I'd like to commit the
following two -
objc/class_self-1.m: brings the problem of having an untyped self to the
extreme consequences - an instance method of an unrelated class - with a
different signature - is picked up by the compiler instead of the intended
class method, and that causes compilation to fail. fixed by the patch.
objc/class_self-2.m: is the case in which the new compiler code requires
you to use a cast. self is redefined to be another class, so you have to
cast it to an id to have it compile. This testcase is not failing, but
I'd like to add it anyway to make sure we don't break it in the future.
Ok to commit the new two testcases and apply the patch ?
gcc/gcc/ChangeLog:
==================
Fri Oct 26 07:42:53 2001 Nicola Pero <n.pero@mi.flashnet.it>
* objc/objc-act.c (finish_message_expr): For the GNU runtime: when
determining the type of the receiver, do not check that TREE_CODE
of receiver is CALL_EXPR before calling receiver_is_class_object
(). (receiver_is_class_object): For the GNU runtime: recognize
the case that the receiver is self in a class method context.
Check that TREE_CODE of receiver is CALL_EXPR when checking that
the receiver is a call to objc_get_class.
Index: objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.99
diff -u -r1.99 objc-act.c
--- objc-act.c 2001/10/21 21:03:48 1.99
+++ objc-act.c 2001/10/27 12:18:56
@@ -4710,14 +4710,16 @@
{
tree chain, exp, arg;
+ /* The receiver is 'self' in the context of a class method. */
+ if (objc_method_context
+ && receiver == self_decl
+ && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
+ {
+ return CLASS_NAME (objc_implementation_context);
+ }
+
if (flag_next_runtime)
{
- /* The receiver is 'self' in the context of a class method. */
- if (objc_method_context
- && receiver == self_decl
- && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
- return CLASS_NAME (objc_implementation_context);
-
/* The receiver is a variable created by
build_class_reference_decl. */
if (TREE_CODE (receiver) == VAR_DECL
@@ -4731,7 +4733,8 @@
{
/* The receiver is a function call that returns an id. Check if
it is a call to objc_getClass, if so, pick up the class name. */
- if ((exp = TREE_OPERAND (receiver, 0))
+ if (TREE_CODE (receiver) == CALL_EXPR
+ && (exp = TREE_OPERAND (receiver, 0))
&& TREE_CODE (exp) == ADDR_EXPR
&& (exp = TREE_OPERAND (exp, 0))
&& TREE_CODE (exp) == FUNCTION_DECL
@@ -4844,8 +4847,8 @@
&& TREE_STATIC_TEMPLATE (TREE_TYPE (rtype)))
statically_typed = 1;
else if ((flag_next_runtime
- || (TREE_CODE (receiver) == CALL_EXPR && IS_ID (rtype)))
- && (class_ident = receiver_is_class_object (receiver)))
+ || (IS_ID (rtype)
+ && (class_ident = receiver_is_class_object (receiver)))))
;
else if (! IS_ID (rtype)
/* Allow any type that matches objc_class_type. */
@@ -5022,9 +5025,9 @@
/* We think we have an instance...loophole: extern id Object; */
hsh = hash_lookup (nst_method_hash_list, sel_name);
+
if (!hsh)
- /* For various loopholes, like sending messages to self in a
- factory context. */
+ /* For various loopholes */
hsh = hash_lookup (cls_method_hash_list, sel_name);
method_prototype = check_duplicates (hsh);
gcc/gcc/testsuite/ChangeLog:
============================
Fri Oct 26 09:02:07 2001 Nicola Pero <n.pero@mi.flashnet.it>
* objc/execute/class_self-1.m: New test.
* objc/execute/class_self-2.m: New test.
gcc/gcc/testsuite/objc/execute/class_self-1.m:
==============================================
/* Contributed by Nicola Pero - Fri Oct 26 22:39:32 BST 2001 */
#include <objc/objc.h>
/* Test calling a class method when there is an instance method
with conflicting types */
/* This class should be unused but on broken compilers its instance
method might get picked up and used instead of the class method of
another class ! */
struct d
{
int a;
};
@interface UnusedClass
{
Class isa;
}
- (struct d) method;
@end
@implementation UnusedClass
- (struct d) method
{
struct d u;
u.a = 0;
return u;
}
@end
/* The real class */
@interface TestClass
{
Class isa;
}
+ (void) test;
+ (int) method;
@end
@implementation TestClass
+ (void) test
{
if ([self method] != 4)
{
abort ();
}
}
+ (int) method
{
return 4;
}
@end
int main (void)
{
[TestClass test];
return 0;
}
gcc/gcc/testsuite/objc/execute/class_self-2.m:
==============================================
/* Contributed by Nicola Pero - Fri Oct 26 22:39:32 BST 2001 */
#include <objc/objc.h>
/* Test calling a class method on self where self has been redefined
to be another class - the call requires a cast */
/* The first class */
struct d
{
int a;
};
@interface ClassA
{
Class isa;
}
+ (Class) class;
+ (struct d) method;
@end
@implementation ClassA
+ (Class) class
{
return self;
}
+ (struct d) method
{
struct d u;
u.a = 5;
return u;
}
@end
/* The second class */
@interface TestClass
{
Class isa;
}
+ (void) test;
@end
@implementation TestClass
+ (void) test
{
self = [ClassA class];
if ([(Class)self method].a != 5)
{
abort ();
}
}
@end
int main (void)
{
[TestClass test];
return 0;
}