diff mbox

Fix for PR objc/49287

Message ID C0B5368C-7B08-4E77-86DD-C7DC4E5CC240@meta-innovation.com
State New
Headers show

Commit Message

Nicola Pero June 5, 2011, 1:07 p.m. UTC
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.

Comments

Mike Stump June 5, 2011, 5:27 p.m. UTC | #1
On Jun 5, 2011, at 6:07 AM, Nicola Pero <nicola.pero@meta-innovation.com> wrote:
> 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 ?

Ok.
diff mbox

Patch

Index: gcc/objc/ChangeLog
===================================================================
--- gcc/objc/ChangeLog  (revision 174624)
+++ gcc/objc/ChangeLog  (working copy)
@@ -1,3 +1,8 @@ 
+2011-06-05  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * objc-act.c (receiver_is_class_object): Expanded comment.
+       (objc_finish_message_expr): Likewise.
+
 2011-06-02  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        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  <nicola.pero@meta-innovation.com>
 
+       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  <nicola.pero@meta-innovation.com>
+
        * 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];