mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-10 02:00:37 +08:00
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
This commit is contained in:
parent
a1d8aa4b1f
commit
10e34e6eb1
gcc
@ -1,3 +1,14 @@
|
||||
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. */
|
||||
/* 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. */
|
||||
|
||||
/* TODO: Check that property types are identical. */
|
||||
;
|
||||
/* 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. */
|
||||
|
@ -1,3 +1,10 @@
|
||||
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.
|
||||
|
82
gcc/testsuite/obj-c++.dg/property/at-property-20.mm
Normal file
82
gcc/testsuite/obj-c++.dg/property/at-property-20.mm
Normal file
@ -0,0 +1,82 @@
|
||||
/* 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
|
80
gcc/testsuite/obj-c++.dg/property/synthesize-8.mm
Normal file
80
gcc/testsuite/obj-c++.dg/property/synthesize-8.mm
Normal file
@ -0,0 +1,80 @@
|
||||
/* 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
|
81
gcc/testsuite/objc.dg/property/at-property-20.m
Normal file
81
gcc/testsuite/objc.dg/property/at-property-20.m
Normal file
@ -0,0 +1,81 @@
|
||||
/* 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
|
80
gcc/testsuite/objc.dg/property/synthesize-8.m
Normal file
80
gcc/testsuite/objc.dg/property/synthesize-8.m
Normal file
@ -0,0 +1,80 @@
|
||||
/* 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
|
Loading…
x
Reference in New Issue
Block a user