diff mbox

ObjC/ObjC++ - added missing checks for property types

Message ID 1289430762.95144315@192.168.4.58
State New
Headers show

Commit Message

Nicola Pero Nov. 10, 2010, 11:12 p.m. UTC
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  <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.

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.

Comments

Mike Stump Nov. 11, 2010, 12:48 a.m. UTC | #1
On Nov 10, 2010, at 3:12 PM, Nicola Pero wrote:
> 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 ?

Ok.
diff mbox

Patch

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  <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 (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  <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-10  Quentin Neill  <quentin.neill.gnu@gmail.com>
 
 	* 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 <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
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 <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
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 <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
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 <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