From patchwork Thu Dec 23 05:32:07 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 76477 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id D1956B70E0 for ; Thu, 23 Dec 2010 16:32:23 +1100 (EST) Received: (qmail 1760 invoked by alias); 23 Dec 2010 05:32:20 -0000 Received: (qmail 1744 invoked by uid 22791); 23 Dec 2010 05:32:18 -0000 X-SWARE-Spam-Status: No, hits=-1.3 required=5.0 tests=AWL, BAYES_00, SARE_SUB_ENC_UTF8, TW_BJ, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 23 Dec 2010 05:32:12 +0000 Received: from eggs.gnu.org ([140.186.70.92]:42877) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PVdmZ-0001B6-5k for gcc-patches@gnu.org; Thu, 23 Dec 2010 00:32:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PVdma-00060s-GH for gcc-patches@gnu.org; Thu, 23 Dec 2010 00:32:09 -0500 Received: from smtp201.iad.emailsrvr.com ([207.97.245.201]:56816) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PVdma-00060n-CB for gcc-patches@gnu.org; Thu, 23 Dec 2010 00:32:08 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp50.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id BFDA1370F1D for ; Thu, 23 Dec 2010 00:32:07 -0500 (EST) Received: from dynamic11.wm-web.iad.mlsrvr.com (dynamic11.wm-web.iad1a.rsapps.net [192.168.2.218]) by smtp50.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id ABBED370B5D for ; Thu, 23 Dec 2010 00:32:07 -0500 (EST) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic11.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id 8C042E0086 for ; Thu, 23 Dec 2010 00:32:07 -0500 (EST) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Thu, 23 Dec 2010 06:32:07 +0100 (CET) Date: Thu, 23 Dec 2010 06:32:07 +0100 (CET) Subject: =?UTF-8?Q?libobjc:=20fix=20class=5FaddMethod()=20to=20return=20NO=20if?= =?UTF-8?Q?=20the=20method=20already=20exists=20in=20the=20class?= From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1293082327.57225869@192.168.2.228> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch fixes an obvious bug in the new Objective-C runtime API implementation. Testcases both for classes in constructions and for classes already constructed are included. While the bug is obvious once you know where to look, it was crashing gnustep-base in the initial (complicated) +initialize phases and it took time to track down. With this patch applied (and using the latest gnustep-base that I've patched to recognize the new ObjC runtime API and use it), I can now use GCC 4.6 to compile GNUstep Objective-C programs that use all the new Objective-C 2.0 features and which actually work. :-) Committed to trunk. Thanks Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (revision 168198) +++ gcc/testsuite/ChangeLog (working copy) @@ -1,3 +1,9 @@ +2010-12-23 Nicola Pero + + * obj-c.dg/gnu-api-2-class.m: Test that class_addMethod() returns + NO if the method is already implemented in the class. + * obj-c++.dg/gnu-api-2-class.mm: Same change. + 2010-12-22 Sebastian Pop PR tree-optimization/47019 Index: gcc/testsuite/objc.dg/gnu-api-2-class.m =================================================================== --- gcc/testsuite/objc.dg/gnu-api-2-class.m (revision 168198) +++ gcc/testsuite/objc.dg/gnu-api-2-class.m (working copy) @@ -140,6 +140,12 @@ int main(int argc, void **args) method_getTypeEncoding (method2))) abort (); + /* Test that if the method already exists in the class, + class_addMethod() returns NO. */ + if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2), + method_getTypeEncoding (method2))) + abort (); + objc_registerClassPair (new_class); /* Now, MySubClass2 is basically the same as MySubClass! We'll @@ -152,6 +158,15 @@ int main(int argc, void **args) if ([o variable] != o) abort (); } + + /* Now, try that if you take an existing class and try to add an + already existing method, class_addMethod returns NO. This is + subtly different from before, when 'new_class' was still in + construction. Now it's a real class and the libobjc internals + differ between the two cases. */ + if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2), + method_getTypeEncoding (method2))) + abort (); } printf ("Testing class_addProtocol ()...\n"); Index: gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm =================================================================== --- gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm (revision 168198) +++ gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm (working copy) @@ -140,6 +140,12 @@ int main () method_getTypeEncoding (method2))) abort (); + /* Test that if the method already exists in the class, + class_addMethod() returns NO. */ + if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2), + method_getTypeEncoding (method2))) + abort (); + objc_registerClassPair (new_class); /* Now, MySubClass2 is basically the same as MySubClass! We'll @@ -152,6 +158,15 @@ int main () if ([o variable] != o) abort (); } + + /* Now, try that if you take an existing class and try to add an + already existing method, class_addMethod returns NO. This is + subtly different from before, when 'new_class' was still in + construction. Now it's a real class and the libobjc internals + differ between the two cases. */ + if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2), + method_getTypeEncoding (method2))) + abort (); } std::cout << "Testing class_addProtocol ()...\n"; Index: libobjc/sendmsg.c =================================================================== --- libobjc/sendmsg.c (revision 168198) +++ libobjc/sendmsg.c (working copy) @@ -759,6 +759,45 @@ class_addMethod (Class class_, SEL selector, IMP i if (method_name == NULL) return NO; + /* If the method already exists in the class, return NO. It is fine + if the method already exists in the superclass; in that case, we + are overriding it. */ + if (CLS_IS_IN_CONSTRUCTION (class_)) + { + /* The class only contains a list of methods; they have not been + registered yet, ie, the method_name of each of them is still + a string, not a selector. Iterate manually over them to + check if we have already added the method. */ + struct objc_method_list * method_list = class_->methods; + while (method_list) + { + int i; + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; ++i) + { + struct objc_method * method = &method_list->method_list[i]; + + if (method->method_name + && strcmp ((char *)method->method_name, method_name) == 0) + return NO; + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + /* The method wasn't found. It's a new one. Go ahead and add + it. */ + } + else + { + /* Do the standard lookup. This assumes the selectors are + mapped. */ + if (search_for_method_in_list (class_->methods, selector)) + return NO; + } + method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list)); method_list->method_count = 1; Index: libobjc/ChangeLog =================================================================== --- libobjc/ChangeLog (revision 168198) +++ libobjc/ChangeLog (working copy) @@ -1,3 +1,8 @@ +2010-12-23 Nicola Pero + + * sendmsg.c (class_addMethod): Return NO if the method already + exists in the class. + 2010-12-22 Nicola Pero * init.c (duplicate_classes): New.