From patchwork Wed Nov 10 23:12:42 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 70723 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id ABD62B7114 for ; Thu, 11 Nov 2010 10:13:57 +1100 (EST) Received: (qmail 8946 invoked by alias); 10 Nov 2010 23:13:41 -0000 Received: (qmail 8861 invoked by uid 22791); 10 Nov 2010 23:13:25 -0000 X-SWARE-Spam-Status: No, hits=-1.3 required=5.0 tests=AWL, BAYES_00, TW_BJ, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 10 Nov 2010 23:12:51 +0000 Received: from eggs.gnu.org ([140.186.70.92]:40967) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PGJqS-0001ct-2N for gcc-patches@gnu.org; Wed, 10 Nov 2010 18:12:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PGJqQ-0007rL-Or for gcc-patches@gnu.org; Wed, 10 Nov 2010 18:12:49 -0500 Received: from smtp201.iad.emailsrvr.com ([207.97.245.201]:55375) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PGJqQ-0007r2-Kq for gcc-patches@gnu.org; Wed, 10 Nov 2010 18:12:46 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp50.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 4454B3710DD for ; Wed, 10 Nov 2010 18:12:44 -0500 (EST) Received: from dynamic11.wm-web.iad.mlsrvr.com (dynamic11.wm-web.iad1a.rsapps.net [192.168.2.218]) by smtp50.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 0F69B371146 for ; Wed, 10 Nov 2010 18:12:43 -0500 (EST) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic11.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id E8CAEE0086 for ; Wed, 10 Nov 2010 18:12:42 -0500 (EST) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Thu, 11 Nov 2010 00:12:42 +0100 (CET) Date: Thu, 11 Nov 2010 00:12:42 +0100 (CET) Subject: ObjC/ObjC++ - added missing checks for property types From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1289430762.95144315@192.168.4.58> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch adds some missing Objective-C 2.0 checks: * check that a new @property declaration has the same (or compatible) type to an existing, inherited @property declaration; * check that a property to @synthesize has the same type of the instance variable used when synthesizing. Testcases are included. Ok to commit to trunk ? Thanks In gcc/objc/: 2010-11-11 Nicola Pero * 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. In gcc/testsuite/: 2010-11-11 Nicola Pero * 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. Index: gcc/objc/objc-act.c =================================================================== --- gcc/objc/objc-act.c (revision 166565) +++ gcc/objc/objc-act.c (working copy) @@ -1184,23 +1184,42 @@ objc_add_property_declaration (location_t location 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 + 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))) { - /* 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. */ - ; + 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; } - else - { - /* Else, the types must match exactly. */ - - /* TODO: Check that property types are identical. */ - ; - } } /* Create a PROPERTY_DECL node. */ @@ -1445,15 +1464,10 @@ objc_maybe_build_component_ref (tree object, tree 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 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 } } - /* 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 argn 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 argn 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 argn ObjC-specific. */ switch (argno) { + case -5: case -4: return false; @@ -9797,19 +9833,32 @@ objc_add_synthesize_declaration_for_property (loca 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. */ Index: gcc/objc/ChangeLog =================================================================== --- gcc/objc/ChangeLog (revision 166565) +++ gcc/objc/ChangeLog (working copy) @@ -1,3 +1,14 @@ +2010-11-11 Nicola Pero + + * 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 * objc-act.c (dump_base_name): Don't declare here. Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (revision 166565) +++ gcc/testsuite/ChangeLog (working copy) @@ -1,3 +1,10 @@ +2010-11-11 Nicola Pero + + * 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-10 Quentin Neill * g++.dg/other/i386-2.C: Add -mtbm. Index: gcc/testsuite/objc.dg/property/at-property-20.m =================================================================== --- gcc/testsuite/objc.dg/property/at-property-20.m (revision 0) +++ gcc/testsuite/objc.dg/property/at-property-20.m (revision 0) @@ -0,0 +1,81 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* 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 +@end + +@interface MySubClass4 : MySubClass1 +@end + +/* Now, the test. */ + +@interface MyClass : MyRootClass +{ } +@property (assign) id 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 *h; +@end Index: gcc/testsuite/objc.dg/property/synthesize-8.m =================================================================== --- gcc/testsuite/objc.dg/property/synthesize-8.m (revision 0) +++ gcc/testsuite/objc.dg/property/synthesize-8.m (revision 0) @@ -0,0 +1,80 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test that when using @synthesize the instance variable and the + property have exactly the same type. */ + +#include + +@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 *z; + ClassA *a; + ClassB *b; + ClassA *c; +} +@property (assign) int v; +@property (assign) float w; +@property (assign) id x; +@property (assign) Test *y; +@property (assign) id *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 *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 Index: gcc/testsuite/obj-c++.dg/property/at-property-20.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/at-property-20.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/at-property-20.mm (revision 0) @@ -0,0 +1,82 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +#include + +/* 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 +@end + +@interface MySubClass4 : MySubClass1 +@end + +/* Now, the test. */ + +@interface MyClass : MyRootClass +{ } +@property (assign) id 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 *h; +@end Index: gcc/testsuite/obj-c++.dg/property/synthesize-8.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/synthesize-8.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/synthesize-8.mm (revision 0) @@ -0,0 +1,80 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test that when using @synthesize the instance variable and the + property have exactly the same type. */ + +#include + +@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 *z; + ClassA *a; + ClassB *b; + ClassA *c; +} +@property (assign) int v; +@property (assign) float w; +@property (assign) id x; +@property (assign) Test *y; +@property (assign) id *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 *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