Patchwork ObjC/ObjC++ - implementation of non-trivial property accessors

login
register
mail settings
Submitter Nicola Pero
Date Oct. 31, 2010, 3:07 a.m.
Message ID <1288494438.904522398@192.168.4.58>
Download mbox | patch
Permalink /patch/69687/
State New
Headers show

Comments

Nicola Pero - Oct. 31, 2010, 3:07 a.m.
This patch implements synthesizing accessors for Objective-C / Objective-C++
properties which are 'atomic', 'retain' or 'copy'. :-)

The existing code would only work for 'assign, nonatomic' properties, in which
case the getter/setter methods simply access the instance variable directly.

The new code can generate more sophisticated getter/setter methods that call into
helper functions in the Objective-C runtime.  For the next runtime these are
objc_getProperty(), objc_setProperty() and objc_copyStruct().  In the GNU runtime
I used identical functions, with the exception of the last one, objc_copyStruct(), 
which seems to have been designed wrong (in a messy way as it requires two locks instead
of one to protect the property because the runtime is unable to determine which 
argument is the property to protect and which argument is the external variable (!)), 
and I couldn't see any reason to reproduce the same error in the GNU runtime, 
where I used two separate functions (designed correctly) instead, called 
objc_getPropertyStruct() and objc_setPropertyStruct(), requiring only one lock 
to protect the property (as expected).  These helpers are part of the runtime ABI,
so the GNU runtime doesn't have to be the same as the next runtime - users never
see these functions directly.  But because they are part of the ABI, it's not
necessarily easy to change them later once you add them.  I hope ours are good. :-)

Testcases are included; they all pass with the GNU runtime.  They should work with 
the next runtime too if garbage collection is disabled and the old ABI is used, as the
only difference is the usage of objc_copyStruct instead of objc_getPropertyStruct
and objc_setPropertyStruct (anyway if there are any issues, we have 2 months
to fix them). :-)

Ok to commit to trunk ?

Thanks

In gcc/objc/:
2010-10-31  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-10-31  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.
Mike Stump - Nov. 1, 2010, 4:13 p.m.
On Oct 30, 2010, at 8:07 PM, Nicola Pero wrote:
> This patch implements synthesizing accessors for Objective-C / Objective-C++
> properties which are 'atomic', 'retain' or 'copy'. :-)

> Ok to commit to trunk ?

Ok.

Patch

Index: objc/objc-act.c
===================================================================
--- objc/objc-act.c	(revision 166087)
+++ objc/objc-act.c	(working copy)
@@ -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_visib
   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 @@  static void
   /* 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:
 
-  /* return self->_property_name; */
+     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.
 
-  /* 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));
+     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 ();
+    }
+
   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 @@  static void
 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_UNUSE
 
   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.  */
+  /* 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)));
 
-  /* _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"));
-
   /* 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;
+      error_at (DECL_SOURCE_LOCATION (decl), "invalid setter, it must have one argument");
+      /* Try to recover somehow.  */
+      new_value = error_mark_node;
     }
 
-  /* 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));
+  /* 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 ();
Index: objc/ChangeLog
===================================================================
--- objc/ChangeLog	(revision 166087)
+++ objc/ChangeLog	(working copy)
@@ -1,3 +1,23 @@ 
+2010-10-31  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.
Index: objc/objc-act.h
===================================================================
--- objc/objc-act.h	(revision 166087)
+++ objc/objc-act.h	(working copy)
@@ -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 */
Index: testsuite/ChangeLog
===================================================================
--- testsuite/ChangeLog	(revision 166087)
+++ testsuite/ChangeLog	(working copy)
@@ -1,3 +1,25 @@ 
+2010-10-31  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-10-30  Nicola Pero  <nicola.pero@meta-innovation.com>
 
 	Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
Index: testsuite/objc.dg/property/at-property-6.m
===================================================================
--- testsuite/objc.dg/property/at-property-6.m	(revision 166087)
+++ testsuite/objc.dg/property/at-property-6.m	(working copy)
@@ -13,7 +13,7 @@ 
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
Index: testsuite/objc.dg/property/at-property-7.m
===================================================================
--- testsuite/objc.dg/property/at-property-7.m	(revision 166087)
+++ testsuite/objc.dg/property/at-property-7.m	(working copy)
@@ -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;
Index: testsuite/objc.dg/property/at-property-8.m
===================================================================
--- testsuite/objc.dg/property/at-property-8.m	(revision 166087)
+++ testsuite/objc.dg/property/at-property-8.m	(working copy)
@@ -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;
Index: testsuite/objc.dg/property/at-property-9.m
===================================================================
--- testsuite/objc.dg/property/at-property-9.m	(revision 166087)
+++ testsuite/objc.dg/property/at-property-9.m	(working copy)
@@ -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;
Index: testsuite/objc.dg/property/at-property-10.m
===================================================================
--- testsuite/objc.dg/property/at-property-10.m	(revision 166087)
+++ testsuite/objc.dg/property/at-property-10.m	(working copy)
@@ -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;
Index: testsuite/objc.dg/property/at-property-11.m
===================================================================
--- testsuite/objc.dg/property/at-property-11.m	(revision 166087)
+++ testsuite/objc.dg/property/at-property-11.m	(working copy)
@@ -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;
Index: testsuite/objc.dg/property/at-property-12.m
===================================================================
--- testsuite/objc.dg/property/at-property-12.m	(revision 0)
+++ testsuite/objc.dg/property/at-property-12.m	(revision 0)
@@ -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;
+}
+
+
Index: testsuite/objc.dg/property/at-property-13.m
===================================================================
--- testsuite/objc.dg/property/at-property-13.m	(revision 0)
+++ testsuite/objc.dg/property/at-property-13.m	(revision 0)
@@ -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;
+}
Index: testsuite/obj-c++.dg/property/at-property-13.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-13.mm	(revision 0)
+++ testsuite/obj-c++.dg/property/at-property-13.mm	(revision 0)
@@ -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);
+}
Index: testsuite/obj-c++.dg/property/at-property-7.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-7.mm	(revision 166087)
+++ testsuite/obj-c++.dg/property/at-property-7.mm	(working copy)
@@ -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;
Index: testsuite/obj-c++.dg/property/at-property-9.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-9.mm	(revision 166087)
+++ testsuite/obj-c++.dg/property/at-property-9.mm	(working copy)
@@ -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;
Index: testsuite/obj-c++.dg/property/at-property-10.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-10.mm	(revision 166087)
+++ testsuite/obj-c++.dg/property/at-property-10.mm	(working copy)
@@ -12,7 +12,7 @@ 
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
Index: testsuite/obj-c++.dg/property/at-property-12.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-12.mm	(revision 0)
+++ testsuite/obj-c++.dg/property/at-property-12.mm	(revision 0)
@@ -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);
+}
+
+
Index: testsuite/obj-c++.dg/property/at-property-6.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-6.mm	(revision 166087)
+++ testsuite/obj-c++.dg/property/at-property-6.mm	(working copy)
@@ -13,7 +13,7 @@ 
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;
Index: testsuite/obj-c++.dg/property/at-property-8.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-8.mm	(revision 166087)
+++ testsuite/obj-c++.dg/property/at-property-8.mm	(working copy)
@@ -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;
Index: testsuite/obj-c++.dg/property/at-property-11.mm
===================================================================
--- testsuite/obj-c++.dg/property/at-property-11.mm	(revision 166087)
+++ testsuite/obj-c++.dg/property/at-property-11.mm	(working copy)
@@ -12,7 +12,7 @@ 
   Class isa;
   int a;
 }
-@property int a;
+@property (nonatomic) int a;
 + (id) initialize;
 + (id) alloc;
 - (id) init;