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: Fix ObjC instance variable lookup in class methods


Yes, Objective-C allows class methods (a.k.a. static member functions in C++)
to access the object's instance variables (a.k.a. data members). This is
because Objective-C also allows the 'self' (a.k.a. 'this') pointer to be
assigned to, and class methods in numerous existing Objective-C frameworks
utilize this mildly bizarre idiom to create and initialize instances of objects.


The problem is that when compiling a class method and looking up a name, the
compiler picks an instance variable even when other variables of that name
(such as a global variable or a parameter) are also visible. This patch fixes
things so that instance variables get picked for use in class methods only
as a last resort (i.e., when no other eligible symbols are in scope).


While I was at it, I cleaned up c-typeck.c so that ObjC-related processing no
longer takes place there. This should improve compile-time performance for
plain C slightly. The decision whether an ivar or another C/C++ symbol should
be used has now been moved to objc_lookup_ivar() itself (with the C/C++ symbol
passed in as an additional parameter).


C maintainers, does the c-typeck.c mod look OK to commit? I'll take the moral
responsibility for the ObjC bits. All of this assumes that the ongoing bootstrap
will reveal no regressions, of course...


Thanks,

--Zem

[gcc/ChangeLog]
2004-10-28  Ziemowit Laski  <zlaski@apple.com>

        * c-common.h (objc_lookup_ivar): Add second parameter to
        prototype.
        * c-typeck.c (build_external_ref): After looking up symbol,
        pass it to objc_lookup_ivar() to decide whether it or the
        ivar should be used, rather than deciding the issue locally.
        * stub-objc.c (objc_lookup_ivar): Add an OTHER parameter,
        which is simply returned in the non-ObjC case.

[gcc/objc/ChangeLog]
2004-10-28  Ziemowit Laski  <zlaski@apple.com>

        * objc-act.c (objc_lookup_ivar): The new OTHER parameter
        contains the result of the ID lookup by the C or C++
        front-end; in class methods, use OTHER if it exists;
        in instance methods, use OTHER only if it is locally
        declared.

[gcc/testsuite/ChangeLog]
2004-10-28  Ziemowit Laski  <zlaski@apple.com>

* objc.dg/local-decl-1.m: New test.

Index: gcc/c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.268
diff -u -3 -p -r1.268 c-common.h
--- gcc/c-common.h      25 Oct 2004 22:55:21 -0000      1.268
+++ gcc/c-common.h      28 Oct 2004 21:45:49 -0000
@@ -905,7 +905,7 @@ extern void objc_check_decl (tree);
 extern int objc_is_reserved_word (tree);
 extern int objc_comptypes (tree, tree, int);
 extern tree objc_message_selector (void);
-extern tree objc_lookup_ivar (tree);
+extern tree objc_lookup_ivar (tree, tree);
 extern void objc_clear_super_receiver (void);
 extern int objc_is_public (tree, tree);
 extern tree objc_is_id (tree);
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.393
diff -u -3 -p -r1.393 c-typeck.c
--- gcc/c-typeck.c      28 Oct 2004 19:30:49 -0000      1.393
+++ gcc/c-typeck.c      28 Oct 2004 21:45:55 -0000
@@ -1724,24 +1724,13 @@ build_external_ref (tree id, int fun)
 {
   tree ref;
   tree decl = lookup_name (id);
-  tree objc_ivar = objc_lookup_ivar (id);
+
+  /* In Objective-C, there may also be an instance variable (ivar) that
+     is accessible.  */
+  decl = objc_lookup_ivar (decl, id);

   if (decl && decl != error_mark_node)
-    {
-      /* Properly declared variable or function reference.  */
-      if (!objc_ivar)
-       ref = decl;
-      else if (decl != objc_ivar && !DECL_FILE_SCOPE_P (decl))
-       {
-         warning ("local declaration of %qs hides instance variable",
-                  IDENTIFIER_POINTER (id));
-         ref = decl;
-       }
-      else
-       ref = objc_ivar;
-    }
-  else if (objc_ivar)
-    ref = objc_ivar;
+    ref = decl;
   else if (fun)
     /* Implicit function declaration.  */
     ref = implicitly_declare (id);
Index: gcc/stub-objc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stub-objc.c,v
retrieving revision 2.7
diff -u -3 -p -r2.7 stub-objc.c
--- gcc/stub-objc.c     3 Sep 2004 20:17:50 -0000       2.7
+++ gcc/stub-objc.c     28 Oct 2004 21:45:55 -0000
@@ -46,9 +46,10 @@ objc_is_object_ptr (tree ARG_UNUSED (arg
 }

 tree
-objc_lookup_ivar (tree ARG_UNUSED (arg))
+objc_lookup_ivar (tree other, tree ARG_UNUSED (arg))
 {
-  return 0;
+  /* Just use whatever C/C++ found.  */
+  return other;
 }

 void
Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.252
diff -u -3 -p -r1.252 objc-act.c
--- gcc/objc/objc-act.c 26 Oct 2004 18:38:54 -0000      1.252
+++ gcc/objc/objc-act.c 28 Oct 2004 21:46:05 -0000
@@ -8435,25 +8435,49 @@ generate_objc_image_info (void)
   finish_var_decl (decl, initlist);
 }

-/* Look up ID as an instance variable.  */
+/* Look up ID as an instance variable.  OTHER contains the result of
+   the C or C++ lookup, which we may want to use instead.  */

 tree
-objc_lookup_ivar (tree id)
+objc_lookup_ivar (tree other, tree id)
 {
-  tree decl;
+  tree ivar;

- if (objc_method_context && !strcmp (IDENTIFIER_POINTER (id), "super"))
+ /* If we are not inside of an ObjC method, ivar lookup makes no sense. */
+ if (!objc_method_context)
+ return other;
+
+ if (!strcmp (IDENTIFIER_POINTER (id), "super"))
/* We have a message to super. */
return get_super_receiver ();
- else if (objc_method_context && (decl = is_ivar (objc_ivar_chain, id)))
+
+ /* In a class method, look up an instance variable only as a last
+ resort. */
+ if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL
+ && other && other != error_mark_node)
+ return other;
+
+ /* Look up the ivar, but do not use it if it is not accessible. */
+ ivar = is_ivar (objc_ivar_chain, id);
+
+ if (!ivar || is_private (ivar))
+ return other;
+
+ /* In an instance method, a local variable (or parameter) may hide the
+ instance variable. */
+ if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL
+ && other && other != error_mark_node && !DECL_FILE_SCOPE_P (other))
{
- if (is_private (decl))
- return 0;
- else
- return build_ivar_reference (id);
+ warning ("local declaration of %qs hides instance variable",
+ IDENTIFIER_POINTER (id));
+
+ return other;
}
- else
- return 0;
+
+ /* At this point, we are either in an instance method with no obscuring
+ local definitions, or in a class method with no alternate definitions
+ at all. */
+ return build_ivar_reference (id);
}


#include "gt-objc-objc-act.h"
Index: gcc/testsuite/objc.dg/local-decl-2.m
===================================================================
RCS file: gcc/testsuite/objc.dg/local-decl-2.m
diff -N gcc/testsuite/objc.dg/local-decl-2.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/objc.dg/local-decl-2.m 28 Oct 2004 21:46:22 -0000
@@ -0,0 +1,42 @@
+/* Test for ivar access inside of class methods. It should be allowed (with a warning), but only
+ if no other declarations with the same name are seen. */
+/* Author: Ziemowit Laski <zlaski@apple.com>. */
+/* { dg-do compile } */
+
+#include <objc/Object.h>
+
+@interface Sprite: Object {
+ int sprite, spree;
+}
++ (void)setFoo:(int)foo;
++ (void)setSprite:(int)sprite;
+- (void)setFoo:(int)foo;
+- (void)setSprite:(int)sprite;
+@end
+
+int spree = 23;
+
+@implementation Sprite
++ (void)setFoo:(int)foo {
+ sprite = foo; /* { dg-warning "instance variable .sprite. accessed in class method" } */
+ spree = foo;
+}
++ (void)setSprite:(int)sprite {
+ int spree;
+ sprite = 15;
+ spree = 17;
+ ((Sprite *)self)->sprite = 16; /* NB: This is how one _should_ access */
+ ((Sprite *)self)->spree = 18; /* ivars from within class methods! */
+}
+- (void)setFoo:(int)foo {
+ sprite = foo;
+ spree = foo;
+}
+- (void)setSprite:(int)sprite {
+ int spree;
+ sprite = 15; /* { dg-warning "local declaration of .sprite. hides instance variable" } */
+ self->sprite = 16;
+ spree = 17; /* { dg-warning "local declaration of .spree. hides instance variable" } */
+ self->spree = 18;
+}
+@end



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