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/7993 (shadowing private ivars in subclasses)


Here is a patch for objc/7993 - just to remind you, objc/7993 is a bug
report we just received, which says - 

"If an instance variable is declared @private, the same variable name
can't be reused as name for local variables when implementing methods of
subclasses.

This is wrong, because when writing subclasses you should not have to
worry about private implementation details of the superclass, such as
names of private variables. (I don't know, however, any official
specification of the Objective-C language, and therefore can't refer to
any document confirming my claim about the purpose of @private.)"

Actually, yes I do agree with the reporter in this instance.  In the pure
GNU ObjC tradition, I don't like @private variables at all :-) but if we
have support for them, it makes sense to have them work properly.

I'd say (just to set the policy in stone) that a meaningful policy would
be that, if an instance variable is private,

 - the class in which it is declared can access it without hassle;

 - a subclass can't access the variable - it's hidden, invisible, and if
you try accessing it you get an 'undeclared' type of error; you can
declare a local variable with the same name and get no error or warning
whatsoever - it is as if the private variables didn't exist.

 - the same level of protection as for @protected variables is in place:
if you try accessing the instance via ->, as for protected variables, you
get an error; but of course if you get the @defs of the object, you can
still access it

 - a subclass can't declare an instance variable with the same name (this
condition is somewhat unfortunate, but can't be removed without messing up
ObjC)

If there is agreement that this is the correct behaviour, I attach a
couple of testcases, and a patch for objc/objc-act.c to implement this
behaviour.  Basically the only change is that a private variable in a
subclass is no longer {existing but generating an error if you
access/refer it}; it is now completely hidden/undeclared (and so can be
shadowed with local variables without warnings).

I'd also like to document this behaviour in the documentation ... but
where ?  I was wondering if, as part of the GCC documentation, we could
start writing a 'reference/specification' of exactly how GNU ObjC/the GNU
ObjC compiler is supposed to behave - where we document all these details
... what generates a warning, what does not, and in the end what is valid
ObjC and what is not.  This might end up becoming a reference /
specification on ObjC - at least on the GNU/Apple ObjC variant - but I
wouldn't mind that, since there is none.  And yes, I quite like writing
documentation about ObjC. :-)

Let me know if the patch makes sense to you :-)

Wed Sep 25 14:33:22 2002  Nicola Pero  <n.pero@mi.flashnet.it>

	Fix PR objc/7993:
        * objc-act.c (is_private): Do not emit the 'instance variable %s
        is declared private' error.
        (is_public): Emit the error after calling is_private.
        (lookup_objc_ivar): If the instance variable is private, return 0
        - the instance variable is invisible here.
       
Index: objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.159
diff -u -r1.159 objc-act.c
--- objc-act.c  17 Sep 2002 13:59:30 -0000      1.159
+++ objc-act.c  25 Sep 2002 13:28:34 -0000
@@ -5851,8 +5851,6 @@
   if (TREE_PRIVATE (decl)
       && ! is_ivar (CLASS_IVARS (implementation_template), DECL_NAME
(decl)))
     {
-      error ("instance variable `%s' is declared private",
-            IDENTIFIER_POINTER (DECL_NAME (decl)));
       return 1;
     }
   else
@@ -5896,7 +5894,17 @@
                           == CATEGORY_IMPLEMENTATION_TYPE))
                      && (CLASS_NAME (objc_implementation_context)
                          == TYPE_NAME (basetype))))
-               return ! is_private (decl);
+               {
+                 int private = is_private (decl);
+                 
+                 if (private)
+                   {
+                     error ("instance variable `%s' is declared private",
+                            IDENTIFIER_POINTER (DECL_NAME (decl)));
+                   }
+                 
+                 return ! private;
+               }
 
              error ("instance variable `%s' is declared %s",
                     IDENTIFIER_POINTER (identifier),
@@ -8526,7 +8534,7 @@
   else if (objc_method_context && (decl = is_ivar (objc_ivar_chain, id)))
     {
       if (is_private (decl))
-       return error_mark_node;
+       return 0;
       else
         return build_ivar_reference (id);
     }

== now the testcases ==

Wed Sep 25 15:28:28 2002  Nicola Pero  <n.pero@mi.flashnet.it>

	* objc.dg/private-1.m: New test.
	* objc.dg/private-2.m: New test.


private-1.m:
============

/* Test errors for accessing @private and @protected variables.  */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>.  */
/* { dg-do compile } */
#include <objc/objc.h>

@interface MySuperClass
{
@private
  int private;

@protected
  int protected;

@public
  int public;
}
- (void) test;
@end

@implementation MySuperClass
- (void) test
{
  private = 12;   /* Ok  */
  protected = 12; /* Ok  */
  public = 12;    /* Ok  */
}
@end


@interface MyClass : MySuperClass 
@end

@implementation MyClass
- (void) test
{
  /* Private variables simply don't exist in the subclass.  */
  private = 12;/* { dg-error "undeclared" } */
  /* { dg-error "function it appears in" "" { target *-*-* } { 36 } } */

  protected = 12; /* Ok  */
  public = 12;    /* Ok  */
}
@end

int main (void)
{
  MyClass *m = nil;
  
  if (m != nil)
    {
      int access;

      access = m->private;   /* { dg-error "is declared private" }  */
      access = m->protected; /* { dg-error "is declared protected" }  */
      access = m->public;    /* Ok  */
    }

  return 0;
}


private-2.m:
============

/* Test warnings for shadowing instance variables.  */
/* Author: Nicola Pero <nicola@brainstorm.co.uk>.  */
/* { dg-do compile } */
#include <objc/objc.h>

@interface MySuperClass
{
@private
  int private;

@protected
  int protected;

@public
  int public;
}
- (void) test;
@end

@implementation MySuperClass
- (void) test
{
  /* FIXME: I wonder if the warnings shouldn't be better generated
     when the variable is declared, rather than used!  */
  int private = 12;
  int protected = 12;
  int public = 12;
  int a;
  
  a = private;    /* { dg-warning "hides instance variable" } */
  a = protected;  /* { dg-warning "hides instance variable" } */
  a = public;     /* { dg-warning "hides instance variable" } */
}
@end


@interface MyClass : MySuperClass 
@end

@implementation MyClass
- (void) test
{
  int private = 12;
  int protected = 12;
  int public = 12;
  int a;

  /* The private variable can be shadowed without warnings, because
   * it's invisible, and not accessible, to the subclass!  */
  a = private;   /* Ok  */
  a = protected; /* { dg-warning "hides instance variable" } */
  a = public;    /* { dg-warning "hides instance variable" } */
}
@end



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