From 8f07a2aa357fd67ca7ef1e640424bc605c6cec31 Mon Sep 17 00:00:00 2001
From: Nicola Pero <nicola.pero@meta-innovation.com>
Date: Mon, 1 Nov 2010 20:06:36 +0000
Subject: [PATCH] In gcc/objc/: 2010-11-01 Nicola Pero
 <nicola.pero@meta-innovation.com>

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

        Implemented Objective-C 2.0 property accessors.
        * objc-act.h (enum objc_tree_index): Added OCTI_GET_PROPERTY_DECL,
        OCTI_SET_PROPERTY_DECL, OCTI_COPY_STRUCT_DECL,
        OCTI_GET_PROPERTY_STRUCT_DECL and OCTI_SET_PROPERTY_STRUCT_DECL.
        (objc_getProperty_decl): New.
        (objc_setProperty_decl): New.
        (objc_copyStruct_decl): New.
        (objc_getPropertyStruct_decl): New.
        (objc_setPropertyStruct_decl): New.
        * objc-act.c (build_objc_property_accessor_helpers): New.
        (synth_module_prologue): Call
        build_objc_property_accessor_helpers.
        (lookup_ivar): New.
        (objc_synthesize_getter): Implemented synthesizing getters that
        work with properties that are not nonatomic, assign properties.
        (objc_synthesize_setter): Implemented synthesizing setters that
        work with properties that are not nonatomic, assign properties.

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

        Implemented Objective-C 2.0 property accessors.
        * objc.dg/property/at-property-6.m: Use nonatomic properties to
        avoid testing more complex accessors in this testcase which is not
        about them.
        * objc.dg/property/at-property-7.m: Same change.
        * objc.dg/property/at-property-8.m: Same change.
        * objc.dg/property/at-property-9.m: Same change.
        * objc.dg/property/at-property-10.m: Same change.
        * objc.dg/property/at-property-11.m: Same change.
        * obj-c++.dg/property/at-property-6.mm: Same change.
        * obj-c++.dg/property/at-property-7.mm: Same change.
        * obj-c++.dg/property/at-property-8.mm: Same change.
        * obj-c++.dg/property/at-property-9.mm: Same change.
        * obj-c++.dg/property/at-property-10.mm: Same change.
        * obj-c++.dg/property/at-property-11.mm: Same change.
        * objc.dg/property/at-property-12.m: New.
        * objc.dg/property/at-property-13.m: New.
        * obj-c++.dg/property/at-property-12.mm: New.
        * obj-c++.dg/property/at-property-13.mm: New.

From-SVN: r166143
---
 gcc/objc/ChangeLog                            |  20 +
 gcc/objc/objc-act.c                           | 435 ++++++++++++++++--
 gcc/objc/objc-act.h                           |  15 +
 gcc/testsuite/ChangeLog                       |  22 +
 .../obj-c++.dg/property/at-property-10.mm     |   2 +-
 .../obj-c++.dg/property/at-property-11.mm     |   2 +-
 .../obj-c++.dg/property/at-property-12.mm     |  46 ++
 .../obj-c++.dg/property/at-property-13.mm     |  71 +++
 .../obj-c++.dg/property/at-property-6.mm      |   2 +-
 .../obj-c++.dg/property/at-property-7.mm      |   2 +-
 .../obj-c++.dg/property/at-property-8.mm      |   2 +-
 .../obj-c++.dg/property/at-property-9.mm      |   2 +-
 .../objc.dg/property/at-property-10.m         |   5 +-
 .../objc.dg/property/at-property-11.m         |   5 +-
 .../objc.dg/property/at-property-12.m         |  46 ++
 .../objc.dg/property/at-property-13.m         |  71 +++
 .../objc.dg/property/at-property-6.m          |   2 +-
 .../objc.dg/property/at-property-7.m          |   2 +-
 .../objc.dg/property/at-property-8.m          |   2 +-
 .../objc.dg/property/at-property-9.m          |   5 +-
 20 files changed, 705 insertions(+), 54 deletions(-)
 create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-12.mm
 create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-13.mm
 create mode 100644 gcc/testsuite/objc.dg/property/at-property-12.m
 create mode 100644 gcc/testsuite/objc.dg/property/at-property-13.m

diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index 04841334ff93..5a7c85f5fc2a 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -1,3 +1,23 @@
+2010-11-01  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+	Implemented Objective-C 2.0 property accessors.	
+	* objc-act.h (enum objc_tree_index): Added OCTI_GET_PROPERTY_DECL,
+	OCTI_SET_PROPERTY_DECL, OCTI_COPY_STRUCT_DECL,
+	OCTI_GET_PROPERTY_STRUCT_DECL and OCTI_SET_PROPERTY_STRUCT_DECL.
+	(objc_getProperty_decl): New.
+	(objc_setProperty_decl): New.
+	(objc_copyStruct_decl): New.
+	(objc_getPropertyStruct_decl): New.
+	(objc_setPropertyStruct_decl): New.
+	* objc-act.c (build_objc_property_accessor_helpers): New.
+	(synth_module_prologue): Call
+	build_objc_property_accessor_helpers.
+	(lookup_ivar): New.
+	(objc_synthesize_getter): Implemented synthesizing getters that
+	work with properties that are not nonatomic, assign properties.
+	(objc_synthesize_setter): Implemented synthesizing setters that
+	work with properties that are not nonatomic, assign properties.
+	
 2010-10-30  Nicola Pero  <nicola.pero@meta-innovation.com>
 
 	Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index e564da55fbc8..00e2a4330a3f 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -178,6 +178,7 @@ static int match_proto_with_proto (tree, tree, int);
 static tree lookup_property (tree, tree);
 static tree lookup_property_in_list (tree, tree);
 static tree lookup_property_in_protocol_list (tree, tree);
+static void build_objc_property_accessor_helpers (void);
 
 static void objc_xref_basetypes (tree, tree);
 
@@ -2348,6 +2349,10 @@ synth_module_prologue (void)
   build_category_template ();
   build_objc_exception_stuff ();
 
+  /* Declare objc_getProperty, object_setProperty and other property
+     accessor helpers.  */
+  build_objc_property_accessor_helpers ();
+
   if (flag_next_runtime)
     build_next_objc_exception_stuff ();
 
@@ -7938,6 +7943,7 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility,
   return klass;
 }
 
+
 static tree
 is_ivar (tree decl_chain, tree ident)
 {
@@ -8516,11 +8522,120 @@ objc_build_property_setter_name (tree ident)
   return string;
 }
 
+/* This routine prepares the declarations of the property accessor
+   helper functions (objc_getProperty(), etc) that are used when
+   @synthesize is used.  */
+static void 
+build_objc_property_accessor_helpers (void)
+{
+  tree type;
+
+  /* Declare the following function:
+     id
+     objc_getProperty (id self, SEL _cmd, 
+                       ptrdiff_t offset, BOOL is_atomic);  */
+  type = build_function_type_list (objc_object_type,
+				   objc_object_type,
+				   objc_selector_type,
+				   ptrdiff_type_node,
+				   boolean_type_node,
+				   NULL_TREE);
+  objc_getProperty_decl = add_builtin_function ("objc_getProperty",
+						type, 0, NOT_BUILT_IN,
+						NULL, NULL_TREE);
+  TREE_NOTHROW (objc_getProperty_decl) = 0;
+  
+  /* Declare the following function:
+     void
+     objc_setProperty (id self, SEL _cmd, 
+                       ptrdiff_t offset, id new_value, 
+                       BOOL is_atomic, BOOL should_copy);  */
+  type = build_function_type_list (void_type_node,
+				   objc_object_type,
+				   objc_selector_type,
+				   ptrdiff_type_node,
+				   objc_object_type,
+				   boolean_type_node,
+				   boolean_type_node,
+				   NULL_TREE);
+  objc_setProperty_decl = add_builtin_function ("objc_setProperty",
+						type, 0, NOT_BUILT_IN,
+						NULL, NULL_TREE);
+  TREE_NOTHROW (objc_setProperty_decl) = 0;
+
+  /* This is the type of all of the following functions
+     (objc_copyStruct(), objc_getPropertyStruct() and
+     objc_setPropertyStruct()).  */
+  type = build_function_type_list (void_type_node,
+				   ptr_type_node,
+				   const_ptr_type_node,
+				   ptrdiff_type_node,       
+				   boolean_type_node,
+				   boolean_type_node,
+				   NULL_TREE);
+
+  if (flag_next_runtime)
+    {
+      /* Declare the following function:
+	 void
+         objc_copyStruct (void *destination, const void *source, 
+	                  ptrdiff_t size, BOOL is_atomic, BOOL has_strong);  */
+      objc_copyStruct_decl = add_builtin_function ("objc_copyStruct",
+						   type, 0, NOT_BUILT_IN,
+						   NULL, NULL_TREE);
+      TREE_NOTHROW (objc_copyStruct_decl) = 0;
+      objc_getPropertyStruct_decl = NULL_TREE;
+      objc_setPropertyStruct_decl = NULL_TREE;
+    }
+  else
+    {
+      objc_copyStruct_decl = NULL_TREE;
+
+      /* Declare the following function:
+	 void
+	 objc_getPropertyStruct (void *destination, const void *source, 
+                                 ptrdiff_t size, BOOL is_atomic, BOOL has_strong);  */
+      objc_getPropertyStruct_decl = add_builtin_function ("objc_getPropertyStruct",
+							  type, 0, NOT_BUILT_IN,
+							  NULL, NULL_TREE);
+      TREE_NOTHROW (objc_getPropertyStruct_decl) = 0;
+      /* Declare the following function:
+	 void
+	 objc_setPropertyStruct (void *destination, const void *source, 
+	                         ptrdiff_t size, BOOL is_atomic, BOOL has_strong);  */
+      objc_setPropertyStruct_decl = add_builtin_function ("objc_setPropertyStruct",
+							  type, 0, NOT_BUILT_IN,
+							  NULL, NULL_TREE);
+      TREE_NOTHROW (objc_setPropertyStruct_decl) = 0;
+    }
+}
+
+/* This looks up an ivar in a class (including superclasses).  */
+static tree
+lookup_ivar (tree interface, tree instance_variable_name)
+{
+  while (interface)
+    {
+      tree decl_chain;
+      
+      for (decl_chain = CLASS_IVARS (interface); decl_chain; decl_chain = DECL_CHAIN (decl_chain))
+	if (DECL_NAME (decl_chain) == instance_variable_name)
+	  return decl_chain;
+      
+      /* Not found.  Search superclass if any.  */
+      if (CLASS_SUPER_NAME (interface))
+	interface = lookup_interface (CLASS_SUPER_NAME (interface));
+    }
+  
+  return NULL_TREE;
+}
+
 /* This routine synthesizes a 'getter' method.  This is only called
    for @synthesize properties.  */
 static void
-objc_synthesize_getter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
+objc_synthesize_getter (tree klass, tree class_method, tree property)
 {
+  location_t location = DECL_SOURCE_LOCATION (property);
   tree fn, decl;
   tree body;
   tree ret_val;
@@ -8543,29 +8658,150 @@ objc_synthesize_getter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
   /* Adapt the 'decl'.  Use the source location of the @synthesize
      statement for error messages.  */
   decl = copy_node (decl);
-  DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (property);
+  DECL_SOURCE_LOCATION (decl) = location;
 
   objc_start_method_definition (false /* is_class_method */, decl, NULL_TREE);
   body = c_begin_compound_stmt (true);
 
-  /* TODO: Implement PROPERTY_NONATOMIC, use objc_getProperty etc as
-     appropriate.  The following code just always does direct ivar
-     access.  */
+  /* Now we need to decide how we build the getter.  There are three
+     cases:
+
+     for 'copy' or 'retain' properties we need to use the
+     objc_getProperty() accessor helper which knows about retain and
+     copy.  It supports both 'nonatomic' and 'atomic' access.
 
-  /* return self->_property_name; */
+     for 'nonatomic, assign' properties we can access the instance
+     variable directly.  'nonatomic' means we don't have to use locks,
+     and 'assign' means we don't have to worry about retain or copy.
+     If you combine the two, it means we can just access the instance
+     variable directly.
+
+     for 'atomic, assign' properties we use objc_copyStruct() (for the
+     next runtime) or objc_getPropertyStruct() (for the GNU runtime).  */
+  switch (PROPERTY_ASSIGN_SEMANTICS (property))
+    {
+    case OBJC_PROPERTY_RETAIN:
+    case OBJC_PROPERTY_COPY:
+      {
+	/* We build "return objc_getProperty (self, _cmd, offset, is_atomic);"  */
+	tree cmd, ivar, offset, is_atomic;
+	cmd = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
+
+	/* Find the ivar to compute the offset.  */
+	ivar = lookup_ivar (klass, PROPERTY_IVAR_NAME (property));
+	if (!ivar || is_private (ivar))
+	  {
+	    /* This should never happen.  */
+	    error_at (location,
+		      "can not find instance variable associated with property");
+	    ret_val = error_mark_node;
+	    break;
+	  }
+	offset = byte_position (ivar);
+
+	if (PROPERTY_NONATOMIC (property))
+	  is_atomic = boolean_false_node;
+	else
+	  is_atomic = boolean_true_node;
+
+	ret_val = build_function_call
+	  (location,
+	   /* Function prototype.  */
+	   objc_getProperty_decl,
+	   /* Parameters.  */
+	   tree_cons    /* self */
+	   (NULL_TREE, self_decl,
+	    tree_cons   /* _cmd */
+	    (NULL_TREE, cmd,
+	     tree_cons  /* offset */
+	     (NULL_TREE, offset,
+	      tree_cons /* is_atomic */
+	      (NULL_TREE, is_atomic, NULL_TREE)))));
+      }
+      break;
+    case OBJC_PROPERTY_ASSIGN:    
+      if (PROPERTY_NONATOMIC (property))
+	{
+	  /* We build "return self->PROPERTY_IVAR_NAME;"  */
+	  ret_val = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
+	  break;
+	}
+      else
+	{
+	  /* We build
+	       <property type> __objc_property_temp;
+	       objc_getPropertyStruct (&__objc_property_temp,
+	                               &(self->PROPERTY_IVAR_NAME),
+	                               sizeof (type of self->PROPERTY_IVAR_NAME),
+				       is_atomic,
+				       false)
+	       return __objc_property_temp;
+
+	     For the NeXT runtime, we need to use objc_copyStruct
+	     instead of objc_getPropertyStruct.  */
+	  tree objc_property_temp_decl, function_decl, function_call;
+	  tree size_of, is_atomic;
+
+	  objc_property_temp_decl = objc_create_temporary_var (TREE_TYPE (property), "__objc_property_temp");
+	  DECL_SOURCE_LOCATION (objc_property_temp_decl) = location;
+	  objc_property_temp_decl = lang_hooks.decls.pushdecl (objc_property_temp_decl);
+
+	  /* sizeof (ivar type).  Since the ivar and the property have
+	     the same type, there is no need to lookup the ivar.  */
+	  size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
+					      true /* is_sizeof */,
+					      false /* complain */);
+	  
+	  if (PROPERTY_NONATOMIC (property))
+	    is_atomic = boolean_false_node;
+	  else
+	    is_atomic = boolean_true_node;
+	  
+	  if (flag_next_runtime)
+	    function_decl = objc_copyStruct_decl;
+	  else
+	    function_decl = objc_getPropertyStruct_decl;
+
+	  function_call = build_function_call
+	    (location,
+	     /* Function prototype.  */
+	     function_decl,
+	     /* Parameters.  */
+	     tree_cons /* &__objc_property_temp_decl */
+	     /* Warning: note that using build_fold_addr_expr_loc()
+		here causes invalid code to be generated.  */
+	     (NULL_TREE, build_unary_op (location, ADDR_EXPR, objc_property_temp_decl, 0),
+	      tree_cons /* &(self->PROPERTY_IVAR_NAME); */
+	      (NULL_TREE, build_fold_addr_expr_loc (location, 
+						    objc_lookup_ivar 
+						    (NULL_TREE, PROPERTY_IVAR_NAME (property))),
+	       tree_cons /* sizeof (PROPERTY_IVAR) */
+	       (NULL_TREE, size_of,
+		tree_cons /* is_atomic */
+		(NULL_TREE, is_atomic,
+		 /* TODO: This is currently ignored by the GNU
+		    runtime, but what about the next one ? */
+		 tree_cons /* has_strong */
+		 (NULL_TREE, boolean_true_node, NULL_TREE))))));
+
+	  add_stmt (function_call);
+
+	  ret_val = objc_property_temp_decl;
+	}
+      break;
+    default:
+      gcc_unreachable ();
+    }
 
-  /* PROPERTY_IVAR_NAME is always defined if we got here, and should
-     be a valid instance variable.  */
-  ret_val = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
   gcc_assert (ret_val);
 
 #ifdef OBJCPLUS
   finish_return_stmt (ret_val);
 #else
-  (void)c_finish_return (DECL_SOURCE_LOCATION (property), ret_val, NULL);
+  c_finish_return (location, ret_val, NULL_TREE);
 #endif
 
-  add_stmt (c_end_compound_stmt (DECL_SOURCE_LOCATION (property), body, true));
+  add_stmt (c_end_compound_stmt (location, body, true));
   fn = current_function_decl;
 #ifdef OBJCPLUS
   finish_function ();
@@ -8578,8 +8814,10 @@ objc_synthesize_getter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
 static void
 objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
 {
-  tree fn, decl, lhs, rhs;
+  location_t location = DECL_SOURCE_LOCATION (property);
+  tree fn, decl;
   tree body;
+  tree new_value, statement;
 
   /* If user has implemented a setter with same name then do nothing.  */
   if (lookup_method (CLASS_NST_METHODS (objc_implementation_context),
@@ -8605,40 +8843,153 @@ objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
 
   body = c_begin_compound_stmt (true);
 
-  /* TODO: Implement PROPERTY_NONATOMIC, use objc_getProperty etc as
-     appropriate.  The following code just always does direct ivar
-     access.  */
-
-  /* _property_name = _value; */
-
-  /* PROPERTY_IVAR_NAME is always defined if we got here, and should
-     be a valid instance variable.  */
-  lhs = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
-  gcc_assert (lhs);
-  
-  /* TODO: Lookup the argument in a more robust way so that it works
-     even if the method prototype does not call it '_value'.  */
-  rhs = lookup_name (get_identifier ("_value"));
+  /* The 'new_value' is the only argument to the method, which is the
+     3rd argument of the function, after self and _cmd.  We use twice
+     TREE_CHAIN to move forward two arguments.  */
+  new_value = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)));
 
   /* This would presumably happen if the user has specified a
-     prototype for the setter that is not the correct one.  */
-  if (rhs == NULL_TREE)
+     prototype for the setter that does not have an argument!  */
+  if (new_value == NULL_TREE)
     {
       /* TODO: This should be caught much earlier than this.  */
-      /* We couldn't find the '_value' identifier in the current
-	 context; presumably the user didn't have a '_value'
-	 argument.  */
-      error_at (DECL_SOURCE_LOCATION (decl), "invalid setter, missing _value argument");
-      /* Just recover somehow.  */
-      rhs = lhs;
-    }
-
-  /* FIXME: NULL types to get compile.  */
-  add_stmt (build_modify_expr (DECL_SOURCE_LOCATION (decl), 
-			       lhs, NULL_TREE, NOP_EXPR, 
-			       DECL_SOURCE_LOCATION (decl), rhs, NULL_TREE));
-  
-  add_stmt (c_end_compound_stmt (DECL_SOURCE_LOCATION (decl), body, true));
+      error_at (DECL_SOURCE_LOCATION (decl), "invalid setter, it must have one argument");
+      /* Try to recover somehow.  */
+      new_value = error_mark_node;
+    }
+
+  /* Now we need to decide how we build the setter.  There are three
+     cases:
+
+     for 'copy' or 'retain' properties we need to use the
+     objc_setProperty() accessor helper which knows about retain and
+     copy.  It supports both 'nonatomic' and 'atomic' access.
+
+     for 'nonatomic, assign' properties we can access the instance
+     variable directly.  'nonatomic' means we don't have to use locks,
+     and 'assign' means we don't have to worry about retain or copy.
+     If you combine the two, it means we can just access the instance
+     variable directly.
+
+     for 'atomic, assign' properties we use objc_copyStruct() (for the
+     next runtime) or objc_setPropertyStruct() (for the GNU runtime).  */
+  switch (PROPERTY_ASSIGN_SEMANTICS (property))
+    {
+    case OBJC_PROPERTY_RETAIN:
+    case OBJC_PROPERTY_COPY:
+      {
+	/* We build "objc_setProperty (self, _cmd, new_value, offset, is_atomic, should_copy);"  */
+	tree cmd, ivar, offset, is_atomic, should_copy;
+	cmd = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
+
+	/* Find the ivar to compute the offset.  */
+	ivar = lookup_ivar (klass, PROPERTY_IVAR_NAME (property));
+	if (!ivar || is_private (ivar))
+	  {
+	    error_at (location,
+		      "can not find instance variable associated with property");
+	    statement = error_mark_node;
+	    break;
+	  }
+	offset = byte_position (ivar);
+
+	if (PROPERTY_NONATOMIC (property))
+	  is_atomic = boolean_false_node;
+	else
+	  is_atomic = boolean_true_node;
+	
+	if (PROPERTY_ASSIGN_SEMANTICS (property) == OBJC_PROPERTY_COPY)
+	  should_copy = boolean_true_node;
+	else
+	  should_copy = boolean_false_node;
+
+	statement = build_function_call
+	  (location,
+	   /* Function prototype.  */
+	   objc_setProperty_decl,
+	   /* Parameters.  */
+	   tree_cons    /* self */
+	   (NULL_TREE, self_decl,
+	    tree_cons   /* _cmd */
+	    (NULL_TREE, cmd,
+	     tree_cons  /* offset */
+	     (NULL_TREE, offset,
+	      tree_cons /* new_value */
+	      (NULL_TREE, new_value,
+	       tree_cons /* is_atomic */
+	       (NULL_TREE, is_atomic, 
+		tree_cons /* should_copy */
+		(NULL_TREE, should_copy, NULL_TREE)))))));
+      }
+      break;
+    case OBJC_PROPERTY_ASSIGN:    
+      if (PROPERTY_NONATOMIC (property))
+	{
+	  /* We build "self->PROPERTY_IVAR_NAME = new_value;"  */
+	  statement = build_modify_expr
+	    (location,
+	     objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property)),
+	     NULL_TREE, NOP_EXPR, 
+	     location, new_value, NULL_TREE);
+	  break;
+	}
+      else
+	{
+	  /* We build
+	       objc_setPropertyStruct (&(self->PROPERTY_IVAR_NAME),
+	                               &new_value,
+	                               sizeof (type of self->PROPERTY_IVAR_NAME),
+				       is_atomic,
+				       false)
+
+	     For the NeXT runtime, we need to use objc_copyStruct
+	     instead of objc_getPropertyStruct.  */
+	  tree function_decl, size_of, is_atomic;
+
+	  /* sizeof (ivar type).  Since the ivar and the property have
+	     the same type, there is no need to lookup the ivar.  */
+	  size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
+					      true /* is_sizeof */,
+					      false /* complain */);
+	  
+	  if (PROPERTY_NONATOMIC (property))
+	    is_atomic = boolean_false_node;
+	  else
+	    is_atomic = boolean_true_node;
+	  
+	  if (flag_next_runtime)
+	    function_decl = objc_copyStruct_decl;
+	  else
+	    function_decl = objc_setPropertyStruct_decl;
+
+	  statement = build_function_call 
+	    (location,
+	     /* Function prototype.  */
+	     function_decl,
+	     /* Parameters.  */
+	     tree_cons /* &(self->PROPERTY_IVAR_NAME); */
+	     (NULL_TREE, build_fold_addr_expr_loc (location, 
+						   objc_lookup_ivar 
+						   (NULL_TREE, PROPERTY_IVAR_NAME (property))),
+	      tree_cons /* &new_value */
+	      (NULL_TREE, build_fold_addr_expr_loc (location, new_value),
+	       tree_cons /* sizeof (PROPERTY_IVAR) */
+	       (NULL_TREE, size_of,
+		tree_cons /* is_atomic */
+		(NULL_TREE, is_atomic,
+		 /* TODO: This is currently ignored by the GNU
+		    runtime, but what about the next one ? */
+		 tree_cons /* has_strong */
+		 (NULL_TREE, boolean_true_node, NULL_TREE))))));
+	}
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  gcc_assert (statement);
+
+  add_stmt (statement);  
+  add_stmt (c_end_compound_stmt (location, body, true));
   fn = current_function_decl;
 #ifdef OBJCPLUS
   finish_function ();
diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h
index 95e90703c5a7..4c10c01378e2 100644
--- a/gcc/objc/objc-act.h
+++ b/gcc/objc/objc-act.h
@@ -339,6 +339,12 @@ enum objc_tree_index
     OCTI_FAST_ENUM_STATE_TEMP,
     OCTI_ENUM_MUTATION_DECL,
 
+    OCTI_GET_PROPERTY_DECL,
+    OCTI_SET_PROPERTY_DECL,
+    OCTI_COPY_STRUCT_DECL,
+    OCTI_GET_PROPERTY_STRUCT_DECL,
+    OCTI_SET_PROPERTY_STRUCT_DECL,
+
     OCTI_MAX
 };
 
@@ -506,4 +512,13 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX];
 #define objc_enumeration_mutation_decl		\
                                 objc_global_trees[OCTI_ENUM_MUTATION_DECL]
 
+/* Declarations of functions used when synthesizing property
+   accessors.  */
+#define objc_getProperty_decl       objc_global_trees[OCTI_GET_PROPERTY_DECL]
+#define objc_setProperty_decl       objc_global_trees[OCTI_SET_PROPERTY_DECL]
+#define objc_copyStruct_decl        objc_global_trees[OCTI_COPY_STRUCT_DECL]
+#define objc_getPropertyStruct_decl objc_global_trees[OCTI_GET_PROPERTY_STRUCT_DECL]
+#define objc_setPropertyStruct_decl objc_global_trees[OCTI_SET_PROPERTY_STRUCT_DECL]
+
+
 #endif /* GCC_OBJC_ACT_H */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b52b52900103..ae4de13e2f57 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,25 @@
+2010-11-01  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+	Implemented Objective-C 2.0 property accessors.
+	* objc.dg/property/at-property-6.m: Use nonatomic properties to
+	avoid testing more complex accessors in this testcase which is not
+	about them.
+	* objc.dg/property/at-property-7.m: Same change.
+	* objc.dg/property/at-property-8.m: Same change.
+	* objc.dg/property/at-property-9.m: Same change.
+	* objc.dg/property/at-property-10.m: Same change.
+	* objc.dg/property/at-property-11.m: Same change.
+	* obj-c++.dg/property/at-property-6.mm: Same change.
+	* obj-c++.dg/property/at-property-7.mm: Same change.
+	* obj-c++.dg/property/at-property-8.mm: Same change.
+	* obj-c++.dg/property/at-property-9.mm: Same change.
+	* obj-c++.dg/property/at-property-10.mm: Same change.
+	* obj-c++.dg/property/at-property-11.mm: Same change.
+	* objc.dg/property/at-property-12.m: New.
+	* objc.dg/property/at-property-13.m: New.
+	* obj-c++.dg/property/at-property-12.mm: New.
+	* obj-c++.dg/property/at-property-13.mm: New.	
+	
 2010-11-01  Steven G. Kargl  <kargl@gcc.gnu.org>
 
 	PR fortran/46152
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-10.mm b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm
index f130292bb0f3..83494ec3bccd 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-10.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm
@@ -12,7 +12,7 @@
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-11.mm b/gcc/testsuite/obj-c++.dg/property/at-property-11.mm
index 36da7bf27948..82880521680d 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-11.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-11.mm
@@ -12,7 +12,7 @@
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-12.mm b/gcc/testsuite/obj-c++.dg/property/at-property-12.mm
new file mode 100644
index 000000000000..8d28bde96684
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-12.mm
@@ -0,0 +1,46 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010.  */
+/* { dg-do run } */
+
+/* Test atomic, assign synthesized methods.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+  id b;
+}
+@property int a;
+@property (assign) id b;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@synthesize b;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  object.a = 40;
+  if (object.a != 40)
+    abort ();
+
+  object.b = object;
+  if (object.b != object)
+    abort ();
+
+  return (0);
+}
+
+
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-13.mm b/gcc/testsuite/obj-c++.dg/property/at-property-13.mm
new file mode 100644
index 000000000000..5a5dcbbf63ce
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-13.mm
@@ -0,0 +1,71 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010.  */
+/* { dg-do run } */
+
+/* Test retain and copy synthesized methods.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int copy_count;
+  id a;
+  id b;
+}
+@property (copy) id a;
+@property (retain) id b;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (id) copyWithZone: (void *)zone;
+- (int) copyCount;
+- (id) autorelease;
+- (oneway void) release;
+- (id) retain;
+@end
+
+/* This class implements copyWithZone, which doesn't do anything other
+   than increasing a counter of how many copies were made.  */
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (id) copyWithZone: (void *)zone { copy_count++; return self; }
+- (int) copyCount { return copy_count; }
+- (id) autorelease { return self; }
+- (oneway void) release { return; }
+- (id) retain { return self; }
+@synthesize a;
+@synthesize b;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+  MyRootClass *argument = [[MyRootClass alloc] init];
+
+  /* This should copy argument.  */
+  object.a = argument;
+  if (object.a != argument)
+    abort ();
+
+  /* Test that it was copied.  */
+  if ([object.a copyCount] != 1)
+    abort ();
+
+  /* We just test that the retain accessors seem to work and that they
+     don't copy.  We don't test that retain was actually called,
+     because if garbage collection is enabled, it may never be
+     called!  */
+  object.b = argument;
+  if (object.b != argument)
+    abort ();
+
+  /* Test that it was not copied.  */
+  if ([object.b copyCount] != 1)
+    abort ();
+
+  return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-6.mm b/gcc/testsuite/obj-c++.dg/property/at-property-6.mm
index 3f1f0d3abe0c..8b7346b95af7 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-6.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-6.mm
@@ -13,7 +13,7 @@
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-7.mm b/gcc/testsuite/obj-c++.dg/property/at-property-7.mm
index cae04dee498f..bace2420e57e 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-7.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-7.mm
@@ -13,7 +13,7 @@
   Class isa;
   int a;
 }
-@property (getter = getA) int a;
+@property (getter = getA, nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-8.mm b/gcc/testsuite/obj-c++.dg/property/at-property-8.mm
index ec37052989a3..a290dd3df35c 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-8.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-8.mm
@@ -13,7 +13,7 @@
   Class isa;
   int a;
 }
-@property (setter = writeA:) int a;
+@property (setter = writeA:, nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-9.mm b/gcc/testsuite/obj-c++.dg/property/at-property-9.mm
index 12e9ffde872b..be52e37f5d06 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-9.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-9.mm
@@ -13,7 +13,7 @@
   Class isa;
   int a;
 }
-@property (getter = giveMeA, setter = writeA:) int a;
+@property (getter = giveMeA, setter = writeA:, nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/objc.dg/property/at-property-10.m b/gcc/testsuite/objc.dg/property/at-property-10.m
index bc6380cd5a6d..1a7a04308992 100644
--- a/gcc/testsuite/objc.dg/property/at-property-10.m
+++ b/gcc/testsuite/objc.dg/property/at-property-10.m
@@ -12,7 +12,10 @@
   Class isa;
   int a;
 }
-@property int a;
+/* Use the simplest synthesized accessor (assign, nonatomic) as we are
+   not testing the synthesized accessors in this test, just the
+   property syntax.  */
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/objc.dg/property/at-property-11.m b/gcc/testsuite/objc.dg/property/at-property-11.m
index 84857e0659a5..2526a9cc1ded 100644
--- a/gcc/testsuite/objc.dg/property/at-property-11.m
+++ b/gcc/testsuite/objc.dg/property/at-property-11.m
@@ -12,7 +12,10 @@
   Class isa;
   int a;
 }
-@property int a;
+/* Use the simplest synthesized accessor (assign, nonatomic) as we are
+   not testing the synthesized accessors in this test, just the
+   property syntax.  */
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/objc.dg/property/at-property-12.m b/gcc/testsuite/objc.dg/property/at-property-12.m
new file mode 100644
index 000000000000..e96b198282ca
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-12.m
@@ -0,0 +1,46 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010.  */
+/* { dg-do run } */
+
+/* Test atomic, assign synthesized methods.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+  id b;
+}
+@property int a;
+@property (assign) id b;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@synthesize b;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  object.a = 40;
+  if (object.a != 40)
+    abort ();
+
+  object.b = object;
+  if (object.b != object)
+    abort ();
+
+  return 0;
+}
+
+
diff --git a/gcc/testsuite/objc.dg/property/at-property-13.m b/gcc/testsuite/objc.dg/property/at-property-13.m
new file mode 100644
index 000000000000..dfdb02f71277
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-13.m
@@ -0,0 +1,71 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010.  */
+/* { dg-do run } */
+
+/* Test retain and copy synthesized methods.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int copy_count;
+  id a;
+  id b;
+}
+@property (copy) id a;
+@property (retain) id b;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (id) copyWithZone: (void *)zone;
+- (int) copyCount;
+- (id) autorelease;
+- (oneway void) release;
+- (id) retain;
+@end
+
+/* This class implements copyWithZone, which doesn't do anything other
+   than increasing a counter of how many copies were made.  */
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (id) copyWithZone: (void *)zone { copy_count++; return self; }
+- (int) copyCount { return copy_count; }
+- (id) autorelease { return self; }
+- (oneway void) release { return; }
+- (id) retain { return self; }
+@synthesize a;
+@synthesize b;
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+  MyRootClass *argument = [[MyRootClass alloc] init];
+
+  /* This should copy argument.  */
+  object.a = argument;
+  if (object.a != argument)
+    abort ();
+
+  /* Test that it was copied.  */
+  if ([object.a copyCount] != 1)
+    abort ();
+
+  /* We just test that the retain accessors seem to work and that they
+     don't copy.  We don't test that retain was actually called,
+     because if garbage collection is enabled, it may never be
+     called!  */
+  object.b = argument;
+  if (object.b != argument)
+    abort ();
+
+  /* Test that it was not copied.  */
+  if ([object.b copyCount] != 1)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-6.m b/gcc/testsuite/objc.dg/property/at-property-6.m
index a97c0b05f670..079995c526a9 100644
--- a/gcc/testsuite/objc.dg/property/at-property-6.m
+++ b/gcc/testsuite/objc.dg/property/at-property-6.m
@@ -13,7 +13,7 @@
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/objc.dg/property/at-property-7.m b/gcc/testsuite/objc.dg/property/at-property-7.m
index dce276407817..6f182d0730e1 100644
--- a/gcc/testsuite/objc.dg/property/at-property-7.m
+++ b/gcc/testsuite/objc.dg/property/at-property-7.m
@@ -13,7 +13,7 @@
   Class isa;
   int a;
 }
-@property (getter = getA) int a;
+@property (getter = getA, nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/objc.dg/property/at-property-8.m b/gcc/testsuite/objc.dg/property/at-property-8.m
index eb1588937246..94ed86e7f8b7 100644
--- a/gcc/testsuite/objc.dg/property/at-property-8.m
+++ b/gcc/testsuite/objc.dg/property/at-property-8.m
@@ -13,7 +13,7 @@
   Class isa;
   int a;
 }
-@property (setter = writeA:) int a;
+@property (setter = writeA:, nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
diff --git a/gcc/testsuite/objc.dg/property/at-property-9.m b/gcc/testsuite/objc.dg/property/at-property-9.m
index 203eb3003fde..6e2d118882f8 100644
--- a/gcc/testsuite/objc.dg/property/at-property-9.m
+++ b/gcc/testsuite/objc.dg/property/at-property-9.m
@@ -13,7 +13,10 @@
   Class isa;
   int a;
 }
-@property (getter = giveMeA, setter = writeA:) int a;
+/* Use the simplest synthesized accessor (assign, nonatomic) as we are
+   not testing the synthesized accessors in this test, just the
+   property syntax.  */
+@property (getter = giveMeA, setter = writeA:, nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
-- 
GitLab