Patchwork ObjC/ObjC++: fixed Objective-C 2.0 dot-syntax with multiple assignments and related tricky cases

login
register
mail settings
Submitter Nicola Pero
Date Nov. 15, 2010, 8:06 p.m.
Message ID <1289851606.089714360@192.168.2.229>
Download mbox | patch
Permalink /patch/71272/
State New
Headers show

Comments

Nicola Pero - Nov. 15, 2010, 8:06 p.m.
This patch fixes using the Objective-C 2.0 dot-syntax in cases such as

 object1.property = object2.property = x;

A number of testcases are included showing this and related cases compiling 
and running fine :-)

It also tidies up some details in the implementation of "object.property++" and similar
that I submitted in my previous patch, and cleans up some related testcases.

Ok to commit to trunk ?

Thanks

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

        * objc-act.c (objc_build_setter_call): New.
        (objc_maybe_build_modify_expr): Rewritten to build a compound
        statement.
        (objc_build_incr_expr_for_property_ref): Updated calls to
        objc_maybe_build_modify_expr to call objc_build_setter_call
        instead.  Use build_modify_expr () instead of build2 (MODIFY_EXPR,
        ...).  Use convert () instead of build1 (NOP_EXPR, ...).  Use
        TREE_NO_WARNING on the final compound statement to silence C++
        warnings.

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

        * objc.dg/property/dotsyntax-18.m: New.
        * objc.dg/property/dotsyntax-19.m: New.
        * objc.dg/property/dotsyntax-20.m: New.
        * obj-c++.dg/property/dotsyntax-18.mm: New.
        * obj-c++.dg/property/dotsyntax-19.mm: New.
        * obj-c++.dg/property/dotsyntax-20.mm: New.
        * objc.dg/property/dotsyntax-4.m: Removed some unused variables and code.
        * objc.dg/property/dotsyntax-6.m: Same change.
        * objc.dg/property/dotsyntax-16.m: Same change.
        * objc.dg/property/dotsyntax-17.m: Same change.
        * obj-c++.dg/property/dotsyntax-4.mm: Same change.
        * obj-c++.dg/property/dotsyntax-6.mm: Same change.
        * obj-c++.dg/property/dotsyntax-16.mm: Same change.
        * obj-c++.dg/property/dotsyntax-17.mm: Same change.
        * objc.dg/property/at-property-22.m: Added missing casts.
        * obj-c++.dg/property/at-property-22.mm: Same change.
Mike Stump - Nov. 15, 2010, 9:40 p.m.
On Nov 15, 2010, at 12:06 PM, Nicola Pero wrote:
> This patch fixes using the Objective-C 2.0 dot-syntax in cases

> Ok to commit to trunk ?

Ok.

Patch

Index: gcc/objc/objc-act.c
===================================================================
--- gcc/objc/objc-act.c	(revision 166763)
+++ gcc/objc/objc-act.c	(working copy)
@@ -1748,6 +1748,42 @@  objc_is_property_ref (tree node)
     return false;
 }
 
+/* This function builds a setter call for a PROPERTY_REF (real, for a
+   declared property, or artificial, for a dot-syntax accessor which
+   is not corresponding to a property).  'lhs' must be a PROPERTY_REF
+   (the caller must check this beforehand).  'rhs' is the value to
+   assign to the property.  A plain setter call is returned, or
+   error_mark_node if the property is readonly.  */
+
+static tree
+objc_build_setter_call (tree lhs, tree rhs)
+{
+  tree object_expr = PROPERTY_REF_OBJECT (lhs);
+  tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs);
+  
+  if (PROPERTY_READONLY (property_decl))
+    {
+      error ("readonly property can not be set");	  
+      return error_mark_node;
+    }
+  else
+    {
+      tree setter_argument = build_tree_list (NULL_TREE, rhs);
+      tree setter;
+      
+      /* TODO: Check that the setter return type is 'void'.  */
+
+      /* TODO: Decay arguments in C.  */
+      setter = objc_finish_message_expr (object_expr, 
+					 PROPERTY_SETTER_NAME (property_decl),
+					 setter_argument);
+      return setter;
+    }
+
+  /* Unreachable, but the compiler may not realize.  */
+  return error_mark_node;
+}
+
 /* This hook routine is called when a MODIFY_EXPR is being built.  We
    check what is being modified; if it is a PROPERTY_REF, we need to
    generate a 'setter' function call for the property.  If this is not
@@ -1767,27 +1803,69 @@  objc_maybe_build_modify_expr (tree lhs, tree rhs)
 {
   if (lhs && TREE_CODE (lhs) == PROPERTY_REF)
     {
-      tree object_expr = PROPERTY_REF_OBJECT (lhs);
-      tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs);
+      /* Building a simple call to the setter method would work for cases such as
 
-      if (PROPERTY_READONLY (property_decl))
-	{
-	  error ("readonly property can not be set");	  
-	  return error_mark_node;
-	}
-      else
-	{
-	  tree setter_argument = build_tree_list (NULL_TREE, rhs);
-	  tree setter;
+      object.count = 1;
 
-	  /* TODO: Check that the setter return type is 'void'.  */
+      but wouldn't work for cases such as
 
-	  /* TODO: Decay argument in C.  */
-	  setter = objc_finish_message_expr (object_expr, 
-					     PROPERTY_SETTER_NAME (property_decl),
-					     setter_argument);
-	  return setter;
-	}
+      count = object2.count = 1;
+
+      to get these to work with very little effort, we build a
+      compound statement which does the setter call (to set the
+      property to 'rhs'), but which can also be evaluated returning
+      the 'rhs'.  So, we want to create the following:
+
+      (temp = rhs; [object setProperty: temp]; temp)
+      */
+      tree temp_variable_decl, bind;
+      /* s1, s2 and s3 are the tree statements that we need in the
+	 compound expression.  */
+      tree s1, s2, s3, compound_expr;
+      
+      /* TODO: If 'rhs' is a constant, we could maybe do without the
+	 'temp' variable ? */
+
+      /* Declare __objc_property_temp in a local bind.  */
+      temp_variable_decl = objc_create_temporary_var (TREE_TYPE (rhs), "__objc_property_temp");
+      DECL_SOURCE_LOCATION (temp_variable_decl) = input_location;
+      bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL);
+      SET_EXPR_LOCATION (bind, input_location);
+      TREE_SIDE_EFFECTS (bind) = 1;
+      add_stmt (bind);
+      
+      /* Now build the compound statement.  */
+      
+      /* s1: __objc_property_temp = rhs */
+      s1 = build_modify_expr (input_location, temp_variable_decl, NULL_TREE,
+			      NOP_EXPR,
+			      input_location, rhs, NULL_TREE);
+      SET_EXPR_LOCATION (s1, input_location);
+  
+      /* s2: [object setProperty: __objc_property_temp] */
+      s2 = objc_build_setter_call (lhs, temp_variable_decl);
+
+      /* This happens if building the setter failed because the property
+	 is readonly.  */
+      if (s2 == error_mark_node)
+	return error_mark_node;
+
+      SET_EXPR_LOCATION (s2, input_location);
+  
+      /* s3: __objc_property_temp */
+      s3 = convert (TREE_TYPE (lhs), temp_variable_decl);
+
+      /* Now build the compound statement (s1, s2, s3) */
+      compound_expr = build_compound_expr (input_location, build_compound_expr (input_location, s1, s2), s3);
+
+      /* Without this, with -Wall you get a 'valued computed is not
+	 used' every time there is a "object.property = x" where the
+	 value of the resulting MODIFY_EXPR is not used.  That is
+	 correct (maybe a more sophisticated implementation could
+	 avoid generating the compound expression if not needed), but
+	 we need to turn it off.  */
+      TREE_NO_WARNING (compound_expr) = 1;
+      return compound_expr;
     }
   else
     return NULL_TREE;
@@ -1821,7 +1899,7 @@  objc_build_incr_expr_for_property_ref (location_t
   tree temp_variable_decl, bind;
   /* s1, s2 and s3 are the tree statements that we need in the
      compound expression.  */
-  tree s1, s2, s3;
+  tree s1, s2, s3, compound_expr;
   
   /* Safety check.  */
   if (!argument || TREE_CODE (argument) != PROPERTY_REF)
@@ -1846,23 +1924,28 @@  objc_build_incr_expr_for_property_ref (location_t
     {
     case PREINCREMENT_EXPR:	 
       /* __objc_property_temp = [object property] + increment */
-      s1 = build2 (MODIFY_EXPR, void_type_node, temp_variable_decl,
-		   build2 (PLUS_EXPR, TREE_TYPE (argument), argument, increment));
+      s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
+			      NOP_EXPR,
+			      location, build2 (PLUS_EXPR, TREE_TYPE (argument), 
+						argument, increment), NULL_TREE);
       break;
     case PREDECREMENT_EXPR:
       /* __objc_property_temp = [object property] - increment */
-      s1 = build2 (MODIFY_EXPR, void_type_node, temp_variable_decl,
-		   build2 (MINUS_EXPR, TREE_TYPE (argument), argument, increment));
+      s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
+			      NOP_EXPR,
+			      location, build2 (MINUS_EXPR, TREE_TYPE (argument), 
+						argument, increment), NULL_TREE);
       break;
     case POSTINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       /* __objc_property_temp = [object property] */
-      s1 = build2 (MODIFY_EXPR, void_type_node, temp_variable_decl, argument);
+      s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
+			      NOP_EXPR,
+			      location, argument, NULL_TREE);
       break;
     default:
       gcc_unreachable ();
     }
-  SET_EXPR_LOCATION (s1, location);
   
   /* s2: [object setProperty: __objc_property_temp <+/- increment>] */
   switch (code)
@@ -1870,19 +1953,19 @@  objc_build_incr_expr_for_property_ref (location_t
     case PREINCREMENT_EXPR:	 
     case PREDECREMENT_EXPR:
       /* [object setProperty: __objc_property_temp] */
-      s2 = objc_maybe_build_modify_expr (argument, temp_variable_decl);
+      s2 = objc_build_setter_call (argument, temp_variable_decl);
       break;
     case POSTINCREMENT_EXPR:
       /* [object setProperty: __objc_property_temp + increment] */
-      s2 = objc_maybe_build_modify_expr (argument,
-					 build2 (PLUS_EXPR, TREE_TYPE (argument), 
-						 temp_variable_decl, increment));
+      s2 = objc_build_setter_call (argument,
+				   build2 (PLUS_EXPR, TREE_TYPE (argument), 
+					   temp_variable_decl, increment));
       break;
     case POSTDECREMENT_EXPR:
       /* [object setProperty: __objc_property_temp - increment] */
-      s2 = objc_maybe_build_modify_expr (argument,
-					 build2 (MINUS_EXPR, TREE_TYPE (argument), 
-						 temp_variable_decl, increment));
+      s2 = objc_build_setter_call (argument,
+				   build2 (MINUS_EXPR, TREE_TYPE (argument), 
+					   temp_variable_decl, increment));
       break;
     default:
       gcc_unreachable ();
@@ -1896,11 +1979,15 @@  objc_build_incr_expr_for_property_ref (location_t
   SET_EXPR_LOCATION (s2, location); 
   
   /* s3: __objc_property_temp */
-  s3 = build1 (NOP_EXPR, TREE_TYPE (argument), temp_variable_decl);
-  SET_EXPR_LOCATION (s3, location); 
+  s3 = convert (TREE_TYPE (argument), temp_variable_decl);
   
   /* Now build the compound statement (s1, s2, s3) */
-  return build_compound_expr (location, build_compound_expr (location, s1, s2), s3);
+  compound_expr = build_compound_expr (location, build_compound_expr (location, s1, s2), s3);
+
+  /* Prevent C++ from warning with -Wall that "right operand of comma
+     operator has no effect".  */
+  TREE_NO_WARNING (compound_expr) = 1;
+  return compound_expr;
 }
 
 tree
Index: gcc/objc/ChangeLog
===================================================================
--- gcc/objc/ChangeLog	(revision 166763)
+++ gcc/objc/ChangeLog	(working copy)
@@ -1,5 +1,17 @@ 
 2010-11-15  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* objc-act.c (objc_build_setter_call): New.
+	(objc_maybe_build_modify_expr): Rewritten to build a compound
+	statement.
+	(objc_build_incr_expr_for_property_ref): Updated calls to
+	objc_maybe_build_modify_expr to call objc_build_setter_call
+	instead.  Use build_modify_expr () instead of build2 (MODIFY_EXPR,
+	...).  Use convert () instead of build1 (NOP_EXPR, ...).  Use
+	TREE_NO_WARNING on the final compound statement to silence C++
+	warnings.
+
+2010-11-15  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* objc-act.c (objc_build_incr_expr_for_property_ref): New.
 	(objc_create_temporary_var): Moved it towards the beginning of the
 	file so that objc_build_incr_expr_for_property_ref can use it.
Index: gcc/testsuite/ChangeLog
===================================================================
--- gcc/testsuite/ChangeLog	(revision 166763)
+++ gcc/testsuite/ChangeLog	(working copy)
@@ -1,5 +1,24 @@ 
 2010-11-15  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* objc.dg/property/dotsyntax-18.m: New.
+	* objc.dg/property/dotsyntax-19.m: New.
+	* objc.dg/property/dotsyntax-20.m: New.
+	* obj-c++.dg/property/dotsyntax-18.mm: New.
+	* obj-c++.dg/property/dotsyntax-19.mm: New.	
+	* obj-c++.dg/property/dotsyntax-20.mm: New.
+	* objc.dg/property/dotsyntax-4.m: Removed some unused variables and code.
+	* objc.dg/property/dotsyntax-6.m: Same change.
+	* objc.dg/property/dotsyntax-16.m: Same change. 
+	* objc.dg/property/dotsyntax-17.m: Same change.
+	* obj-c++.dg/property/dotsyntax-4.mm: Same change.
+	* obj-c++.dg/property/dotsyntax-6.mm: Same change.
+	* obj-c++.dg/property/dotsyntax-16.mm: Same change. 
+	* obj-c++.dg/property/dotsyntax-17.mm: Same change.
+	* objc.dg/property/at-property-22.m: Added missing casts.
+	* obj-c++.dg/property/at-property-22.mm: Same change.
+	
+2010-11-15  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* objc.dg/property/dotsyntax-16.m: New.
 	* objc.dg/property/dotsyntax-17.m: New.	
 	* obj-c++.dg/property/dotsyntax-16.mm: New.
Index: gcc/testsuite/objc.dg/property/at-property-22.m
===================================================================
--- gcc/testsuite/objc.dg/property/at-property-22.m	(revision 166763)
+++ gcc/testsuite/objc.dg/property/at-property-22.m	(working copy)
@@ -128,31 +128,31 @@  int main (void)
   if (object.penum != Black)
     abort ();
 
-  object.pcharp = 0;
+  object.pcharp = (char *)0;
   if (object.pcharp != 0)
     abort ();
   
-  object.pshortp = 0;
+  object.pshortp = (short *)0;
   if (object.pshortp != 0)
     abort ();
 
-  object.pintp = 0;
+  object.pintp = (int *)0;
   if (object.pintp != 0)
     abort ();
     
-  object.plongp = 0;
+  object.plongp = (long *)0;
   if (object.plongp != 0)
     abort ();
     
-  object.pfloatp = 0;
+  object.pfloatp = (float *)0;
   if (object.pfloatp != 0)
     abort ();
     
-  object.pdoublep = 0;
+  object.pdoublep = (double *)0;
   if (object.pdoublep != 0)
     abort ();
     
-  object.penump = 0;
+  object.penump = (enum colour *)0;
   if (object.penump != 0)
     abort ();
 
Index: gcc/testsuite/objc.dg/property/dotsyntax-17.m
===================================================================
--- gcc/testsuite/objc.dg/property/dotsyntax-17.m	(revision 166763)
+++ gcc/testsuite/objc.dg/property/dotsyntax-17.m	(working copy)
@@ -34,7 +34,6 @@ 
 int main (void)
 {
   MyRootClass *object = [[MyRootClass alloc] init];
-  int i;
 
   object.count = 10; /* { dg-error "readonly property can not be set" } */
   if (object.count != 10) /* Ok */
Index: gcc/testsuite/objc.dg/property/dotsyntax-19.m
===================================================================
--- gcc/testsuite/objc.dg/property/dotsyntax-19.m	(revision 0)
+++ gcc/testsuite/objc.dg/property/dotsyntax-19.m	(revision 0)
@@ -0,0 +1,113 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test dot-syntax with more tricky assignments.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  id a;
+  id b;
+  int p1;
+  float p2;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+
+@property (assign) id object1;
+@property (assign) id object2;
+- (id) test;
+- (id) myself;
+- (id) nilObject;
+
+@property int p1;
+@property float p2;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize object1 = a;
+@synthesize object2 = b;
+- (id) test
+{
+  /* Test multiple assignments with 'self'.  */
+  self.object1 = self.object2 = self;
+
+  if (self.object1 != self || self.object2 != self)
+    abort ();
+
+  /* Test multiple assignments with a conditional and method calls.  */
+  self.object1 = self.object2 = (self ? [self myself] : [self nilObject]);
+
+  if (self.object1 != self || self.object2 != self)
+    abort ();
+
+  self.object1 = self.object2 = (self ? [self nilObject] : [self myself]);
+
+  if (self.object1 != nil || self.object2 != nil)
+    abort ();
+
+  return self.object1;
+}
+- (id) myself
+{
+  return self;
+}
+- (id) nilObject
+{
+  return nil;
+}
+
+@synthesize p1;
+@synthesize p2;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+  MyRootClass *object1 = [[MyRootClass alloc] init];
+
+  [object test];
+
+  /* Now, test multiple assignments with different types.  Use
+     int/float as they seem to happily crash the compiler in gimplify
+     if proper conversions are not being generated by the
+     frontend. ;-) */
+  object.p1 = object.p2 = 12;
+
+  if (object.p1 != 12 || object.p2 != 12)
+    abort ();
+
+  object.p1 = object.p2 = 2.7;
+
+  if (object.p1 != 2)
+    abort ();
+
+  /* Just try a different loop, mixing in a few different standard C
+     constructs to cover a few other cases.  */
+  object.p1 = 10;
+  object1.p1 = 0;
+  while (object.p1)
+    {
+      object1.p1 += ((object.p2 = 4.56) ? 0 : object.p1);
+      object.p1--;
+    }
+
+  if (object.p1 != 0 || object1.p1 != 0)
+    abort ();
+
+  if ((object.p1 = 0))
+    abort ();
+
+  return 0;
+}
+
+
Index: gcc/testsuite/objc.dg/property/dotsyntax-20.m
===================================================================
--- gcc/testsuite/objc.dg/property/dotsyntax-20.m	(revision 0)
+++ gcc/testsuite/objc.dg/property/dotsyntax-20.m	(revision 0)
@@ -0,0 +1,67 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+/* Test warnings with the dot-syntax.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  id a;
+  id b;
+  int p1;
+  int p2;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+
+@property int p1;
+@property int p2;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize p1;
+@synthesize p2;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  /* First, test that the artificial code generated by dot-syntax does
+     not generate unexpected warnings.  */
+
+  /* All of the following should generate no warnings.  */
+  object.p1 = 0;
+  object.p2 = 0;
+  object.p1 = object.p2 = 0;
+  if (object.p1 > 0)
+    object.p2 = 0;
+  
+  object.p1++;
+  ++object.p1;
+  object.p1--;
+  --object.p1;
+  
+  while (object.p1)
+    object.p1--;
+
+  /* Now test some warnings.  */
+  object.p1; /* { dg-warning "value computed is not used" } */
+
+  /* TODO: It would be good to get the following to warn.  */
+  if (object.p1 = 0) /* dg-warning "suggest parentheses around assignment used as truth value" */
+    abort ();
+
+  return 0;
+}
+
+
Index: gcc/testsuite/objc.dg/property/dotsyntax-16.m
===================================================================
--- gcc/testsuite/objc.dg/property/dotsyntax-16.m	(revision 166763)
+++ gcc/testsuite/objc.dg/property/dotsyntax-16.m	(working copy)
@@ -37,7 +37,6 @@ 
 int main (void)
 {
   MyRootClass *object = [[MyRootClass alloc] init];
-  int i;
 
   object.count = 10;
   if (object.count != 10)
Index: gcc/testsuite/objc.dg/property/dotsyntax-18.m
===================================================================
--- gcc/testsuite/objc.dg/property/dotsyntax-18.m	(revision 0)
+++ gcc/testsuite/objc.dg/property/dotsyntax-18.m	(revision 0)
@@ -0,0 +1,90 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test dot-syntax with tricky assignments.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (int) count;
+- (void) setCount: (int)count;
+- (int) somethingToExecuteOnlyOnce;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (int) count
+{
+  return a;
+}
+- (void) setCount: (int)count
+{
+  a = count;
+}
+- (int) somethingToExecuteOnlyOnce
+{
+  a++;
+  return 10;
+}
+@end
+
+int main (void)
+{
+  MyRootClass *object1 = [[MyRootClass alloc] init];
+  MyRootClass *object2 = [[MyRootClass alloc] init];
+  MyRootClass *object3 = [[MyRootClass alloc] init];
+  int i;
+
+  object1.count = 10;
+  if (object1.count != 10)
+    abort ();
+
+  object2.count = 10;
+  if (object2.count != 10)
+    abort ();
+
+  /* Test multiple assignments to a constant.  */
+  object1.count = object2.count = 20;
+
+  if (object1.count != 20 || object2.count != 20)
+    abort ();
+
+  i = object1.count = 30;
+
+  if (i != 30 || object1.count != 30)
+    abort ();
+
+  i = object2.count = 30;
+
+  if (i != 30 || object2.count != 30)
+    abort ();
+
+  /* Test a simple assignment to something with a side-effect; the
+     'rhs' should be evaluated only once.  */
+  object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
+
+  if (object1.count != 30 || object2.count != 31)
+    abort ();
+
+  /* Test multiple assignments with side effects.  */
+  object3.count = object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
+
+  if (object1.count != 30 || object2.count != 32 || object3.count != 30)
+    abort ();
+
+  return 0;
+}
+
+
Index: gcc/testsuite/objc.dg/property/dotsyntax-4.m
===================================================================
--- gcc/testsuite/objc.dg/property/dotsyntax-4.m	(revision 166763)
+++ gcc/testsuite/objc.dg/property/dotsyntax-4.m	(working copy)
@@ -9,9 +9,6 @@ 
 #include <objc/objc.h>
 #include <objc/runtime.h>
 
-static int a;
-static id b;
-
 @interface MyRootClass
 {
   Class isa;
@@ -19,38 +16,16 @@ 
 + (id) initialize;
 + (id) alloc;
 - (id) init;
-+ (int) count;
-+ (void) setCount: (int)value;
-+ (id) next;
-+ (void) setNext: (id)value;
 @end
 
 @implementation MyRootClass
 + (id) initialize { return self; }
 + (id) alloc { return class_createInstance (self, 0); }
 - (id) init { return self; }
-+ (int) count
-{
-  return a;
-}
-+ (void) setCount: (int)value
-{
-  a = value;
-}
-+ (id) next
-{
-  return b;
-}
-+ (void) setNext: (id)value
-{
-  b = value;
-}
 @end
 
 int main (void)
 {
-  MyRootClass *object = [[MyRootClass alloc] init];
-
   MyRootClass.invalid = 40;      /* { dg-error "could not find setter.getter" } */
   if (MyRootClass.invalid != 40) /* { dg-error "could not find setter.getter" } */
     abort ();
Index: gcc/testsuite/objc.dg/property/dotsyntax-6.m
===================================================================
--- gcc/testsuite/objc.dg/property/dotsyntax-6.m	(revision 166763)
+++ gcc/testsuite/objc.dg/property/dotsyntax-6.m	(working copy)
@@ -10,7 +10,6 @@ 
 
 @class MyRootClass;
 
-static int c;
 static MyRootClass *shared_root = nil;
 
 @interface MyRootClass
Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm	(revision 0)
@@ -0,0 +1,113 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test dot-syntax with more tricky assignments.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  id a;
+  id b;
+  int p1;
+  float p2;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+
+@property (assign) id object1;
+@property (assign) id object2;
+- (id) test;
+- (id) myself;
+- (id) nilObject;
+
+@property int p1;
+@property float p2;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize object1 = a;
+@synthesize object2 = b;
+- (id) test
+{
+  /* Test multiple assignments with 'self'.  */
+  self.object1 = self.object2 = self;
+
+  if (self.object1 != self || self.object2 != self)
+    abort ();
+
+  /* Test multiple assignments with a conditional and method calls.  */
+  self.object1 = self.object2 = (self ? [self myself] : [self nilObject]);
+
+  if (self.object1 != self || self.object2 != self)
+    abort ();
+
+  self.object1 = self.object2 = (self ? [self nilObject] : [self myself]);
+
+  if (self.object1 != nil || self.object2 != nil)
+    abort ();
+
+  return self.object1;
+}
+- (id) myself
+{
+  return self;
+}
+- (id) nilObject
+{
+  return nil;
+}
+
+@synthesize p1;
+@synthesize p2;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+  MyRootClass *object1 = [[MyRootClass alloc] init];
+
+  [object test];
+
+  /* Now, test multiple assignments with different types.  Use
+     int/float as they seem to happily crash the compiler in gimplify
+     if proper conversions are not being generated by the
+     frontend. ;-) */
+  object.p1 = object.p2 = 12;
+
+  if (object.p1 != 12 || object.p2 != 12)
+    abort ();
+
+  object.p1 = object.p2 = 2.7;
+
+  if (object.p1 != 2)
+    abort ();
+
+  /* Just try a different loop, mixing in a few different standard C
+     constructs to cover a few other cases.  */
+  object.p1 = 10;
+  object1.p1 = 0;
+  while (object.p1)
+    {
+      object1.p1 += ((object.p2 = 4.56) ? 0 : object.p1);
+      object.p1--;
+    }
+
+  if (object.p1 != 0 || object1.p1 != 0)
+    abort ();
+
+  if ((object.p1 = 0))
+    abort ();
+
+  return 0;
+}
+
+
Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm	(revision 166763)
+++ gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm	(working copy)
@@ -9,9 +9,6 @@ 
 #include <objc/objc.h>
 #include <objc/runtime.h>
 
-static int a;
-static id b;
-
 @interface MyRootClass
 {
   Class isa;
@@ -19,38 +16,16 @@ 
 + (id) initialize;
 + (id) alloc;
 - (id) init;
-+ (int) count;
-+ (void) setCount: (int)value;
-+ (id) next;
-+ (void) setNext: (id)value;
 @end
 
 @implementation MyRootClass
 + (id) initialize { return self; }
 + (id) alloc { return class_createInstance (self, 0); }
 - (id) init { return self; }
-+ (int) count
-{
-  return a;
-}
-+ (void) setCount: (int)value
-{
-  a = value;
-}
-+ (id) next
-{
-  return b;
-}
-+ (void) setNext: (id)value
-{
-  b = value;
-}
 @end
 
 int main (void)
 {
-  MyRootClass *object = [[MyRootClass alloc] init];
-
   MyRootClass.invalid = 40;      /* { dg-error "could not find setter.getter" } */
   if (MyRootClass.invalid != 40) /* { dg-error "could not find setter.getter" } */
     abort ();
@@ -60,9 +35,9 @@  int main (void)
     abort ();
 
   MyRootClass.int;        /* { dg-error "expected identifier" } */
-                          /* { dg-error "expected" "" { target *-*-* } 62 } */
+                          /* { dg-error "expected" "" { target *-*-* } 37 } */
   if (MyRootClass.int)    /* { dg-error "expected identifier" } */
-                          /* { dg-error "expected" "" { target *-*-* } 64 } */
+                          /* { dg-error "expected" "" { target *-*-* } 39 } */
     abort ();
 
   return 0;
Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm	(revision 0)
@@ -0,0 +1,67 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+/* Test warnings with the dot-syntax.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  id a;
+  id b;
+  int p1;
+  int p2;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+
+@property int p1;
+@property int p2;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize p1;
+@synthesize p2;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  /* First, test that the artificial code generated by dot-syntax does
+     not generate unexpected warnings.  */
+
+  /* All of the following should generate no warnings.  */
+  object.p1 = 0;
+  object.p2 = 0;
+  object.p1 = object.p2 = 0;
+  if (object.p1 > 0)
+    object.p2 = 0;
+  
+  object.p1++;
+  ++object.p1;
+  object.p1--;
+  --object.p1;
+  
+  while (object.p1)
+    object.p1--;
+
+  /* Now test some warnings.  */
+  object.p1; /* This warning does not seem to be produced in C++.  dg-warning "value computed is not used" */
+
+  /* TODO: It would be good to get the following to warn.  */
+  if (object.p1 = 0) /* dg-warning "suggest parentheses around assignment used as truth value" */
+    abort ();
+
+  return 0;
+}
+
+
Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm	(revision 0)
@@ -0,0 +1,90 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test dot-syntax with tricky assignments.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (int) count;
+- (void) setCount: (int)count;
+- (int) somethingToExecuteOnlyOnce;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (int) count
+{
+  return a;
+}
+- (void) setCount: (int)count
+{
+  a = count;
+}
+- (int) somethingToExecuteOnlyOnce
+{
+  a++;
+  return 10;
+}
+@end
+
+int main (void)
+{
+  MyRootClass *object1 = [[MyRootClass alloc] init];
+  MyRootClass *object2 = [[MyRootClass alloc] init];
+  MyRootClass *object3 = [[MyRootClass alloc] init];
+  int i;
+
+  object1.count = 10;
+  if (object1.count != 10)
+    abort ();
+
+  object2.count = 10;
+  if (object2.count != 10)
+    abort ();
+
+  /* Test multiple assignments to a constant.  */
+  object1.count = object2.count = 20;
+
+  if (object1.count != 20 || object2.count != 20)
+    abort ();
+
+  i = object1.count = 30;
+
+  if (i != 30 || object1.count != 30)
+    abort ();
+
+  i = object2.count = 30;
+
+  if (i != 30 || object2.count != 30)
+    abort ();
+
+  /* Test a simple assignment to something with a side-effect; the
+     'rhs' should be evaluated only once.  */
+  object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
+
+  if (object1.count != 30 || object2.count != 31)
+    abort ();
+
+  /* Test multiple assignments with side effects.  */
+  object3.count = object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
+
+  if (object1.count != 30 || object2.count != 32 || object3.count != 30)
+    abort ();
+
+  return 0;
+}
+
+
Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm	(revision 166763)
+++ gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm	(working copy)
@@ -34,7 +34,6 @@ 
 int main (void)
 {
   MyRootClass *object = [[MyRootClass alloc] init];
-  int i;
 
   object.count = 10; /* { dg-error "readonly property can not be set" } */
   if (object.count != 10) /* Ok */
Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm	(revision 166763)
+++ gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm	(working copy)
@@ -10,7 +10,6 @@ 
 
 @class MyRootClass;
 
-static int c;
 static MyRootClass *shared_root = nil;
 
 @interface MyRootClass
Index: gcc/testsuite/obj-c++.dg/property/at-property-22.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/at-property-22.mm	(revision 166763)
+++ gcc/testsuite/obj-c++.dg/property/at-property-22.mm	(working copy)
@@ -128,31 +128,31 @@  int main (void)
   if (object.penum != Black)
     abort ();
 
-  object.pcharp = 0;
+  object.pcharp = (char *)0;
   if (object.pcharp != 0)
     abort ();
   
-  object.pshortp = 0;
+  object.pshortp = (short *)0;
   if (object.pshortp != 0)
     abort ();
 
-  object.pintp = 0;
+  object.pintp = (int *)0;
   if (object.pintp != 0)
     abort ();
     
-  object.plongp = 0;
+  object.plongp = (long *)0;
   if (object.plongp != 0)
     abort ();
     
-  object.pfloatp = 0;
+  object.pfloatp = (float *)0;
   if (object.pfloatp != 0)
     abort ();
     
-  object.pdoublep = 0;
+  object.pdoublep = (double *)0;
   if (object.pdoublep != 0)
     abort ();
     
-  object.penump = 0;
+  object.penump = (enum colour *)0;
   if (object.penump != 0)
     abort ();
 
Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm	(revision 166763)
+++ gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm	(working copy)
@@ -37,7 +37,6 @@ 
 int main (void)
 {
   MyRootClass *object = [[MyRootClass alloc] init];
-  int i;
 
   object.count = 10;
   if (object.count != 10)