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> 2010-11-10 Joseph Myers <joseph@codesourcery.com>
* objc-act.c (objc_init): Use %' in diagnostic. * objc-act.c (objc_init): Use %' in diagnostic.
......
...@@ -1184,22 +1184,41 @@ objc_add_property_declaration (location_t location, tree decl, ...@@ -1184,22 +1184,41 @@ objc_add_property_declaration (location_t location, tree decl,
return; return;
} }
if (property_readonly) /* We now check that the new and old property declarations have
{ the same types (or compatible one). In the Objective-C
/* If the property is readonly, it is Ok if the property tradition of loose type checking, we do type-checking but
type is a specialization of the previously declared one. only generate warnings (not errors) if they do not match.
Eg, the superclass returns 'NSArray' while the subclass For non-readonly properties, the types must match exactly;
returns 'NSMutableArray'. */ for readonly properties, it is allowed to use a "more
specialized" type in the new property declaration. Eg, the
/* TODO: Check that the types are the same, or more specialized. */ 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
else object to the superclass, which is allowed, you'd still
{ expect the getter to return an (NSArray *), which works since
/* Else, the types must match exactly. */ an (NSMutableArray *) is an (NSArray *) too. So, the set of
objects belonging to the type of the new @property should be
/* TODO: Check that property types are identical. */ 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) ...@@ -1445,15 +1464,10 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
else if (t == self_decl) else if (t == self_decl)
interface_type = lookup_interface (CLASS_NAME (implementation_template)); interface_type = lookup_interface (CLASS_NAME (implementation_template));
/* TODO: Protocols. */
if (interface_type) if (interface_type)
{ {
if (TREE_CODE (objc_method_context) != CLASS_METHOD_DECL) if (TREE_CODE (objc_method_context) != CLASS_METHOD_DECL)
{
x = lookup_property (interface_type, property_ident); x = lookup_property (interface_type, property_ident);
/* TODO: Protocols. */
}
if (x == NULL_TREE) if (x == NULL_TREE)
{ {
...@@ -1468,8 +1482,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident) ...@@ -1468,8 +1482,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
if (t == self_decl) if (t == self_decl)
implementation = objc_implementation_context; implementation = objc_implementation_context;
/* TODO: Protocols. */
x = maybe_make_artificial_property_decl x = maybe_make_artificial_property_decl
(interface_type, implementation, NULL_TREE, (interface_type, implementation, NULL_TREE,
property_ident, property_ident,
...@@ -1544,8 +1556,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident) ...@@ -1544,8 +1556,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
} }
} }
/* TODO: Fix compiling super.accessor. */
if (x) if (x)
{ {
tree expression; tree expression;
...@@ -2121,8 +2131,8 @@ objc_common_type (tree type1, tree type2) ...@@ -2121,8 +2131,8 @@ objc_common_type (tree type1, tree type2)
returning 'true', this routine may issue warnings related to, e.g., returning 'true', this routine may issue warnings related to, e.g.,
protocol conformance. When returning 'false', the routine must protocol conformance. When returning 'false', the routine must
produce absolutely no warnings; the C or C++ front-end will do so 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, instead, if needed. If either LTYP or RTYP is not an Objective-C
the routine must return 'false'. type, the routine must return 'false'.
The ARGNO parameter is encoded as follows: The ARGNO parameter is encoded as follows:
>= 1 Parameter number (CALLEE contains function being called); >= 1 Parameter number (CALLEE contains function being called);
...@@ -2130,8 +2140,11 @@ objc_common_type (tree type1, tree type2) ...@@ -2130,8 +2140,11 @@ objc_common_type (tree type1, tree type2)
-1 Assignment; -1 Assignment;
-2 Initialization; -2 Initialization;
-3 Comparison (LTYP and RTYP may match in either direction); -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 bool
objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
...@@ -2216,10 +2229,23 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) ...@@ -2216,10 +2229,23 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE) if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE)
rcls = NULL_TREE; rcls = NULL_TREE;
/* If either type is an unqualified 'id', we're done. */ /* 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)) if ((!lproto && objc_is_object_id (ltyp))
|| (!rproto && objc_is_object_id (rtyp))) || (!rproto && objc_is_object_id (rtyp)))
return true; 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)); pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp));
...@@ -2236,13 +2262,22 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) ...@@ -2236,13 +2262,22 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
else else
{ {
if (!pointers_compatible) if (!pointers_compatible)
{
/* 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 pointers_compatible
= (objc_is_object_id (ltyp) || objc_is_object_id (rtyp)); = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
else
pointers_compatible = objc_is_object_id (ltyp);
}
if (!pointers_compatible) if (!pointers_compatible)
pointers_compatible = DERIVED_FROM_P (ltyp, rtyp); 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); pointers_compatible = DERIVED_FROM_P (rtyp, ltyp);
} }
...@@ -2268,6 +2303,7 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) ...@@ -2268,6 +2303,7 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
ObjC-specific. */ ObjC-specific. */
switch (argno) switch (argno)
{ {
case -5:
case -4: case -4:
return false; return false;
...@@ -9797,19 +9833,32 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac ...@@ -9797,19 +9833,32 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac
if (ivar_name == NULL_TREE) if (ivar_name == NULL_TREE)
ivar_name = property_name; ivar_name = property_name;
/* Check that the instance variable exists. You can only use a /* Check that the instance variable exists. You can only use an
non-private instance variable from the same class, not one from instance variable from the same class, not one from the
the superclass (this makes sense as it allows us to check that an superclass (this makes sense as it allows us to check that an
instance variable is only used in one synthesized property). */ instance variable is only used in one synthesized property). */
if (!is_ivar (CLASS_IVARS (interface), ivar_name)) {
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", error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar",
IDENTIFIER_POINTER (property_name)); IDENTIFIER_POINTER (property_name));
return; return;
} }
/* TODO: Check that the types of the instance variable and of the /* If the instance variable has a different C type, we warn. */
property match. */ 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 /* Check that no other property is using the same instance
variable. */ 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> 2010-11-11 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/cpp/warn-normalized-3.c: Update expected note text. * 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