In gcc/objc/: 2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com>

In gcc/objc/:
2010-11-08  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc-act.c (objc_add_synthesize_declaration_for_property):
        Iterate over IMPL_PROPERTY_DECL, not CLASS_PROPERTY_DECL, when
        checking for an existing @synthesize or @dynamic declaration.
        Search for an inherited @property declaration if none is found in
        the local interface.  If the required instance variable does not
        exist, return instead of trying to continue to prevent a compiler
        crash later.  Check that the instance variable is not already
        being used by another @synthesize.
        (objc_add_dynamic_declaration_for_property): Iterate over
        IMPL_PROPERTY_DECL, not CLASS_PROPERTY_DECL, when checking for an
        existing @synthesize or @dynamic declaration.
        (objc_synthesize_getter): Search for the getter declaration in
        protocols and superclasses as well.
        (objc_synthesize_setter): Search for the setter declaration in
        protocols and superclasses as well.

In gcc/testsuite/:
2010-11-08  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc.dg/property/synthesize-3.m: New.
        * objc.dg/property/synthesize-4.m: New.
        * objc.dg/property/synthesize-5.m: New.
        * objc.dg/property/synthesize-6.m: New.
        * obj-c++.dg/property/synthesize-3.mm: New.
        * obj-c++.dg/property/synthesize-4.mm: New.
        * obj-c++.dg/property/synthesize-5.mm: New.
        * obj-c++.dg/property/synthesize-6.mm: New.

From-SVN: r166456
This commit is contained in:
Nicola Pero 2010-11-08 22:04:03 +00:00 committed by Nicola Pero
parent 4ca5d2a7bd
commit 4741888d03
11 changed files with 438 additions and 25 deletions

View File

@ -1,3 +1,21 @@
2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com>
* objc-act.c (objc_add_synthesize_declaration_for_property):
Iterate over IMPL_PROPERTY_DECL, not CLASS_PROPERTY_DECL, when
checking for an existing @synthesize or @dynamic declaration.
Search for an inherited @property declaration if none is found in
the local interface. If the required instance variable does not
exist, return instead of trying to continue to prevent a compiler
crash later. Check that the instance variable is not already
being used by another @synthesize.
(objc_add_dynamic_declaration_for_property): Iterate over
IMPL_PROPERTY_DECL, not CLASS_PROPERTY_DECL, when checking for an
existing @synthesize or @dynamic declaration.
(objc_synthesize_getter): Search for the getter declaration in
protocols and superclasses as well.
(objc_synthesize_setter): Search for the setter declaration in
protocols and superclasses as well.
2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com>
* objc-act.c (lookup_property): When checking categories, also

View File

@ -9363,7 +9363,7 @@ lookup_ivar (tree interface, tree instance_variable_name)
/* This routine synthesizes a 'getter' method. This is only called
for @synthesize properties. */
static void
objc_synthesize_getter (tree klass, tree class_method, tree property)
objc_synthesize_getter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree property)
{
location_t location = DECL_SOURCE_LOCATION (property);
tree fn, decl;
@ -9375,9 +9375,9 @@ objc_synthesize_getter (tree klass, tree class_method, tree property)
PROPERTY_GETTER_NAME (property)))
return;
/* Find declaration of the property getter in the interface. There
must be one. TODO: Search superclasses as well. */
decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_GETTER_NAME (property));
/* Find declaration of the property getter in the interface (or
superclass, or protocol). There must be one. */
decl = lookup_method_static (klass, PROPERTY_GETTER_NAME (property), 0);
/* If one not declared in the interface, this condition has already
been reported as user error (because property was not declared in
@ -9542,7 +9542,7 @@ objc_synthesize_getter (tree klass, tree class_method, tree property)
/* This routine synthesizes a 'setter' method. */
static void
objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
objc_synthesize_setter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree property)
{
location_t location = DECL_SOURCE_LOCATION (property);
tree fn, decl;
@ -9554,9 +9554,9 @@ objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
PROPERTY_SETTER_NAME (property)))
return;
/* Find declaration of the property setter in the interface. There
must be one. TODO: Search superclasses as well. */
decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_SETTER_NAME (property));
/* Find declaration of the property setter in the interface (or
superclass, or protocol). There must be one. */
decl = lookup_method_static (klass, PROPERTY_SETTER_NAME (property), 0);
/* If one not declared in the interface, this condition has already
been reported as user error (because property was not declared in
@ -9736,10 +9736,11 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac
{
/* Find the @property declaration. */
tree property;
tree x;
/* Check that synthesize or dynamic has not already been used for
the same property. */
for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
for (property = IMPL_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
if (PROPERTY_NAME (property) == property_name)
{
location_t original_location = DECL_SOURCE_LOCATION (property);
@ -9756,12 +9757,9 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac
return;
}
/* Check that the property is declared in the interface. */
/* TODO: This only check the immediate class; we need to check the
superclass (and categories ?) as well. */
for (property = CLASS_PROPERTY_DECL (interface); property; property = TREE_CHAIN (property))
if (PROPERTY_NAME (property) == property_name)
break;
/* Check that the property is declared in the interface. It could
also be declared in a superclass or protocol. */
property = lookup_property (interface, property_name);
if (!property)
{
@ -9783,18 +9781,37 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac
if (ivar_name == NULL_TREE)
ivar_name = property_name;
/* Check that the instance variable exists. You can only use an
instance variable from the same class, not one from the
superclass. */
/* Check that the instance variable exists. You can only use a
non-private instance variable from the same class, not one from
the superclass (this makes sense as it allows us to check that an
instance variable is only used in one synthesized property). */
if (!is_ivar (CLASS_IVARS (interface), ivar_name))
error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar",
IDENTIFIER_POINTER (property_name));
{
error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar",
IDENTIFIER_POINTER (property_name));
return;
}
/* TODO: Check that the types of the instance variable and of the
property match. */
/* TODO: Check that no other property is using the same instance
/* Check that no other property is using the same instance
variable. */
for (x = IMPL_PROPERTY_DECL (objc_implementation_context); x; x = TREE_CHAIN (x))
if (PROPERTY_IVAR_NAME (x) == ivar_name)
{
location_t original_location = DECL_SOURCE_LOCATION (x);
error_at (location, "property %qs is using the same instance variable as property %qs",
IDENTIFIER_POINTER (property_name),
IDENTIFIER_POINTER (PROPERTY_NAME (x)));
if (original_location != UNKNOWN_LOCATION)
inform (original_location, "originally specified here");
/* We keep going on. This won't cause the compiler to fail;
the failure would most likely be at runtime. */
}
/* Note that a @synthesize (and only a @synthesize) always sets
PROPERTY_IVAR_NAME to a non-NULL_TREE. You can recognize a
@ -9876,7 +9893,7 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface,
/* Check that synthesize or dynamic has not already been used for
the same property. */
for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
for (property = IMPL_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
if (PROPERTY_NAME (property) == property_name)
{
location_t original_location = DECL_SOURCE_LOCATION (property);
@ -9912,9 +9929,10 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface,
METHOD_PROPERTY_CONTEXT that points to the original
PROPERTY_DECL; when we check that these methods have been
implemented, we need to easily find that they are associated
with a dynamic property. TODO: Clean this up; maybe the
@property PROPERTY_DECL should contain a reference to the
@dynamic PROPERTY_DECL ? */
with a dynamic property. TODO: Remove this hack; it will not
work with properties in a protocol that may be implemented by
different classes and be @dynamic in some, and non-@dynamic
in other ones. */
PROPERTY_DYNAMIC (property) = 1;
/* We have to copy the property, because we want to chain it to

View File

@ -1,3 +1,14 @@
2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com>
* objc.dg/property/synthesize-3.m: New.
* objc.dg/property/synthesize-4.m: New.
* objc.dg/property/synthesize-5.m: New.
* objc.dg/property/synthesize-6.m: New.
* obj-c++.dg/property/synthesize-3.mm: New.
* obj-c++.dg/property/synthesize-4.mm: New.
* obj-c++.dg/property/synthesize-5.mm: New.
* obj-c++.dg/property/synthesize-6.mm: New.
2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com>
* objc.dg/property/at-property-5.m: Updated test.

View File

@ -0,0 +1,66 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do run } */
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
/* Test @synthesize for a @property which is not declared directly in
the @interface, but in a @protocol that the @interface conforms
to. */
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdlib.h>
@interface MyRootClass
{
Class isa;
}
+ (id) initialize;
+ (id) alloc;
- (id) init;
@end
@implementation MyRootClass
+ (id) initialize { return self; }
+ (id) alloc { return class_createInstance (self, 0); }
- (id) init { return self; }
@end
@protocol MyProtocol
@property int v1;
@end
@protocol MyProtocol2
@property int v2;
@end
@interface Test : MyRootClass <MyProtocol, MyProtocol2>
{
int v1;
int _v2;
}
@end
@implementation Test
@synthesize v1;
@synthesize v2 = _v2;
@end
int main (void)
{
Test *object = [[Test alloc] init];
/* Check that the synthesized methods exist and work. Do not invoke
them via property syntax - that is another test. Here we just
want to test the synthesis of the methods. */
[object setV1: 400];
if ([object v1] != 400)
abort ();
[object setV2: 31];
if ([object v2] != 31)
abort ();
return 0;
}

View File

@ -0,0 +1,67 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do run } */
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
/* Test @synthesize for a @property where the setter/getter are also
declared by the user. This is fine. */
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdlib.h>
@interface MyRootClass
{
Class isa;
}
+ (id) initialize;
+ (id) alloc;
- (id) init;
@end
@implementation MyRootClass
+ (id) initialize { return self; }
+ (id) alloc { return class_createInstance (self, 0); }
- (id) init { return self; }
@end
@protocol MyProtocol
@property int v1;
@end
@protocol MyProtocol2
@property int v2;
@end
@interface Test : MyRootClass <MyProtocol, MyProtocol2>
{
int v1;
int _v2;
}
- (int)v1;
- (void)setV1: (int)aNumber;
- (int)v2;
@end
@implementation Test
@synthesize v1;
@synthesize v2 = _v2;
@end
int main (void)
{
Test *object = [[Test alloc] init];
/* We use dot-syntax here as this is just a general test that
user-declared setters/getters don't cause confusion. */
object.v1 = 400;
if (object.v1 != 400)
abort ();
object.v2 = 31;
if (object.v2 != 31)
abort ();
return 0;
}

View File

@ -0,0 +1,18 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
/* Test that @synthesize does not ICE if asked to use a non-existing
ivar. */
#include <objc/objc.h>
@interface Test
@property int v1;
@end
@implementation Test
@synthesize v1; /* { dg-error "must be an existing ivar" } */
@end
/* { dg-warning "incomplete implementation" "" { target *-*-* } 15 } */
/* { dg-warning "method definition for .-setV1:. not found" "" { target *-*-* } 15 } */
/* { dg-warning "method definition for .-v1. not found" "" { target *-*-* } 15 } */

View File

@ -0,0 +1,32 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
/* Test that each @synthesize is using a different instance variable,
and that it must belong to the class (not to a superclass). */
#include <objc/objc.h>
@interface Test
{
int v;
int w;
}
@property int v1;
@property int v2;
@end
#if 0 /* This is a problem in the testsuite; the compiler is fine, but the testsuite still barfs on the following. */
@implementation Test
@synthesize v1 = v; /* dg-message "originally specified here" */
@synthesize v2 = v; /* dg-error "property .v2. is using the same instance variable as property .v1." */
@end
#endif
@interface Test2 : Test
@property int w1;
@end
@implementation Test2
@synthesize w1; /* { dg-error "ivar .w1. used by .@synthesize. declaration must be an existing ivar" } */
@end
/* { dg-warning "incomplete implementation" "" { target *-*-* } 29 } */
/* { dg-warning "method definition for .-setW1:. not found" "" { target *-*-* } 29 } */
/* { dg-warning "method definition for .-w1. not found" "" { target *-*-* } 29 } */

View File

@ -0,0 +1,66 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do run } */
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
/* Test @synthesize for a @property which is not declared directly in
the @interface, but in a @protocol that the @interface conforms
to. */
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdlib.h>
@interface MyRootClass
{
Class isa;
}
+ (id) initialize;
+ (id) alloc;
- (id) init;
@end
@implementation MyRootClass
+ (id) initialize { return self; }
+ (id) alloc { return class_createInstance (self, 0); }
- (id) init { return self; }
@end
@protocol MyProtocol
@property int v1;
@end
@protocol MyProtocol2
@property int v2;
@end
@interface Test : MyRootClass <MyProtocol, MyProtocol2>
{
int v1;
int _v2;
}
@end
@implementation Test
@synthesize v1;
@synthesize v2 = _v2;
@end
int main (void)
{
Test *object = [[Test alloc] init];
/* Check that the synthesized methods exist and work. Do not invoke
them via property syntax - that is another test. Here we just
want to test the synthesis of the methods. */
[object setV1: 400];
if ([object v1] != 400)
abort ();
[object setV2: 31];
if ([object v2] != 31)
abort ();
return 0;
}

View File

@ -0,0 +1,67 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do run } */
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
/* Test @synthesize for a @property where the setter/getter are also
declared by the user. This is fine. */
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdlib.h>
@interface MyRootClass
{
Class isa;
}
+ (id) initialize;
+ (id) alloc;
- (id) init;
@end
@implementation MyRootClass
+ (id) initialize { return self; }
+ (id) alloc { return class_createInstance (self, 0); }
- (id) init { return self; }
@end
@protocol MyProtocol
@property int v1;
@end
@protocol MyProtocol2
@property int v2;
@end
@interface Test : MyRootClass <MyProtocol, MyProtocol2>
{
int v1;
int _v2;
}
- (int)v1;
- (void)setV1: (int)aNumber;
- (int)v2;
@end
@implementation Test
@synthesize v1;
@synthesize v2 = _v2;
@end
int main (void)
{
Test *object = [[Test alloc] init];
/* We use dot-syntax here as this is just a general test that
user-declared setters/getters don't cause confusion. */
object.v1 = 400;
if (object.v1 != 400)
abort ();
object.v2 = 31;
if (object.v2 != 31)
abort ();
return 0;
}

View File

@ -0,0 +1,18 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
/* Test that @synthesize does not ICE if asked to use a non-existing
ivar. */
#include <objc/objc.h>
@interface Test
@property int v1;
@end
@implementation Test
@synthesize v1; /* { dg-error "must be an existing ivar" } */
@end
/* { dg-warning "incomplete implementation" "" { target *-*-* } 15 } */
/* { dg-warning "method definition for .-setV1:. not found" "" { target *-*-* } 15 } */
/* { dg-warning "method definition for .-v1. not found" "" { target *-*-* } 15 } */

View File

@ -0,0 +1,32 @@
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
/* Test that each @synthesize is using a different instance variable,
and that it must belong to the class (not to a superclass). */
#include <objc/objc.h>
@interface Test
{
int v;
int w;
}
@property int v1;
@property int v2;
@end
@implementation Test
@synthesize v1 = v; /* { dg-message "originally specified here" } */
@synthesize v2 = v; /* { dg-error "property .v2. is using the same instance variable as property .v1." } */
@end
@interface Test2 : Test
@property int w1;
@end
@implementation Test2
@synthesize w1; /* { dg-error "ivar .w1. used by .@synthesize. declaration must be an existing ivar" } */
@end
/* { dg-warning "incomplete implementation" "" { target *-*-* } 29 } */
/* { dg-warning "method definition for .-setW1:. not found" "" { target *-*-* } 29 } */
/* { dg-warning "method definition for .-w1. not found" "" { target *-*-* } 29 } */