Patchwork =?UTF-8?Q?ObjC/ObjC++=20-=20@property=20parsing=20(2)?=

login
register
mail settings
Submitter Nicola Pero
Date Oct. 26, 2010, 11:27 a.m.
Message ID <1288092464.877230470@192.168.2.227>
Download mbox | patch
Permalink /patch/69234/
State New
Headers show

Comments

Nicola Pero - Oct. 26, 2010, 11:27 a.m.
(apologies, this patch got stuck in my computer last night, reposting now)

This patch (which can only be applied on top of the previous one) does another chunk of work on @property:

 * it implements parsing all of the missing @property attributes (assign, copy, retain, nonatomic, readwrite)

 * it tidies up the interface between the parser and objc-act.c.  It's now composed of a single function,
objc_add_property_declaration().  The parsing is all done in the parser, which parses the property and
accumulates the property attributes in local variables, then calls objc_add_property_declaration() passing all 
the details of the @property in explicit arguments.  The "global" (to objc-act.c) property variables 
(property_readonly, property_getter, etc) are gone, and so is objc_set_property_attr.

 * it implements checking all the new @property attributes and preparing the final property attributes that
will be used.

 * it adds testcases for parsing the new property attributes (and producing the correct errors/warnings 
on conflicting attributes) in both Objective-C and Objective-C++.

I haven't implemented the functionality of the new attributes yet.  That will be another patch.

In the interest of incremental changes of reasonable size, I have also left the old copies and ivar property 
attributes in place, and haven't removed the ability to use @property in @implementation yet.  I'll do that
once I have implemented @synthesize and I'll be able to update all the testcases to use @synthesize instead
of @property inside an @implementation context.

All testcases still pass, and the new ones too.

Ok to commit to trunk ?

Thanks

In gcc/:
2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>

        * c-parser.c (c_parser_objc_at_property_declaration): Recognize
        RID_ASSIGN, RID_COPY, RID_RETAIN, RID_READWRITE and RID_NONATOMIC.
        Do not use objc_set_property_attr, but use local variables
        instead.  Detect repeated usage of setter, getter and ivar
        attributes.  Improved error processing when a setter name does not
        end in ':'.  Do not check for CPP_CLOSE_PAREN after we determined
        that the token is a keyword.  Updated call to
        objc_add_property_declaration.

In gcc/cp/:
2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>

        * parser.c (cp_parser_objc_at_property_declaration): Recognize
        RID_ASSIGN, RID_COPY, RID_RETAIN, RID_READWRITE and RID_NONATOMIC.
        Do not use objc_set_property_attr, but use local variables
        instead.  Detect repeated usage of setter, getter and ivar
        attributes.  Improved error processing when a setter name does not
        end in ':'.  Do not check for CPP_CLOSE_PAREN after we determined
        that the token is a keyword.  Updated call to
        objc_add_property_declaration.

In gcc/c-family/:
2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>

        * c-common.h (enum rid): Added RID_READWRITE, RID_ASSIGN,
        RID_RETAIN, RID_COPY and RID_NONATOMIC.  Updated RID_FIRST_PATTR
        and RID_LAST_PATTR.
        (objc_add_property_declaration): Added additional arguments.
        (objc_property_attribute_kind): Removed.
        (objc_set_property_attr): Removed.
        * c-common.c (c_common_reswords): Added readwrite, assign, retain,
        copy and nonatomic.
        * stub-objc.c (objc_add_property_declaration): Added additional
        arguments.
        (objc_set_property_attr): Removed.

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

        * objc-act.c (objc_add_property_declaration): Added arguments to
        pass the various property attributes that were parsed with the
        property declaration.  Process arguments to determine the final
        property attributes and produce error messages as appropriate.
        Added temporary code to keep the compiler silent about variables
        set but not used - for new attributes that are only checked but
        have no effect yet.
        (property_readonly): Removed.
        (property_setter): Removed.
        (property_getter): Removed.
        (property_ivar): Removed.
        (property_copies): Removed.
        (objc_set_property_attr): Removed.
        * objc-act.h (enum property_assign_semantics): New.

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

        * obj-c.dg/property/at-property-4.m: New.
        * obj-c++.dg/property/at-property-4.mm: New.
        * obj-c++.dg/property/property-neg-5.m: Updated testcase for
        updates in warning.
        * obj-c++.dg/property/property-neg-5.mm: Updated testcase for
        updates in warning.
Mike Stump - Oct. 27, 2010, 2:52 a.m.
On Oct 26, 2010, at 7:27 AM, Nicola Pero wrote:
> This patch (which can only be applied on top of the previous one)  
> does another chunk of work on @property:


> Ok to commit to trunk ?

Ok.

Patch

diff -rupN --exclude=.svn trunk3/gcc/c-family/c-common.c trunk4/gcc/c-family/c-common.c
--- trunk3/gcc/c-family/c-common.c	2010-10-24 00:46:29.000000000 +0100
+++ trunk4/gcc/c-family/c-common.c	2010-10-25 23:25:11.000000000 +0100
@@ -556,10 +556,16 @@  const struct c_common_resword c_common_r
   { "oneway",		RID_ONEWAY,		D_OBJC },
   { "out",		RID_OUT,		D_OBJC },
   /* These are recognized inside a property attribute list */
-  { "readonly",		RID_READONLY,		D_OBJC }, 
-  { "copies",		RID_COPIES,		D_OBJC },
+  { "assign",	        RID_ASSIGN,		D_OBJC }, 
+  { "copy",	        RID_COPY,		D_OBJC }, 
   { "getter",		RID_GETTER,		D_OBJC }, 
+  { "nonatomic",	RID_NONATOMIC,		D_OBJC }, 
+  { "readonly",		RID_READONLY,		D_OBJC }, 
+  { "readwrite",	RID_READWRITE,		D_OBJC }, 
+  { "retain",	        RID_RETAIN,		D_OBJC }, 
   { "setter",		RID_SETTER,		D_OBJC }, 
+  /* The following two will be removed once @synthesize is fully implemented.  */
+  { "copies",		RID_COPIES,		D_OBJC },
   { "ivar",		RID_IVAR,		D_OBJC }, 
 };
 
diff -rupN --exclude=.svn trunk3/gcc/c-family/c-common.h trunk4/gcc/c-family/c-common.h
--- trunk3/gcc/c-family/c-common.h	2010-10-25 21:51:41.000000000 +0100
+++ trunk4/gcc/c-family/c-common.h	2010-10-25 23:25:10.000000000 +0100
@@ -82,7 +82,13 @@  enum rid
 
   /* ObjC ("PATTR" reserved words - they do not appear after a '@' 
      and are keywords only as property attributes)  */
-  RID_READONLY, RID_COPIES, RID_GETTER, RID_SETTER, RID_IVAR,
+  RID_GETTER, RID_SETTER,
+  RID_READONLY, RID_READWRITE,
+  RID_ASSIGN, RID_RETAIN, RID_COPY,
+  /* RID_IVAR and RID_COPIES will be removed once @synthesize is
+     completed.  */
+  RID_COPIES, RID_IVAR,
+  RID_NONATOMIC,
 
   /* C (reserved and imaginary types not implemented, so any use is a
      syntax error) */
@@ -187,8 +193,8 @@  enum rid
   RID_LAST_AT = RID_AT_IMPLEMENTATION,
   RID_FIRST_PQ = RID_IN,
   RID_LAST_PQ = RID_ONEWAY,
-  RID_FIRST_PATTR = RID_READONLY,
-  RID_LAST_PATTR = RID_IVAR
+  RID_FIRST_PATTR = RID_GETTER,
+  RID_LAST_PATTR = RID_NONATOMIC
 };
 
 #define OBJC_IS_AT_KEYWORD(rid) \
@@ -431,16 +437,6 @@  extern c_language_kind c_language;
 #define c_dialect_cxx()		((c_language & clk_cxx) != 0)
 #define c_dialect_objc()	((c_language & clk_objc) != 0)
 
-/* ObjC Property Attribute types.  */
-typedef enum objc_property_attribute_kind {
-  OBJC_PATTR_INIT	= 0,
-  OBJC_PATTR_READONLY	= 1,
-  OBJC_PATTR_GETTER	= 2,
-  OBJC_PATTR_SETTER	= 3,
-  OBJC_PATTR_IVAR	= 4,
-  OBJC_PATTR_COPIES	= 5
-} objc_property_attribute_kind;
-
 /* ObjC ivar visibility types.  */
 typedef enum objc_ivar_visibility_kind {
   OBJC_IVAR_VIS_PROTECTED = 0,
@@ -1040,10 +1036,10 @@  extern tree objc_generate_static_init_ca
 extern tree objc_generate_write_barrier (tree, enum tree_code, tree);
 extern void objc_set_method_opt (bool);
 extern void objc_finish_foreach_loop (location_t, tree, tree, tree, tree, tree);
-extern void objc_set_property_attr 
-  (location_t, objc_property_attribute_kind, tree);
 extern bool  objc_method_decl (enum tree_code);
-extern void objc_add_property_declaration (location_t, tree);
+extern void objc_add_property_declaration (location_t, tree, bool, bool, bool, 
+					   bool, bool, bool, tree, tree,
+					   bool, tree);
 extern tree objc_build_getter_call (tree, tree);
 extern tree objc_build_setter_call (tree, tree);
 extern void objc_add_synthesize_declaration (location_t, tree);
diff -rupN --exclude=.svn trunk3/gcc/c-family/ChangeLog trunk4/gcc/c-family/ChangeLog
--- trunk3/gcc/c-family/ChangeLog	2010-10-25 20:22:12.000000000 +0100
+++ trunk4/gcc/c-family/ChangeLog	2010-10-26 11:34:52.000000000 +0100
@@ -1,5 +1,19 @@ 
 2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* c-common.h (enum rid): Added RID_READWRITE, RID_ASSIGN,
+	RID_RETAIN, RID_COPY and RID_NONATOMIC.  Updated RID_FIRST_PATTR
+	and RID_LAST_PATTR.
+	(objc_add_property_declaration): Added additional arguments.
+	(objc_property_attribute_kind): Removed.
+	(objc_set_property_attr): Removed.
+	* c-common.c (c_common_reswords): Added readwrite, assign, retain,
+	copy and nonatomic.
+	* stub-objc.c (objc_add_property_declaration): Added additional
+	arguments.
+	(objc_set_property_attr): Removed.
+	
+2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* c-common.h (objc_add_property_variable): Renamed to
 	objc_add_property_declaration.  Added location argument.
 	* stub-objc.c (objc_add_property_variable): Same change.
diff -rupN --exclude=.svn trunk3/gcc/c-family/stub-objc.c trunk4/gcc/c-family/stub-objc.c
--- trunk3/gcc/c-family/stub-objc.c	2010-10-24 22:38:27.000000000 +0100
+++ trunk4/gcc/c-family/stub-objc.c	2010-10-25 21:05:00.000000000 +0100
@@ -324,14 +324,18 @@  objc_get_class_ivars (tree ARG_UNUSED (n
 }
 
 void
-objc_set_property_attr (location_t ARG_UNUSED (loc),
-			objc_property_attribute_kind ARG_UNUSED (code),
-			tree ARG_UNUSED (identifier))
-{
-}
-
-void
-objc_add_property_declaration (location_t ARG_UNUSED (loc), tree ARG_UNUSED (prop))
+objc_add_property_declaration (location_t ARG_UNUSED (location), 
+			       tree ARG_UNUSED (decl),
+			       bool ARG_UNUSED (parsed_property_readonly),
+			       bool ARG_UNUSED (parsed_property_readwrite),
+			       bool ARG_UNUSED (parsed_property_assign),
+			       bool ARG_UNUSED (parsed_property_retain),
+			       bool ARG_UNUSED (parsed_property_copy),
+			       bool ARG_UNUSED (parsed_property_nonatomic),
+			       tree ARG_UNUSED (parsed_property_getter_ident),
+			       tree ARG_UNUSED (parsed_property_setter_ident),
+			       bool ARG_UNUSED (parsed_property_copies),
+			       tree ARG_UNUSED (parsed_property_ivar_ident))
 {
 }
 
diff -rupN --exclude=.svn trunk3/gcc/ChangeLog trunk4/gcc/ChangeLog
--- trunk3/gcc/ChangeLog	2010-10-26 10:49:44.000000000 +0100
+++ trunk4/gcc/ChangeLog	2010-10-26 11:34:11.000000000 +0100
@@ -1,5 +1,16 @@ 
 2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* c-parser.c (c_parser_objc_at_property_declaration): Recognize
+	RID_ASSIGN, RID_COPY, RID_RETAIN, RID_READWRITE and RID_NONATOMIC.
+	Do not use objc_set_property_attr, but use local variables
+	instead.  Detect repeated usage of setter, getter and ivar
+	attributes.  Improved error processing when a setter name does not
+	end in ':'.  Do not check for CPP_CLOSE_PAREN after we determined
+	that the token is a keyword.  Updated call to
+	objc_add_property_declaration.
+
+2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* c-parser.c (c_parser_objc_at_property): Renamed to
 	c_parser_objc_at_property_declaration.  Updated calls to
 	objc_add_property_variable, now objc_add_property_declaration.
diff -rupN --exclude=.svn trunk3/gcc/cp/ChangeLog trunk4/gcc/cp/ChangeLog
--- trunk3/gcc/cp/ChangeLog	2010-10-26 10:49:33.000000000 +0100
+++ trunk4/gcc/cp/ChangeLog	2010-10-26 11:34:32.000000000 +0100
@@ -1,5 +1,16 @@ 
 2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* parser.c (cp_parser_objc_at_property_declaration): Recognize
+	RID_ASSIGN, RID_COPY, RID_RETAIN, RID_READWRITE and RID_NONATOMIC.
+	Do not use objc_set_property_attr, but use local variables
+	instead.  Detect repeated usage of setter, getter and ivar
+	attributes.  Improved error processing when a setter name does not
+	end in ':'.  Do not check for CPP_CLOSE_PAREN after we determined
+	that the token is a keyword.  Updated call to
+	objc_add_property_declaration.
+
+2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* parser.c (cp_parser_objc_property_decl): Renamed to
 	cp_parser_objc_struct_declaration.  Return the parsed trees
 	instead of calling objc_add_property_variable directly.  Detect
diff -rupN --exclude=.svn trunk3/gcc/cp/parser.c trunk4/gcc/cp/parser.c
--- trunk3/gcc/cp/parser.c	2010-10-26 10:48:50.000000000 +0100
+++ trunk4/gcc/cp/parser.c	2010-10-26 10:50:49.000000000 +0100
@@ -22648,23 +22648,41 @@  cp_parser_objc_struct_declaration (cp_pa
     @property int a, b, c;
 
    PS: This function is identical to
-   c_parser_objc_at_property_declaration for C.  Keep them in sync.
-
-   WORK IN PROGRESS: At the moment, the list of attributes that are
-   parsed is different from the above list.  It will be updated to use
-   the above list at the same time as @synthesize is implemented.  */
+   c_parser_objc_at_property_declaration for C.  Keep them in sync.  */
 static void 
 cp_parser_objc_at_property_declaration (cp_parser *parser)
 {
+  /* The following variables hold the attributes of the properties as
+     parsed.  They are 'false' or 'NULL_TREE' if the attribute was not
+     seen.  When we see an attribute, we set them to 'true' (if they
+     are boolean properties) or to the identifier (if they have an
+     argument, ie, for getter and setter).  Note that here we only
+     parse the list of attributes, check the syntax and accumulate the
+     attributes that we find.  objc_add_property_declaration() will
+     then process the information.  */
+  bool property_assign = false;
+  bool property_copy = false;
+  tree property_getter_ident = NULL_TREE;
+  bool property_nonatomic = false;
+  bool property_readonly = false;
+  bool property_readwrite = false;
+  bool property_retain = false;
+  tree property_setter_ident = NULL_TREE;
+  /* The following two will be removed once @synthesize is
+     implemented.  */
+  bool property_copies = false;
+  tree property_ivar_ident = NULL_TREE;
+
+  /* 'properties' is the list of properties that we read.  Usually a
+     single one, but maybe more (eg, in "@property int a, b, c;" there
+     are three).  */
   tree properties;
   location_t loc;
+
   loc = cp_lexer_peek_token (parser->lexer)->location;
 
   cp_lexer_consume_token (parser->lexer);  /* Eat '@property'.  */
 
-  /* Initialize attributes to an empty list.  */
-  objc_set_property_attr (loc, OBJC_PATTR_INIT, NULL_TREE);
-
   /* Parse the optional attribute list...  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
     {
@@ -22683,18 +22701,20 @@  cp_parser_objc_at_property_declaration (
 	      break;
 	    }
 	  keyword = C_RID_CODE (token->u.value);
+	  cp_lexer_consume_token (parser->lexer);
 	  switch (keyword)
 	    {
-	      tree ident;
-	      objc_property_attribute_kind pkind;
-	    case RID_READONLY:
-	      cp_lexer_consume_token (parser->lexer);
-	      objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
-	      break;
+	    case RID_ASSIGN:    property_assign = true;    break;
+	    case RID_COPIES:    property_copies = true;    break;
+	    case RID_COPY:      property_copy = true;      break;
+	    case RID_NONATOMIC: property_nonatomic = true; break;
+	    case RID_READONLY:  property_readonly = true;  break;
+	    case RID_READWRITE: property_readwrite = true; break;
+	    case RID_RETAIN:    property_retain = true;    break;
+
 	    case RID_GETTER:
 	    case RID_SETTER:
 	    case RID_IVAR:
-	      cp_lexer_consume_token (parser->lexer);
 	      if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
 		{
 		  cp_parser_error (parser,
@@ -22709,39 +22729,37 @@  cp_parser_objc_at_property_declaration (
 		  syntax_error = true;
 		  break;
 		}
-	      ident = cp_lexer_peek_token (parser->lexer)->u.value;
-	      cp_lexer_consume_token (parser->lexer);
 	      if (keyword == RID_SETTER)
 		{
-		  pkind = OBJC_PATTR_SETTER;
-		  /* Eat the identifier, and look for the following : */
-		  if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
-		    {
-		      cp_parser_error (parser,
-				      "setter name must be followed by %<:%>");
-		      syntax_error = true;
-		      break;
-		    }
+		  if (property_setter_ident != NULL_TREE)
+		    cp_parser_error (parser, "the %<setter%> attribute may only be specified once");
+		  else
+		    property_setter_ident = cp_lexer_peek_token (parser->lexer)->u.value;
 		  cp_lexer_consume_token (parser->lexer);
+		  if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+		    cp_parser_error (parser, "setter name must terminate with %<:%>");
+		  else
+		    cp_lexer_consume_token (parser->lexer);
 		}
 	      else if (keyword == RID_GETTER)
-		pkind = OBJC_PATTR_GETTER;
-	      else
-		pkind = OBJC_PATTR_IVAR;
-	      objc_set_property_attr (loc, pkind, ident);
-	      break;
-	    case RID_COPIES:
-	      cp_lexer_consume_token (parser->lexer);
-	      objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE);
-	      break;
-	    default:
-	      if (token->type == CPP_CLOSE_PAREN)
-		cp_parser_error (parser, "expected identifier");
-	      else
 		{
+		  if (property_getter_ident != NULL_TREE)
+		    cp_parser_error (parser, "the %<getter%> attribute may only be specified once");
+		  else
+		    property_getter_ident = cp_lexer_peek_token (parser->lexer)->u.value;
 		  cp_lexer_consume_token (parser->lexer);
-		  cp_parser_error (parser, "unknown property attribute");
 		}
+	      else /* RID_IVAR, this case will go away.  */
+		{
+		  if (property_ivar_ident != NULL_TREE)
+		    cp_parser_error (parser, "the %<ivar%> attribute may only be specified once");
+		  else
+		    property_ivar_ident = cp_lexer_peek_token (parser->lexer)->u.value;
+		  cp_lexer_consume_token (parser->lexer);
+		}
+	      break;
+	    default:
+	      cp_parser_error (parser, "unknown property attribute");
 	      syntax_error = true;
 	      break;
 	    }
@@ -22785,7 +22803,13 @@  cp_parser_objc_at_property_declaration (
       properties = nreverse (properties);
       
       for (; properties; properties = TREE_CHAIN (properties))
-	objc_add_property_declaration (loc, copy_node (properties));
+	objc_add_property_declaration (loc, copy_node (properties),
+				       property_readonly, property_readwrite,
+				       property_assign, property_retain,
+				       property_copy, property_nonatomic,
+				       property_getter_ident, property_setter_ident,
+				       /* The following two will be removed.  */
+				       property_copies, property_ivar_ident);
     }
   
   cp_parser_consume_semicolon_at_end_of_statement (parser);
diff -rupN --exclude=.svn trunk3/gcc/c-parser.c trunk4/gcc/c-parser.c
--- trunk3/gcc/c-parser.c	2010-10-25 20:21:29.000000000 +0100
+++ trunk4/gcc/c-parser.c	2010-10-25 23:37:12.000000000 +0100
@@ -7603,24 +7603,42 @@  c_parser_objc_diagnose_bad_element_prefi
     @property int a, b, c;
 
   PS: This function is identical to cp_parser_objc_at_propery_declaration
-  for C++.  Keep them in sync.
-
-  WORK IN PROGRESS: At the moment, the list of attributes that are
-  parsed is different from the above list.  It will be updated to use
-  the above list at the same time as @synthesize is implemented.  */
+  for C++.  Keep them in sync.  */
 static void
 c_parser_objc_at_property_declaration (c_parser *parser)
 {
+  /* The following variables hold the attributes of the properties as
+     parsed.  They are 'false' or 'NULL_TREE' if the attribute was not
+     seen.  When we see an attribute, we set them to 'true' (if they
+     are boolean properties) or to the identifier (if they have an
+     argument, ie, for getter and setter).  Note that here we only
+     parse the list of attributes, check the syntax and accumulate the
+     attributes that we find.  objc_add_property_declaration() will
+     then process the information.  */
+  bool property_assign = false;
+  bool property_copy = false;
+  tree property_getter_ident = NULL_TREE;
+  bool property_nonatomic = false;
+  bool property_readonly = false;
+  bool property_readwrite = false;
+  bool property_retain = false;
+  tree property_setter_ident = NULL_TREE;
+  /* The following two will be removed once @synthesize is
+     implemented.  */
+  bool property_copies = false;
+  tree property_ivar_ident = NULL_TREE;
+
+  /* 'properties' is the list of properties that we read.  Usually a
+     single one, but maybe more (eg, in "@property int a, b, c;" there
+     are three).  */
   tree properties;
   location_t loc;
+
   loc = c_parser_peek_token (parser)->location;
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY));
 
   c_parser_consume_token (parser);  /* Eat '@property'.  */
 
-  /* Initialize attributes to an empty list.  */
-  objc_set_property_attr (loc, OBJC_PATTR_INIT, NULL_TREE);
-
   /* Parse the optional attribute list...  */
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
     {
@@ -7648,18 +7666,20 @@  c_parser_objc_at_property_declaration (c
 	      break;
 	    }
 	  keyword = token->keyword;
+	  c_parser_consume_token (parser);
 	  switch (keyword)
 	    {
-	      tree ident;
-	      objc_property_attribute_kind pkind;
-	    case RID_READONLY:
-	      c_parser_consume_token (parser);
-	      objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
-	      break;
+	    case RID_ASSIGN:    property_assign = true;    break;
+	    case RID_COPIES:    property_copies = true;    break;
+	    case RID_COPY:      property_copy = true;      break;
+	    case RID_NONATOMIC: property_nonatomic = true; break;
+	    case RID_READONLY:  property_readonly = true;  break;
+	    case RID_READWRITE: property_readwrite = true; break;
+	    case RID_RETAIN:    property_retain = true;    break;
+
 	    case RID_GETTER:
 	    case RID_SETTER:
 	    case RID_IVAR:
-	      c_parser_consume_token (parser);
 	      if (c_parser_next_token_is_not (parser, CPP_EQ))
 		{
 		  c_parser_error (parser,
@@ -7674,39 +7694,37 @@  c_parser_objc_at_property_declaration (c
 		  syntax_error = true;
 		  break;
 		}
-	      ident = c_parser_peek_token (parser)->value;
-	      c_parser_consume_token (parser);
 	      if (keyword == RID_SETTER)
 		{
-		  pkind = OBJC_PATTR_SETTER;
-		  /* Eat the identifier, and look for the following : */
-		  if (c_parser_next_token_is_not (parser, CPP_COLON))
-		    {
-		      c_parser_error (parser,
-				      "setter name must be followed by %<:%>");
-		      syntax_error = true;
-		      break;
-		    }
+		  if (property_setter_ident != NULL_TREE)
+		    c_parser_error (parser, "the %<setter%> attribute may only be specified once");
+		  else
+		    property_setter_ident = c_parser_peek_token (parser)->value;
 		  c_parser_consume_token (parser);
+		  if (c_parser_next_token_is_not (parser, CPP_COLON))
+		    c_parser_error (parser, "setter name must terminate with %<:%>");
+		  else
+		    c_parser_consume_token (parser);
 		}
 	      else if (keyword == RID_GETTER)
-		pkind = OBJC_PATTR_GETTER;
-	      else
-		pkind = OBJC_PATTR_IVAR;
-	      objc_set_property_attr (loc, pkind, ident);
-	      break;
-	    case RID_COPIES:
-	      c_parser_consume_token (parser);
-	      objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE);
-	      break;
-	    default:
-	      if (token->type == CPP_CLOSE_PAREN)
-		c_parser_error (parser, "expected identifier");
-	      else
 		{
+		  if (property_getter_ident != NULL_TREE)
+		    c_parser_error (parser, "the %<getter%> attribute may only be specified once");
+		  else
+		    property_getter_ident = c_parser_peek_token (parser)->value;
+		  c_parser_consume_token (parser);
+		}
+	      else /* RID_IVAR, this case will go away.  */
+		{
+		  if (property_ivar_ident != NULL_TREE)
+		    c_parser_error (parser, "the %<ivar%> attribute may only be specified once");
+		  else
+		    property_ivar_ident = c_parser_peek_token (parser)->value;
 		  c_parser_consume_token (parser);
-		  c_parser_error (parser, "unknown property attribute");
 		}
+	      break;
+	    default:
+	      c_parser_error (parser, "unknown property attribute");
 	      syntax_error = true;
 	      break;
 	    }
@@ -7741,7 +7759,13 @@  c_parser_objc_at_property_declaration (c
       properties = nreverse (properties);
       
       for (; properties; properties = TREE_CHAIN (properties))
-	objc_add_property_declaration (loc, copy_node (properties));
+	objc_add_property_declaration (loc, copy_node (properties),
+				       property_readonly, property_readwrite,
+				       property_assign, property_retain,
+				       property_copy, property_nonatomic,
+				       property_getter_ident, property_setter_ident,
+				       /* The following two will be removed.  */
+				       property_copies, property_ivar_ident);
     }
 
   c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
diff -rupN --exclude=.svn trunk3/gcc/objc/ChangeLog trunk4/gcc/objc/ChangeLog
--- trunk3/gcc/objc/ChangeLog	2010-10-25 20:22:40.000000000 +0100
+++ trunk4/gcc/objc/ChangeLog	2010-10-26 11:35:07.000000000 +0100
@@ -1,5 +1,22 @@ 
 2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* objc-act.c (objc_add_property_declaration): Added arguments to
+	pass the various property attributes that were parsed with the
+	property declaration.  Process arguments to determine the final
+	property attributes and produce error messages as appropriate.
+	Added temporary code to keep the compiler silent about variables
+	set but not used - for new attributes that are only checked but
+	have no effect yet.
+	(property_readonly): Removed.
+	(property_setter): Removed.
+	(property_getter): Removed.
+	(property_ivar): Removed.
+	(property_copies): Removed.	
+	(objc_set_property_attr): Removed.
+	* objc-act.h (enum property_assign_semantics): New.
+	
+2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* objc-act.c (objc_add_property_variable): Renamed to
 	objc_add_property_declaration.  Added location argument.  Updated
 	warnings and errors to use it.  Use error, not fatal_error, if a
diff -rupN --exclude=.svn trunk3/gcc/objc/objc-act.c trunk4/gcc/objc/objc-act.c
--- trunk3/gcc/objc/objc-act.c	2010-10-25 04:04:11.000000000 +0100
+++ trunk4/gcc/objc/objc-act.c	2010-10-26 10:38:50.000000000 +0100
@@ -406,11 +406,6 @@  static int method_slot = 0;
    required.  */
 static bool objc_method_optional_flag = false;
 
-static bool property_readonly;
-static tree property_getter;
-static tree property_setter;
-static tree property_ivar;
-static bool property_copies;
 static bool in_objc_property_setter_name_context = false;
 
 static int objc_collecting_ivars = 0;
@@ -815,68 +810,93 @@  objc_set_method_opt (bool optional)
     }
 }
 
-/* This routine gathers property attribute information from the attribute
-   portion of a property declaration. */
-
+/* This routine is called by the parser when a
+   @property... declaration is found.  'decl' is the declaration of
+   the property (type/identifier), and the other arguments represent
+   property attributes that may have been specified in the Objective-C
+   declaration.  'parsed_property_readonly' is 'true' if the attribute
+   'readonly' was specified, and 'false' if not; similarly for the
+   other bool parameters.  'parsed_property_getter_ident' is NULL_TREE
+   if the attribute 'getter' was not specified, and is the identifier
+   corresponding to the specified getter if it was; similarly for
+   'parsed_property_setter_ident'.  */
 void
-objc_set_property_attr (location_t loc, objc_property_attribute_kind attr,
-			tree ident)
+objc_add_property_declaration (location_t location, tree decl,
+			       bool parsed_property_readonly, bool parsed_property_readwrite,
+			       bool parsed_property_assign, bool parsed_property_retain,
+			       bool parsed_property_copy, bool parsed_property_nonatomic,
+			       tree parsed_property_getter_ident, tree parsed_property_setter_ident,
+			       /* The following two will be removed.  */
+			       bool parsed_property_copies, tree parsed_property_ivar_ident)
 {
-  static char string[BUFSIZE];
-  switch (attr)
+  tree property_decl;
+  tree x;
+  tree interface = NULL_TREE;
+  /* 'property_readonly' is the final readonly/rewrite attribute of
+     the property declaration after all things have been
+     considered.  */
+  bool property_readonly = false;
+  enum objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN;
+  /* The following will be removed once @synthesize is implemented.  */
+  bool property_copies = false;
+
+  if (parsed_property_readonly && parsed_property_readwrite)
     {
-    case OBJC_PATTR_INIT: /* init */
-	property_readonly = property_copies = false;
-	property_setter = property_getter = property_ivar = NULL_TREE;
-	break;
-    case OBJC_PATTR_READONLY: /* readonly */
+      error_at (location, "%<readonly%> attribute conflicts with %<readwrite%> attribute");
+      /* In case of conflicting attributes (here and below), after
+	 producing an error, we pick one of the attributes and keep
+	 going.  */
+      property_readonly = false;
+    }
+  else
+    {
+      if (parsed_property_readonly)
 	property_readonly = true;
-	break;
-    case OBJC_PATTR_GETTER: /* getter = ident */
-	if (property_getter != NULL_TREE)
-	  error_at (loc, "the %<getter%> attribute may only be specified once");
-        property_getter = ident;
-	break;
-    case OBJC_PATTR_SETTER: /* setter = ident */
-	if (property_setter != NULL_TREE)
-	  error_at (loc, "the %<setter%> attribute may only be specified once");
-	/* setters always have a trailing ':' in their name. In fact, this is the
-	   only syntax that parser recognizes for a setter name. Must add a trailing
-	   ':' here so name matches that of the declaration of user instance method
-	   for the setter. */
-	sprintf (string, "%s:", IDENTIFIER_POINTER (ident));
-	property_setter = get_identifier (string);;
-	break;
-    case OBJC_PATTR_IVAR: /* ivar = ident */
-	if (property_ivar != NULL_TREE)
-	  error_at (loc, "the %<ivar%> attribute may only be specified once");
-	else if (objc_interface_context) 
-	  {
-	    warning_at (loc, 0, "the %<ivar%> attribute is ignored in an @interface");
-	    property_ivar = NULL_TREE;
-	  }
-	else
-	  property_ivar = ident;
-	break;
-    case OBJC_PATTR_COPIES: /* copies */
-	property_copies = true;
-	break;
-    default:
-	break;
+  
+      if (parsed_property_readwrite)
+	property_readonly = false;
     }
-}
 
-/* This routine builds a 'property_decl' tree node and adds it to the list
-   of such properties in the current class. It also checks for duplicates.
-*/
+  if (parsed_property_readonly && parsed_property_setter_ident)
+    {
+      /* Maybe this should be an error ? */
+      warning_at (location, 0, "%<readonly%> attribute conflicts with %<setter%> attribute");
+      parsed_property_readonly = false;
+    }
 
-void
-objc_add_property_declaration (location_t location, tree decl)
-{
-  tree property_decl;
-  tree x;
-  tree interface = NULL_TREE;
+  if (parsed_property_assign && parsed_property_retain)
+    {
+      error_at (location, "%<assign%> attribute conflicts with %<retain%> attribute");
+      property_assign_semantics = OBJC_PROPERTY_RETAIN;
+    }
+  else if (parsed_property_assign && parsed_property_copy)
+    {
+      error_at (location, "%<assign%> attribute conflicts with %<copy%> attribute");
+      property_assign_semantics = OBJC_PROPERTY_COPY;
+    }
+  else if (parsed_property_retain && parsed_property_copy)
+    {
+      error_at (location, "%<retain%> attribute conflicts with %<copy%> attribute");
+      property_assign_semantics = OBJC_PROPERTY_COPY;
+    }
+  else
+    {
+      if (parsed_property_assign)
+	property_assign_semantics = OBJC_PROPERTY_ASSIGN;
+
+      if (parsed_property_retain)
+	property_assign_semantics = OBJC_PROPERTY_RETAIN;
+
+      if (parsed_property_copy)
+	property_assign_semantics = OBJC_PROPERTY_COPY;
+    }
+
+  /* This will be removed when @synthesize is implemented.  */
+  if (parsed_property_copies)
+    property_copies = true;
 
+  /* This case will be removed when @synthesize is implemented; then
+     @property will only be allowed in an @interface context.  */
   if (objc_implementation_context)
     {
       interface = lookup_interface (CLASS_NAME (objc_implementation_context));
@@ -896,19 +916,41 @@  objc_add_property_declaration (location_
 	    }
         }
     }
+  else if (objc_interface_context) 
+    {
+      /* This will be removed when ivar is removed.  */
+      if (parsed_property_ivar_ident)
+	{
+	  warning_at (location, 0, "the %<ivar%> attribute is ignored in an @interface");
+	  parsed_property_ivar_ident = NULL_TREE;
+	}
+    }
   else if (!objc_interface_context)
     {
       error_at (location, "property declaration not in @interface or @implementation context");
       return;
     }
 
+  if (parsed_property_setter_ident)
+    {
+      /* The setter should be terminated by ':', but the parser only
+	 passes us an identifier without ':'.  So, we need to add ':'
+	 at the end.  */
+      const char *parsed_setter = IDENTIFIER_POINTER (parsed_property_setter_ident);
+      size_t length = strlen (parsed_setter);
+      char *final_setter = (char *)alloca (length + 2);
+
+      sprintf (final_setter, "%s:", parsed_setter);
+      parsed_property_setter_ident = get_identifier (final_setter);
+    }
+
   property_decl = make_node (PROPERTY_DECL);
   TREE_TYPE (property_decl) = TREE_TYPE (decl);
 
   PROPERTY_NAME (property_decl) = DECL_NAME (decl);
-  PROPERTY_GETTER_NAME (property_decl) = property_getter;
-  PROPERTY_SETTER_NAME (property_decl) = property_setter;
-  PROPERTY_IVAR_NAME (property_decl) = property_ivar;
+  PROPERTY_GETTER_NAME (property_decl) = parsed_property_getter_ident;
+  PROPERTY_SETTER_NAME (property_decl) = parsed_property_setter_ident;
+  PROPERTY_IVAR_NAME (property_decl) = parsed_property_ivar_ident;
   PROPERTY_READONLY (property_decl) = property_readonly 
 					? boolean_true_node 
 					: boolean_false_node;
@@ -916,6 +958,20 @@  objc_add_property_declaration (location_
 					? boolean_true_node 
 					: boolean_false_node;
 
+  /* TODO: The following is temporary code that will be removed when
+     property_assign_semantics and property_nonatomic are
+     implemented.  */
+  if (objc_implementation_context && objc_interface_context)
+    {
+      /* This branch is impossible but the compiler can't know it.  Do
+	 something with property_assign_semantics and
+	 parsed_property_nonatomic (not implemented yet) to convince
+	 the compiler we're using them and prevent it from generating
+	 warnings and breaking bootstrap.  */
+      PROPERTY_COPIES (property_decl) = property_assign_semantics ? boolean_true_node : boolean_false_node;
+      PROPERTY_READONLY (property_decl) = parsed_property_nonatomic ? boolean_true_node : boolean_false_node;
+    }
+
   if (objc_interface_context)
     {
       /* Doing the property in interface declaration. */
@@ -938,6 +994,8 @@  objc_add_property_declaration (location_
     }
   else
     {
+      /* This case will go away once @syhtensize is implemented.  */
+
       /* Doing the property in implementation context. */
       /* If property is not declared in the interface issue error. */
       for (x = CLASS_PROPERTY_DECL (interface); x; x = TREE_CHAIN (x))
@@ -964,7 +1022,8 @@  objc_add_property_declaration (location_
       if (PROPERTY_READONLY (property_decl) == boolean_true_node &&
 	  PROPERTY_SETTER_NAME (property_decl))
 	{
-	  warning_at (location, 0, "a %<readonly%> property cannot have a setter (ignored)");
+	  /* This error is already reported up there.  */
+	  /* warning_at (location, 0, "a %<readonly%> property cannot have a setter (ignored)"); */
 	  PROPERTY_SETTER_NAME (property_decl) = NULL_TREE;
 	}
       /* Add the property to the list of properties for current implementation. */
@@ -1039,7 +1098,7 @@  lookup_property (tree interface_type, tr
   return inter;
 }
 
-/* This routine recognizes a dot-notation for a propery reference and generates a call to
+/* This routine recognizes a dot-notation for a property reference and generates a call to
    the getter function for this property. In all other cases, it returns a NULL_TREE.
 */
 
diff -rupN --exclude=.svn trunk3/gcc/objc/objc-act.h trunk4/gcc/objc/objc-act.h
--- trunk3/gcc/objc/objc-act.h	2010-10-20 19:04:55.000000000 +0100
+++ trunk4/gcc/objc/objc-act.h	2010-10-25 21:54:17.000000000 +0100
@@ -61,6 +61,12 @@  tree objc_eh_personality (void);
 #define PROPERTY_READONLY(DECL) ((DECL)->decl_minimal.context)
 #define PROPERTY_COPIES(DECL) ((DECL)->decl_common.size_unit)
 
+enum objc_property_assign_semantics {
+  OBJC_PROPERTY_ASSIGN = 1,
+  OBJC_PROPERTY_RETAIN = 2,
+  OBJC_PROPERTY_COPY = 3
+};
+
 /* CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
    CATEGORY_INTERFACE_TYPE, CATEGORY_IMPLEMENTATION_TYPE,
    PROTOCOL_INTERFACE_TYPE */
diff -rupN --exclude=.svn trunk3/gcc/testsuite/ChangeLog trunk4/gcc/testsuite/ChangeLog
--- trunk3/gcc/testsuite/ChangeLog	2010-10-26 10:49:50.000000000 +0100
+++ trunk4/gcc/testsuite/ChangeLog	2010-10-26 11:35:21.000000000 +0100
@@ -1,5 +1,14 @@ 
 2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* obj-c.dg/property/at-property-4.m: New.
+	* obj-c++.dg/property/at-property-4.mm: New.
+	* obj-c++.dg/property/property-neg-5.m: Updated testcase for
+	updates in warning.
+	* obj-c++.dg/property/property-neg-5.mm: Updated testcase for
+	updates in warning.
+	
+2010-10-25  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* objc.dg/property/at-property-1.m: New.	
 	* objc.dg/property/at-property-2.m: New.
 	* objc.dg/property/at-property-3.m: New.
diff -rupN --exclude=.svn trunk3/gcc/testsuite/obj-c++.dg/property/at-property-4.mm trunk4/gcc/testsuite/obj-c++.dg/property/at-property-4.mm
--- trunk3/gcc/testsuite/obj-c++.dg/property/at-property-4.mm	1970-01-01 01:00:00.000000000 +0100
+++ trunk4/gcc/testsuite/obj-c++.dg/property/at-property-4.mm	2010-10-26 10:32:35.000000000 +0100
@@ -0,0 +1,41 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+- (id) myGetter;
+- (id) myGetterB;
+- (void) mySetter: (id)property;
+- (void) mySetterB: (id)property;
+
+/* Test that all the new property attributes can be parsed.  */
+@property (assign)    id property_a;
+@property (copy)      id property_b;
+@property (nonatomic) id property_c;
+@property (readonly)  id property_d;
+@property (readwrite) id property_e;
+@property (retain)    id property_f;
+@property (release)   id property_g;      /* { dg-error "unknown property attribute" } */
+
+/* The following will be enabled when @synthesized is implemented.  */
+/* @property (getter=myGetter)   id property_h; */
+/* @property (setter=mySetter:)  id property_i; */
+
+/* Now test various problems.  */
+
+@property (readonly, readwrite) int a;    /* { dg-error ".readonly. attribute conflicts with .readwrite. attribute" } */
+/* The following will be enabled when @synthesized is implemented.  */
+/* @property (readonly, setter=setA:) int b; */ /* dg-warning ".readonly. attribute conflicts with .setter. attribute" */
+
+@property (assign, retain) id c;          /* { dg-error ".assign. attribute conflicts with .retain. attribute" } */
+@property (assign, copy) id d;            /* { dg-error ".assign. attribute conflicts with .copy. attribute" } */
+@property (copy, retain) id e;            /* { dg-error ".retain. attribute conflicts with .copy. attribute" } */
+
+/* The following will be enabled when @synthesized is implemented.  */
+/* @property (setter=mySetter:,setter=mySetterB:)  id f; */ /* dg-error ".setter. attribute may only be specified once" */
+/* @property (getter=myGetter:,getter=myGetterB:)  id f; */ /* dg-error ".getter. attribute may only be specified once" */
+
+@end
diff -rupN --exclude=.svn trunk3/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm trunk4/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm
--- trunk3/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm	2010-10-15 10:16:40.000000000 +0100
+++ trunk4/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm	2010-10-26 09:31:04.000000000 +0100
@@ -2,6 +2,6 @@ 
 /* { dg-do compile } */
 
 @interface Foo
-@property ( readonly, getter = HELLO, setter = THERE : ) int value;
+@property ( readonly, getter = HELLO, setter = THERE : ) int value; /* { dg-warning ".readonly. attribute conflicts with .setter. attribute" } */
 @end	/* { dg-warning "getter = \\'HELLO\\' may not be specified in an interface" } */ 
 	/* { dg-warning "setter = \\'THERE\\:\\' may not be specified in an interface" "" { target *-*-* } 6 } */
diff -rupN --exclude=.svn trunk3/gcc/testsuite/objc.dg/property/at-property-4.m trunk4/gcc/testsuite/objc.dg/property/at-property-4.m
--- trunk3/gcc/testsuite/objc.dg/property/at-property-4.m	1970-01-01 01:00:00.000000000 +0100
+++ trunk4/gcc/testsuite/objc.dg/property/at-property-4.m	2010-10-26 10:32:24.000000000 +0100
@@ -0,0 +1,41 @@ 
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+- (id) myGetter;
+- (id) myGetterB;
+- (void) mySetter: (id)property;
+- (void) mySetterB: (id)property;
+
+/* Test that all the new property attributes can be parsed.  */
+@property (assign)    id property_a;
+@property (copy)      id property_b;
+@property (nonatomic) id property_c;
+@property (readonly)  id property_d;
+@property (readwrite) id property_e;
+@property (retain)    id property_f;
+@property (release)   id property_g;      /* { dg-error "unknown property attribute" } */
+
+/* The following will be enabled when @synthesized is implemented.  */
+/* @property (getter=myGetter)   id property_h; */
+/* @property (setter=mySetter:)  id property_i; */
+
+/* Now test various problems.  */
+
+@property (readonly, readwrite) int a;    /* { dg-error ".readonly. attribute conflicts with .readwrite. attribute" } */
+/* The following will be enabled when @synthesized is implemented.  */
+/* @property (readonly, setter=setA:) int b; */ /* dg-warning ".readonly. attribute conflicts with .setter. attribute" */
+
+@property (assign, retain) id c;          /* { dg-error ".assign. attribute conflicts with .retain. attribute" } */
+@property (assign, copy) id d;            /* { dg-error ".assign. attribute conflicts with .copy. attribute" } */
+@property (copy, retain) id e;            /* { dg-error ".retain. attribute conflicts with .copy. attribute" } */
+
+/* The following will be enabled when @synthesized is implemented.  */
+/* @property (setter=mySetter:,setter=mySetterB:)  id f; */ /* dg-error ".setter. attribute may only be specified once" */
+/* @property (getter=myGetter:,getter=myGetterB:)  id f; */ /* dg-error ".getter. attribute may only be specified once" */
+
+@end
diff -rupN --exclude=.svn trunk3/gcc/testsuite/objc.dg/property/property-neg-5.m trunk4/gcc/testsuite/objc.dg/property/property-neg-5.m
--- trunk3/gcc/testsuite/objc.dg/property/property-neg-5.m	2010-10-25 01:38:02.000000000 +0100
+++ trunk4/gcc/testsuite/objc.dg/property/property-neg-5.m	2010-10-26 09:31:01.000000000 +0100
@@ -2,6 +2,6 @@ 
 /* { dg-do compile } */
 
 @interface Foo
-@property ( readonly, getter = HELLO, setter = THERE : ) int value;
+@property ( readonly, getter = HELLO, setter = THERE : ) int value; /* { dg-warning ".readonly. attribute conflicts with .setter. attribute" } */
 @end	/* { dg-warning "getter = \\'HELLO\\' may not be specified in an interface" } */ 
 	/* { dg-warning "setter = \\'THERE\\:\\' may not be specified in an interface" "" { target *-*-* } 6 } */