From patchwork Sun Jun 5 13:07:10 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 98763 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 1B498B6FC9 for ; Sun, 5 Jun 2011 23:07:36 +1000 (EST) Received: (qmail 21387 invoked by alias); 5 Jun 2011 13:07:33 -0000 Received: (qmail 21375 invoked by uid 22791); 5 Jun 2011 13:07:31 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL, BAYES_00, 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; Sun, 05 Jun 2011 13:07:16 +0000 Received: from eggs.gnu.org ([140.186.70.92]:58298) by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1QTD2x-0001f8-Od for gcc-patches@gnu.org; Sun, 05 Jun 2011 09:07:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QTD2v-0002pE-CJ for gcc-patches@gnu.org; Sun, 05 Jun 2011 09:07:15 -0400 Received: from smtp161.iad.emailsrvr.com ([207.97.245.161]:36509) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QTD2u-0002p8-Ut for gcc-patches@gnu.org; Sun, 05 Jun 2011 09:07:13 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp26.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 2782EA816A for ; Sun, 5 Jun 2011 09:07:12 -0400 (EDT) Received: by smtp26.relay.iad1a.emailsrvr.com (Authenticated sender: nicola.pero-AT-meta-innovation.com) with ESMTPSA id 6EC3DA8169 for ; Sun, 5 Jun 2011 09:07:11 -0400 (EDT) From: Nicola Pero Subject: Fix for PR objc/49287 Date: Sun, 5 Jun 2011 14:07:10 +0100 Message-Id: To: gcc-patches@gnu.org Mime-Version: 1.0 (Apple Message framework v1084) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 207.97.245.161 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 PR objc/49287. The problem is that enabling the compiler checks for missing @interfaces triggered a couple of warnings of missing @interfaces in some testcases (this only showed up with the NeXT runtime because objc_getClass() is treated specially only with the NeXT runtime; we haven't changed the GNU ABI yet). The patch adds a cast to the testcases to remove the warnings and fix the apparent regression. OK to commit ? Thanks PS: I spent time considering whether the compiler behaviour in terms of warnings needed improving in this specific case, and ended up thinking that it's fine as it is. It's a rare issue where our compiler currently behaves identically to the latest Apple GCC in terms of warnings. Apple clang doesn't behave in the same way, as it's unable to check method invocations based on the arguments of objc_getClass() like GCC does, and so can miss serious warnings if objc_getClass() is the receiver of a method invocation not supported by the class, but on the other hand, doesn't emit a warning when objc_getClass() is used as a receiver of a method invocation and the @interface of the class is not available. I wondered for a while if this last behaviour is slightly better, but it's unclear. In the end, I see no compelling reason to change anything. It's a very rare issue anyhow. I added comments to objc-act.c trying to summarize the issues involved so if in the future we want to change things, information is readily available. Index: gcc/objc/ChangeLog =================================================================== --- gcc/objc/ChangeLog (revision 174624) +++ gcc/objc/ChangeLog (working copy) @@ -1,3 +1,8 @@ +2011-06-05 Nicola Pero + + * objc-act.c (receiver_is_class_object): Expanded comment. + (objc_finish_message_expr): Likewise. + 2011-06-02 Nicola Pero PR objc/48539 Index: gcc/objc/objc-act.c =================================================================== --- gcc/objc/objc-act.c (revision 174624) +++ gcc/objc/objc-act.c (working copy) @@ -5270,7 +5270,42 @@ receiver_is_class_object (tree receiver, int self, return exp; /* 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. */ + it is a call to objc_getClass, if so, pick up the class name. + + This is required by the GNU runtime, which compiles + + [NSObject alloc] + + into + + [objc_get_class ("NSObject") alloc]; + + and then, to check that the receiver responds to the +alloc + method, needs to be able to determine that the objc_get_class() + call returns the NSObject class and not just a generic Class + pointer. + + But, traditionally this is enabled for all runtimes, not just the + GNU one, which means that the compiler is smarter than you'd + expect when dealing with objc_getClass(). For example, with the + Apple runtime, in the code + + [objc_getClass ("NSObject") alloc]; + + the compiler will recognize the objc_getClass() call as special + (due to the code below) and so will know that +alloc is called on + the 'NSObject' class, and can perform the corresponding checks. + + Programmers can disable this behaviour by casting the results of + objc_getClass() to 'Class' (this may seem weird because + objc_getClass() is already declared to return 'Class', but the + compiler treats it as a special function). This may be useful if + the class is never declared, and the compiler would complain + about a missing @interface for it. Then, you can do + + [(Class)objc_getClass ("MyClassNeverDeclared") alloc]; + + to silence the warnings. */ if (TREE_CODE (receiver) == CALL_EXPR && (exp = CALL_EXPR_FN (receiver)) && TREE_CODE (exp) == ADDR_EXPR @@ -5478,13 +5513,16 @@ objc_finish_message_expr (tree receiver, tree sel_ { /* If 'rtype' is NULL_TREE at this point it means that we have seen no @interface corresponding to that - class name, only a @class declaration. So, we have a - class name (class_tree) but no actual details of the - class methods. We won't be able to check that the - class responds to the method, and we will have to - guess the method prototype. Emit a warning, then - keep going (this will use any method with a matching - name, as if the receiver was of type 'Class'). */ + class name, only a @class declaration (alternatively, + this was a call such as [objc_getClass("SomeClass") + alloc], where we've never seen the @interface of + SomeClass). So, we have a class name (class_tree) + but no actual details of the class methods. We won't + be able to check that the class responds to the + method, and we will have to guess the method + prototype. Emit a warning, then keep going (this + will use any method with a matching name, as if the + receiver was of type 'Class'). */ warning (0, "@interface of class %qE not found", class_tree); } } Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (revision 174656) +++ gcc/testsuite/ChangeLog (working copy) @@ -1,5 +1,14 @@ 2011-06-05 Nicola Pero + PR objc/49287 + * objc.dg/gnu-api-2-class.m: Updated testcase silencing compiler + warning. + * objc.dg/gnu-api-2-objc.m: Likewise. + * obj-c++.dg/gnu-api-2-class.mm: Likewise + * obj-c++.dg/gnu-api-2-objc.mm: Likewise. + +2011-06-05 Nicola Pero + * objc.dg/gnu-api-2-objc.m: Fixed testcase. Use log2 of the alignment, not the alignment, when calling class_addIvar(). Add an 'isa' instance variable to the test root class. Index: gcc/testsuite/objc.dg/gnu-api-2-class.m =================================================================== --- gcc/testsuite/objc.dg/gnu-api-2-class.m (revision 174655) +++ gcc/testsuite/objc.dg/gnu-api-2-class.m (working copy) @@ -109,7 +109,7 @@ int main(int argc, void **args) objc_registerClassPair (new_class); { - MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init]; + MySubClass *o = [[(Class)objc_getClass ("MySubSubClass") alloc] init]; Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar"); Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar"); Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar"); @@ -178,7 +178,7 @@ int main(int argc, void **args) /* Now, MySubClass2 is basically the same as MySubClass! We'll use the variable and setVariable: methods on it. */ { - MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init]; + MySubClass *o = (MySubClass *)[[(Class)objc_getClass ("MySubClass2") alloc] init]; [o setVariable: o]; Index: gcc/testsuite/objc.dg/gnu-api-2-objc.m =================================================================== --- gcc/testsuite/objc.dg/gnu-api-2-objc.m (revision 174656) +++ gcc/testsuite/objc.dg/gnu-api-2-objc.m (working copy) @@ -93,7 +93,7 @@ int main(int argc, void **args) abort (); { - MySubClass *o = [[objc_getClass ("MyNewSubClass") alloc] init]; + MySubClass *o = [[(Class)objc_getClass ("MyNewSubClass") alloc] init]; if (object_getClass (o) != objc_getClass ("MyNewSubClass")) abort (); Index: gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm =================================================================== --- gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm (revision 174656) +++ gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm (working copy) @@ -93,7 +93,7 @@ int main () abort (); { - MySubClass *o = [[objc_getClass ("MyNewSubClass") alloc] init]; + MySubClass *o = [[(Class)objc_getClass ("MyNewSubClass") alloc] init]; if (object_getClass (o) != objc_getClass ("MyNewSubClass")) abort (); Index: gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm =================================================================== --- gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm (revision 174655) +++ gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm (working copy) @@ -109,7 +109,7 @@ int main () objc_registerClassPair (new_class); { - MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init]; + MySubClass *o = [[(Class)objc_getClass ("MySubSubClass") alloc] init]; Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar"); Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar"); Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar"); @@ -178,7 +178,7 @@ int main () /* Now, MySubClass2 is basically the same as MySubClass! We'll use the variable and setVariable: methods on it. */ { - MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init]; + MySubClass *o = (MySubClass *)[[(Class)objc_getClass ("MySubClass2") alloc] init]; [o setVariable: o];