Commit 10e34e6e by Nicola Pero Committed by Nicola Pero

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

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

        * objc-act.c (objc_add_property_declaration): Check that the type
        of a property and of an inherited property match.
        (objc_maybe_build_component_ref): Tidied up indentation and
        comments.
        (objc_common_type): Added new type of check (-5).  If an unknown
        class is involved in a comparison, try to look up its interface.
        (objc_add_synthesize_declaration_for_property): Check that the
        property to synthesize and the instance variable to use have the
        same type.

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

        * objc.dg/property/at-property-20.m: New.
        * objc.dg/property/synthesize-8.m: New.
        * obj-c++.dg/property/at-property-20.m: New.
        * obj-c++.dg/property/synthesize-8.mm: New.

From-SVN: r166612
parent a1d8aa4b
2010-11-11 Nicola Pero <nicola.pero@meta-innovation.com>
* objc-act.c (objc_add_property_declaration): Check that the type
of a property and of an inherited property match.
(objc_maybe_build_component_ref): Tidied up indentation and
comments.
(objc_common_type): Added new type of check (-5).
(objc_add_synthesize_declaration_for_property): Check that the
property to synthesize and the instance variable to use have the
same type.
2010-11-10 Joseph Myers <joseph@codesourcery.com>
* objc-act.c (objc_init): Use %' in diagnostic.
......
......@@ -1184,22 +1184,41 @@ objc_add_property_declaration (location_t location, tree decl,
return;
}
if (property_readonly)
{
/* If the property is readonly, it is Ok if the property
type is a specialization of the previously declared one.
Eg, the superclass returns 'NSArray' while the subclass
returns 'NSMutableArray'. */
/* TODO: Check that the types are the same, or more specialized. */
;
}
else
{
/* Else, the types must match exactly. */
/* TODO: Check that property types are identical. */
;
/* We now check that the new and old property declarations have
the same types (or compatible one). In the Objective-C
tradition of loose type checking, we do type-checking but
only generate warnings (not errors) if they do not match.
For non-readonly properties, the types must match exactly;
for readonly properties, it is allowed to use a "more
specialized" type in the new property declaration. Eg, the
superclass has a getter returning (NSArray *) and the
subclass a getter returning (NSMutableArray *). The object's
getter returns an (NSMutableArray *); but if you cast the
object to the superclass, which is allowed, you'd still
expect the getter to return an (NSArray *), which works since
an (NSMutableArray *) is an (NSArray *) too. So, the set of
objects belonging to the type of the new @property should be
a subset of the set of objects belonging to the type of the
old @property. This is what "specialization" means. And the
reason it only applies to readonly properties is that for a
readwrite property the setter would have the opposite
requirement - ie that the superclass type is more specialized
then the subclass one; hence the only way to satisfy both
constraints is that the types match. */
/* If the types are not the same in the C sense, we warn ... */
if (!comptypes (TREE_TYPE (x), TREE_TYPE (decl))
/* ... unless the property is readonly, in which case we
allow a new, more specialized, declaration. */
&& (!property_readonly
|| !objc_compare_types (TREE_TYPE (x),
TREE_TYPE (decl), -5, NULL_TREE)))
{
warning_at (location, 0,
"type of property %qD conflicts with previous declaration", decl);
if (original_location != UNKNOWN_LOCATION)
inform (original_location, "originally specified here");
return;
}
}
......@@ -1445,15 +1464,10 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
else if (t == self_decl)
interface_type = lookup_interface (CLASS_NAME (implementation_template));
/* TODO: Protocols. */
if (interface_type)
{
if (TREE_CODE (objc_method_context) != CLASS_METHOD_DECL)
{
x = lookup_property (interface_type, property_ident);
/* TODO: Protocols. */
}
x = lookup_property (interface_type, property_ident);
if (x == NULL_TREE)
{
......@@ -1468,8 +1482,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
if (t == self_decl)
implementation = objc_implementation_context;
/* TODO: Protocols. */
x = maybe_make_artificial_property_decl
(interface_type, implementation, NULL_TREE,
property_ident,
......@@ -1544,8 +1556,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
}
}
/* TODO: Fix compiling super.accessor. */
if (x)
{
tree expression;
......@@ -2121,8 +2131,8 @@ objc_common_type (tree type1, tree type2)
returning 'true', this routine may issue warnings related to, e.g.,
protocol conformance. When returning 'false', the routine must
produce absolutely no warnings; the C or C++ front-end will do so
instead, if needed. If either LTYP or RTYP is not an Objective-C type,
the routine must return 'false'.
instead, if needed. If either LTYP or RTYP is not an Objective-C
type, the routine must return 'false'.
The ARGNO parameter is encoded as follows:
>= 1 Parameter number (CALLEE contains function being called);
......@@ -2130,8 +2140,11 @@ objc_common_type (tree type1, tree type2)
-1 Assignment;
-2 Initialization;
-3 Comparison (LTYP and RTYP may match in either direction);
-4 Silent comparison (for C++ overload resolution).
*/
-4 Silent comparison (for C++ overload resolution);
-5 Silent "specialization" comparison for RTYP to be a "specialization"
of LTYP (a specialization means that RTYP is LTYP plus some constraints,
so that each object of type RTYP is also of type LTYP). This is used
when comparing property types. */
bool
objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
......@@ -2216,11 +2229,24 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE)
rcls = NULL_TREE;
/* If either type is an unqualified 'id', we're done. */
if ((!lproto && objc_is_object_id (ltyp))
|| (!rproto && objc_is_object_id (rtyp)))
return true;
/* If either type is an unqualified 'id', we're done. This is because
an 'id' can be assigned to or from any type with no warnings. */
if (argno != -5)
{
if ((!lproto && objc_is_object_id (ltyp))
|| (!rproto && objc_is_object_id (rtyp)))
return true;
}
else
{
/* For property checks, though, an 'id' is considered the most
general type of object, hence if you try to specialize an
'NSArray *' (ltyp) property with an 'id' (rtyp) one, we need
to warn. */
if (!lproto && objc_is_object_id (ltyp))
return true;
}
pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp));
/* If the underlying types are the same, and at most one of them has
......@@ -2236,13 +2262,22 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
else
{
if (!pointers_compatible)
pointers_compatible
= (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
{
/* Again, if any of the two is an 'id', we're satisfied,
unless we're comparing properties, in which case only an
'id' on the left-hand side (old property) is good
enough. */
if (argno != -5)
pointers_compatible
= (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
else
pointers_compatible = objc_is_object_id (ltyp);
}
if (!pointers_compatible)
pointers_compatible = DERIVED_FROM_P (ltyp, rtyp);
if (!pointers_compatible && argno <= -3)
if (!pointers_compatible && (argno == -3 || argno == -4))
pointers_compatible = DERIVED_FROM_P (rtyp, ltyp);
}
......@@ -2268,6 +2303,7 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
ObjC-specific. */
switch (argno)
{
case -5:
case -4:
return false;
......@@ -9797,19 +9833,32 @@ 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 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
/* Check that the instance variable exists. You can only use an
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));
return;
}
{
tree ivar = is_ivar (CLASS_IVARS (interface), ivar_name);
if (!ivar)
{
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. */
/* If the instance variable has a different C type, we warn. */
if (!comptypes (TREE_TYPE (property), TREE_TYPE (ivar)))
{
location_t original_location = DECL_SOURCE_LOCATION (ivar);
error_at (location, "property %qs is using instance variable %qs of incompatible type",
IDENTIFIER_POINTER (property_name),
IDENTIFIER_POINTER (ivar_name));
if (original_location != UNKNOWN_LOCATION)
inform (original_location, "originally specified here");
}
}
/* Check that no other property is using the same instance
variable. */
......
2010-11-11 Nicola Pero <nicola.pero@meta-innovation.com>
* objc.dg/property/at-property-20.m: New.
* objc.dg/property/synthesize-8.m: New.
* obj-c++.dg/property/at-property-20.m: New.
* obj-c++.dg/property/synthesize-8.mm: New.
2010-11-11 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/cpp/warn-normalized-3.c: Update expected note text.
......
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
#include <objc/objc.h>
/* Test that if you have a property declared in a class and a
sub-class, the types match (unless it's a readonly property, in
which case a "specialization" is enough). */
@protocol MyProtocolA
- (void) doNothingA;
@end
@protocol MyProtocolB
- (void) doNothingB;
@end
@interface MyRootClass
{
Class isa;
}
@end
@interface MySubClass1 : MyRootClass
@end
@interface MySubClass2 : MyRootClass
@end
@interface MySubClass3 : MyRootClass <MyProtocolA>
@end
@interface MySubClass4 : MySubClass1
@end
/* Now, the test. */
@interface MyClass : MyRootClass
{ }
@property (assign) id <MyProtocolA> a; /* { dg-warning "originally specified here" } */
@property int b; /* { dg-warning "originally specified here" } */
@property float c; /* { dg-warning "originally specified here" } */
@property (assign) MyRootClass *d; /* { dg-warning "originally specified here" } */
@property (assign) MySubClass1 *e; /* { dg-warning "originally specified here" } */
/* FIXME: The compiler seems to generate messages correctly, but the testsuite still fails the test. */
/*@property (assign, readonly) MySubClass1 *f; */ /* dg-warning "originally specified here" */
@property (assign) MySubClass3 *g; /* { dg-warning "originally specified here" } */
/*@property (assign, readonly) MySubClass3 *h; */ /* dg-warning "originally specified here" */
@end
/* The following are all OK because they are identical. */
@interface MyClass2 : MyClass
{ }
@property (assign) id a;
@property int b;
@property float c;
@property (assign) MyRootClass *d;
@property (assign) MySubClass1 *e;
@property (assign, readonly) MySubClass1 *f;
@property (assign) MySubClass3 *g;
@property (assign, readonly) MySubClass3 *h;
@end
/* The following are not OK. */
@interface MyClass3 : MyClass
{ }
@property (assign) MySubClass1 *a; /* { dg-warning "type of property .a. conflicts with previous declaration" } */
@property float b; /* { dg-warning "type of property .b. conflicts with previous declaration" } */
@property int c; /* { dg-warning "type of property .c. conflicts with previous declaration" } */
@property (assign) id d; /* { dg-warning "type of property .d. conflicts with previous declaration" } */
@property (assign) MyRootClass *e; /* { dg-warning "type of property .e. conflicts with previous declaration" } */
/*@property (assign, readonly) MyRootClass *f; */ /* dg-warning "type of property .f. conflicts with previous declaration" */
@property (assign) MySubClass2 *g; /* { dg-warning "type of property .g. conflicts with previous declaration" } */
/*@property (assign, readonly) MySubClass2 *h; */ /* dg-warning "type of property .h. conflicts with previous declaration" */
@end
/* The following are OK. */
@interface MyClass4 : MyClass
{ }
@property (assign, readonly) MySubClass4 *f;
@property (assign, readonly) MySubClass3 <MyProtocolB> *h;
@end
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
/* Test that when using @synthesize the instance variable and the
property have exactly the same type. */
#include <objc/objc.h>
@protocol MyProtocol
- (void)aMethod;
@end
@interface ClassA
@end
@interface ClassB : ClassA
@end
/* This is all OK. */
@interface Test
{
int v;
float w;
id x;
Test *y;
id <MyProtocol> *z;
ClassA *a;
ClassB *b;
ClassA <MyProtocol> *c;
}
@property (assign) int v;
@property (assign) float w;
@property (assign) id x;
@property (assign) Test *y;
@property (assign) id <MyProtocol> *z;
@property (assign) ClassA *a;
@property (assign) ClassB *b;
@end
@implementation Test
@synthesize v;
@synthesize w;
@synthesize x;
@synthesize y;
@synthesize z;
@synthesize a;
@synthesize b;
@end
/* This is not OK. */
@interface Test2
{
int v; /* { dg-warning "originally specified here" } */
float w; /* { dg-warning "originally specified here" } */
id x; /* { dg-warning "originally specified here" } */
Test *y; /* { dg-warning "originally specified here" } */
id <MyProtocol> *z; /* { dg-warning "originally specified here" } */
ClassA *a; /* { dg-warning "originally specified here" } */
ClassB *b; /* { dg-warning "originally specified here" } */
}
@property (assign) float v;
@property (assign) id w;
@property (assign) int x;
@property (assign) id y;
@property (assign) Test *z;
@property (assign) ClassB *a;
@property (assign) ClassA *b;
@end
@implementation Test2
@synthesize v; /* { dg-error "property .v. is using instance variable .v. of incompatible type" } */
@synthesize w; /* { dg-error "property .w. is using instance variable .w. of incompatible type" } */
@synthesize x; /* { dg-error "property .x. is using instance variable .x. of incompatible type" } */
@synthesize y; /* { dg-error "property .y. is using instance variable .y. of incompatible type" } */
@synthesize z; /* { dg-error "property .z. is using instance variable .z. of incompatible type" } */
@synthesize a; /* { dg-error "property .a. is using instance variable .a. of incompatible type" } */
@synthesize b; /* { dg-error "property .b. is using instance variable .b. of incompatible type" } */
@end
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
#include <objc/objc.h>
/* Test that if you have a property declared in a class and a
sub-class, the types match (unless it's a readonly property, in
which case a "specialization" is enough). */
@protocol MyProtocolA
- (void) doNothingA;
@end
@protocol MyProtocolB
- (void) doNothingB;
@end
@interface MyRootClass
{
Class isa;
}
@end
@interface MySubClass1 : MyRootClass
@end
@interface MySubClass2 : MyRootClass
@end
@interface MySubClass3 : MyRootClass <MyProtocolA>
@end
@interface MySubClass4 : MySubClass1
@end
/* Now, the test. */
@interface MyClass : MyRootClass
{ }
@property (assign) id <MyProtocolA> a; /* { dg-message "originally specified here" } */
@property int b; /* { dg-message "originally specified here" } */
@property float c; /* { dg-message "originally specified here" } */
@property (assign) MyRootClass *d; /* { dg-message "originally specified here" } */
@property (assign) MySubClass1 *e; /* { dg-message "originally specified here" } */
@property (assign, readonly) MySubClass1 *f; /* { dg-message "originally specified here" } */
@property (assign) MySubClass3 *g; /* { dg-message "originally specified here" } */
@property (assign, readonly) MySubClass3 *h; /* { dg-message "originally specified here" } */
@end
/* The following are all OK because they are identical. */
@interface MyClass2 : MyClass
{ }
@property (assign) id a;
@property int b;
@property float c;
@property (assign) MyRootClass *d;
@property (assign) MySubClass1 *e;
@property (assign, readonly) MySubClass1 *f;
@property (assign) MySubClass3 *g;
@property (assign, readonly) MySubClass3 *h;
@end
/* The following are not OK. */
@interface MyClass3 : MyClass
{ }
@property (assign) MySubClass1 *a; /* { dg-warning "type of property .a. conflicts with previous declaration" } */
@property float b; /* { dg-warning "type of property .b. conflicts with previous declaration" } */
@property int c; /* { dg-warning "type of property .c. conflicts with previous declaration" } */
@property (assign) id d; /* { dg-warning "type of property .d. conflicts with previous declaration" } */
@property (assign) MyRootClass *e; /* { dg-warning "type of property .e. conflicts with previous declaration" } */
@property (assign, readonly) MyRootClass *f; /* { dg-warning "type of property .f. conflicts with previous declaration" } */
@property (assign) MySubClass2 *g; /* { dg-warning "type of property .g. conflicts with previous declaration" } */
@property (assign, readonly) MySubClass2 *h; /* { dg-warning "type of property .h. conflicts with previous declaration" } */
@end
/* The following are OK. */
@interface MyClass4 : MyClass
{ }
@property (assign, readonly) MySubClass4 *f;
@property (assign, readonly) MySubClass3 <MyProtocolB> *h;
@end
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
/* { dg-do compile } */
/* Test that when using @synthesize the instance variable and the
property have exactly the same type. */
#include <objc/objc.h>
@protocol MyProtocol
- (void)aMethod;
@end
@interface ClassA
@end
@interface ClassB : ClassA
@end
/* This is all OK. */
@interface Test
{
int v;
float w;
id x;
Test *y;
id <MyProtocol> *z;
ClassA *a;
ClassB *b;
ClassA <MyProtocol> *c;
}
@property (assign) int v;
@property (assign) float w;
@property (assign) id x;
@property (assign) Test *y;
@property (assign) id <MyProtocol> *z;
@property (assign) ClassA *a;
@property (assign) ClassB *b;
@end
@implementation Test
@synthesize v;
@synthesize w;
@synthesize x;
@synthesize y;
@synthesize z;
@synthesize a;
@synthesize b;
@end
/* This is not OK. */
@interface Test2
{
int v; /* { dg-message "originally specified here" } */
float w; /* { dg-message "originally specified here" } */
id x; /* { dg-message "originally specified here" } */
Test *y; /* { dg-message "originally specified here" } */
id <MyProtocol> *z; /* { dg-message "originally specified here" } */
ClassA *a; /* { dg-message "originally specified here" } */
ClassB *b; /* { dg-message "originally specified here" } */
}
@property (assign) float v;
@property (assign) id w;
@property (assign) int x;
@property (assign) id y;
@property (assign) Test *z;
@property (assign) ClassB *a;
@property (assign) ClassA *b;
@end
@implementation Test2
@synthesize v; /* { dg-error "property .v. is using instance variable .v. of incompatible type" } */
@synthesize w; /* { dg-error "property .w. is using instance variable .w. of incompatible type" } */
@synthesize x; /* { dg-error "property .x. is using instance variable .x. of incompatible type" } */
@synthesize y; /* { dg-error "property .y. is using instance variable .y. of incompatible type" } */
@synthesize z; /* { dg-error "property .z. is using instance variable .z. of incompatible type" } */
@synthesize a; /* { dg-error "property .a. is using instance variable .a. of incompatible type" } */
@synthesize b; /* { dg-error "property .b. is using instance variable .b. of incompatible type" } */
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment