diff mbox

[ObjC*,committed,1/2] @property

Message ID A5C4B796-E246-49C8-9496-903AEC014072@sandoe-acoustics.co.uk
State New
Headers show

Commit Message

Iain Sandoe Oct. 14, 2010, 8:17 p.m. UTC
Hi,
Another chunk from the ObjC part of FSF apple 'trunk' branch.

This implements:

@property - with attributes from the set " readonly, copies, getter=,  
setter= and ivar="  i.e. property "V1".

As discussed with Mike off list, rather than merge a buggy first  
implementation followed by fixes - this applies all the related  
property radars : 4436866, 4505126, 4506903, 4517826

I took the liberty of replacing some magic numbers with an enum ...
... oh, and I made it work on fgnu-runtime too ;)

r165479 (test-suite changes are in part2)

cheers,
Iain

add @property to ObjC*

	merge from FSF apple 'trunk' branch.
	2006 Fariborz Jahanian <fjahanian@apple.com>
	
gcc/c-family:

	* c-common.c (c_common_resword): Define @property and its attributes.
	* c-common.h: Define property attribute enum entries.
	(OBJC_IS_PATTR_KEYWORD): New.
	(objc_property_attribute_kind): New enum.
	Declare objc_set_property_attr (), objc_add_property_variable (),
	objc_build_getter_call () and objc_build_setter_call ().
	* stub-objc.c (objc_set_property_attr): New stub.
	(objc_add_property_variable): Likewise.
	(objc_build_getter_call): Likewise.
	(objc_build_setter_call) Likewise.

gcc:

	* c-parser.c (c_parser, objc_property_attr_context) New flag.
	(c_lex_one_token): Handle property attributes.
	(c_parser_external_declaration): Handle @property.
	(c_parser_declaration_or_fndef): Warn on invalid attributes before
	@alias, @class, @end and @property objc keywords.
	(c_parser_objc_methodprotolist): Handle @property.
	(c_parser_objc_property_attrlist): New.
	(c_parser_objc_at_property): New.
	* c-typeck.c (build_component_ref): Handle CLASS.property syntax.
	(build_modify_expr): Likewise.

gcc/cp:

	* typeck.c (finish_class_member_access_expr): Handle CLASS.property
	syntax.
	(cp_build_modify_expr): Likewise.
	* parser.c (cp_parser_objc_method_prototype_list): Handle @property.
	(cp_parser_objc_method_definition_list): Likewise.
	(cp_parser_objc_property_decl): New.
	(cp_parser_objc_property_attrlist): New.
	(cp_parser_objc_at_property): New.

gcc/objc:

	* objc-act.c (CALL_EXPR_OBJC_PROPERTY_GETTER): New.
	property_readonly, property_getter, property_setter, property_ivar,
	property_copies, in_objc_property_setter_name_context: New vars.
	(objc_set_property_attr): New.
	(objc_add_property_variable): New.
	(lookup_property_in_list): New.
	(lookup_property): New.
	(objc_build_getter_call): New.
	(objc_setter_func_call): New.
	(get_selector_from_reference): New.
	(objc_build_setter_call): New.
	(is_property): New.
	(build_property_reference): New.
	(objc_finish_message_expr): Detect readonly property and warn.
	(objc_build_property_ivar_name): New.
	(objc_build_property_setter_name): New.
	(objc_gen_one_property_datum): New.
	(objc_process_getter_setter): New.
	(objc_synthesize_getter): New.
	(objc_synthesize_setter): New.
	(objc_gen_property_data): New.
	(finish_class): Generate property data.
	(comp_proto_with_proto): Separated from ...
	(match_proto_with_proto): ... New.
	(objc_lookup_ivar): Handle properties.
	* objc-tree.def (PROPERTY_DECL): New tree code.
	* objc-act.h: CLASS_LANG_SLOT_ELTS, PROTOCOL_LANG_SLOT_ELTS update  
size.
	(METHOD_PROPERTY_CONTEXT): New.
	(PROPERTY_NAME): New.
	(PROPERTY_GETTER_NAME): New.
	(PROPERTY_SETTER_NAME): New.
	(PROPERTY_IVAR_NAME): New.
	(PROPERTY_READONLY): New.
	(PROPERTY_COPIES): New.
	(TOTAL_CLASS_RAW_IVARS): New.
	(CLASS_PROPERTY_DECL): New.
	(IMPL_PROPERTY_DECL): New.
	* objc-lang.c (objc_init_ts): Update fields for property_decl.

gcc/objcp:

	* objcp-lang.c (objcxx_init_ts): Update for property_decl.

Comments

Nicola Pero Oct. 15, 2010, 10:41 a.m. UTC | #1
This is brilliant.  I can't wait to try it out tonight :-)

Thanks

-----Original Message-----
From: "IainS" <developer@sandoe-acoustics.co.uk>
Sent: Thursday, 14 October, 2010 22:17
To: "GCC Patches" <gcc-patches@gcc.gnu.org>
Cc: "Mike Stump" <mrs@gcc.gnu.org>, "Nicola Pero" <nicola.pero@meta-innovation.com>
Subject: [Patch ObjC* committed 1/2] @property

Hi,
Another chunk from the ObjC part of FSF apple 'trunk' branch.

This implements:

@property - with attributes from the set " readonly, copies, getter=,  
setter= and ivar="  i.e. property "V1".

As discussed with Mike off list, rather than merge a buggy first  
implementation followed by fixes - this applies all the related  
property radars : 4436866, 4505126, 4506903, 4517826

I took the liberty of replacing some magic numbers with an enum ...
... oh, and I made it work on fgnu-runtime too ;)

r165479 (test-suite changes are in part2)

cheers,
Iain

add @property to ObjC*

	merge from FSF apple 'trunk' branch.
	2006 Fariborz Jahanian <fjahanian@apple.com>
	
gcc/c-family:

	* c-common.c (c_common_resword): Define @property and its attributes.
	* c-common.h: Define property attribute enum entries.
	(OBJC_IS_PATTR_KEYWORD): New.
	(objc_property_attribute_kind): New enum.
	Declare objc_set_property_attr (), objc_add_property_variable (),
	objc_build_getter_call () and objc_build_setter_call ().
	* stub-objc.c (objc_set_property_attr): New stub.
	(objc_add_property_variable): Likewise.
	(objc_build_getter_call): Likewise.
	(objc_build_setter_call) Likewise.

gcc:

	* c-parser.c (c_parser, objc_property_attr_context) New flag.
	(c_lex_one_token): Handle property attributes.
	(c_parser_external_declaration): Handle @property.
	(c_parser_declaration_or_fndef): Warn on invalid attributes before
	@alias, @class, @end and @property objc keywords.
	(c_parser_objc_methodprotolist): Handle @property.
	(c_parser_objc_property_attrlist): New.
	(c_parser_objc_at_property): New.
	* c-typeck.c (build_component_ref): Handle CLASS.property syntax.
	(build_modify_expr): Likewise.

gcc/cp:

	* typeck.c (finish_class_member_access_expr): Handle CLASS.property
	syntax.
	(cp_build_modify_expr): Likewise.
	* parser.c (cp_parser_objc_method_prototype_list): Handle @property.
	(cp_parser_objc_method_definition_list): Likewise.
	(cp_parser_objc_property_decl): New.
	(cp_parser_objc_property_attrlist): New.
	(cp_parser_objc_at_property): New.

gcc/objc:

	* objc-act.c (CALL_EXPR_OBJC_PROPERTY_GETTER): New.
	property_readonly, property_getter, property_setter, property_ivar,
	property_copies, in_objc_property_setter_name_context: New vars.
	(objc_set_property_attr): New.
	(objc_add_property_variable): New.
	(lookup_property_in_list): New.
	(lookup_property): New.
	(objc_build_getter_call): New.
	(objc_setter_func_call): New.
	(get_selector_from_reference): New.
	(objc_build_setter_call): New.
	(is_property): New.
	(build_property_reference): New.
	(objc_finish_message_expr): Detect readonly property and warn.
	(objc_build_property_ivar_name): New.
	(objc_build_property_setter_name): New.
	(objc_gen_one_property_datum): New.
	(objc_process_getter_setter): New.
	(objc_synthesize_getter): New.
	(objc_synthesize_setter): New.
	(objc_gen_property_data): New.
	(finish_class): Generate property data.
	(comp_proto_with_proto): Separated from ...
	(match_proto_with_proto): ... New.
	(objc_lookup_ivar): Handle properties.
	* objc-tree.def (PROPERTY_DECL): New tree code.
	* objc-act.h: CLASS_LANG_SLOT_ELTS, PROTOCOL_LANG_SLOT_ELTS update  
size.
	(METHOD_PROPERTY_CONTEXT): New.
	(PROPERTY_NAME): New.
	(PROPERTY_GETTER_NAME): New.
	(PROPERTY_SETTER_NAME): New.
	(PROPERTY_IVAR_NAME): New.
	(PROPERTY_READONLY): New.
	(PROPERTY_COPIES): New.
	(TOTAL_CLASS_RAW_IVARS): New.
	(CLASS_PROPERTY_DECL): New.
	(IMPL_PROPERTY_DECL): New.
	* objc-lang.c (objc_init_ts): Update fields for property_decl.

gcc/objcp:

	* objcp-lang.c (objcxx_init_ts): Update for property_decl.
diff mbox

Patch

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 165478)
+++ gcc/c-family/c-common.c	(working copy)
@@ -543,6 +543,7 @@  const struct c_common_resword c_common_reswords[]
   { "synchronized",	RID_AT_SYNCHRONIZED,	D_OBJC },
   { "optional",		RID_AT_OPTIONAL,	D_OBJC },
   { "required",		RID_AT_REQUIRED,	D_OBJC },
+  { "property",		RID_AT_PROPERTY,	D_OBJC },
   /* These are recognized only in protocol-qualifier context
      (see above) */
   { "bycopy",		RID_BYCOPY,		D_OBJC },
@@ -551,6 +552,12 @@  const struct c_common_resword c_common_reswords[]
   { "inout",		RID_INOUT,		D_OBJC },
   { "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 },
+  { "getter",		RID_GETTER,		D_OBJC }, 
+  { "setter",		RID_SETTER,		D_OBJC }, 
+  { "ivar",		RID_IVAR,		D_OBJC }, 
 };
 
 const unsigned int num_c_common_reswords =
Index: gcc/c-family/stub-objc.c
===================================================================
--- gcc/c-family/stub-objc.c	(revision 165478)
+++ gcc/c-family/stub-objc.c	(working copy)
@@ -314,7 +314,31 @@  objc_get_class_ivars (tree ARG_UNUSED (name))
   return 0;
 }
 
+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_variable (tree ARG_UNUSED (prop))
+{
+}
+
 tree
+objc_build_getter_call (tree ARG_UNUSED (datum), tree ARG_UNUSED (component))
+{
+  return 0;
+}
+
+tree
+objc_build_setter_call (tree ARG_UNUSED (lhs), tree ARG_UNUSED (rhs))
+{
+  return 0;
+}
+
+tree
 objc_build_throw_stmt (location_t ARG_UNUSED (loc), tree ARG_UNUSED (expr))
 {
   return 0;
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 165478)
+++ gcc/c-family/c-common.h	(working copy)
@@ -80,6 +80,10 @@  enum rid
      are keywords only in specific contexts)  */
   RID_IN, RID_OUT, RID_INOUT, RID_BYCOPY, RID_BYREF, RID_ONEWAY,
 
+  /* 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,
+
   /* C (reserved and imaginary types not implemented, so any use is a
      syntax error) */
   RID_IMAGINARY,
@@ -143,7 +147,7 @@  enum rid
   RID_AT_PROTOCOL, RID_AT_SELECTOR,
   RID_AT_THROW,	   RID_AT_TRY,       RID_AT_CATCH,
   RID_AT_FINALLY,  RID_AT_SYNCHRONIZED, 
-  RID_AT_OPTIONAL, RID_AT_REQUIRED,
+  RID_AT_OPTIONAL, RID_AT_REQUIRED, RID_AT_PROPERTY,
   RID_AT_INTERFACE,
   RID_AT_IMPLEMENTATION,
 
@@ -181,7 +185,9 @@  enum rid
   RID_FIRST_AT = RID_AT_ENCODE,
   RID_LAST_AT = RID_AT_IMPLEMENTATION,
   RID_FIRST_PQ = RID_IN,
-  RID_LAST_PQ = RID_ONEWAY
+  RID_LAST_PQ = RID_ONEWAY,
+  RID_FIRST_PATTR = RID_READONLY,
+  RID_LAST_PATTR = RID_IVAR
 };
 
 #define OBJC_IS_AT_KEYWORD(rid) \
@@ -192,6 +198,10 @@  enum rid
   ((unsigned int) (rid) >= (unsigned int) RID_FIRST_PQ && \
    (unsigned int) (rid) <= (unsigned int) RID_LAST_PQ)
 
+#define OBJC_IS_PATTR_KEYWORD(rid) \
+  ((unsigned int) (rid) >= (unsigned int) RID_FIRST_PATTR && \
+   (unsigned int) (rid) <= (unsigned int) RID_LAST_PATTR)
+
 /* OBJC_IS_CXX_KEYWORD recognizes the 'CXX_OBJC' keywords (such as
    'class') which are shared in a subtle way between Objective-C and
    C++.  When the lexer is lexing in Objective-C/Objective-C++, if it
@@ -420,6 +430,16 @@  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;
+
 /* The various name of operator that appears in error messages. */
 typedef enum ref_operator {
   /* NULL */
@@ -1009,7 +1029,12 @@  extern tree objc_generate_static_init_call (tree);
 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_variable (tree);
+extern tree objc_build_getter_call (tree, tree);
+extern tree objc_build_setter_call (tree, tree);
 
 /* The following are provided by the C and C++ front-ends, and called by
    ObjC/ObjC++.  */
Index: gcc/objc/objc-act.c
===================================================================
--- gcc/objc/objc-act.c	(revision 165478)
+++ gcc/objc/objc-act.c	(working copy)
@@ -163,6 +163,27 @@  static void build_next_objc_exception_stuff (void)
 static bool objc_derived_from_p (tree, tree);
 #define DERIVED_FROM_P(PARENT, CHILD) objc_derived_from_p (PARENT, CHILD)
 #endif
+
+/* Property.  */
+static void objc_gen_one_property_datum (tree, tree, tree, bool*);
+static void objc_gen_property_data (tree, tree);
+static void objc_synthesize_getter (tree, tree, tree);
+static void objc_process_getter_setter (tree, tree, bool);
+static void objc_synthesize_setter (tree, tree, tree);
+static char *objc_build_property_ivar_name (tree);
+static char *objc_build_property_setter_name (tree, bool);
+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 tree objc_setter_func_call (tree, tree, tree);
+static tree build_property_reference (tree, tree);
+static tree is_property (tree, tree);
+/* Set on a CALL_EXPR if it is for call to a getter function represented by an
+   objective-c property declaration. */
+#define CALL_EXPR_OBJC_PROPERTY_GETTER(NODE) \
+  (CALL_EXPR_CHECK(NODE)->base.deprecated_flag)
+
 static void objc_xref_basetypes (tree, tree);
 
 static void build_class_template (void);
@@ -194,6 +215,10 @@  static hash hash_lookup (hash *, tree);
 static tree lookup_method (tree, tree);
 static tree lookup_method_static (tree, tree, int);
 
+static tree add_class (tree, tree);
+static void add_category (tree, tree);
+static inline tree lookup_category (tree, tree);
+
 enum string_section
 {
   class_names,		/* class, category, protocol, module names */
@@ -369,6 +394,13 @@  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;
 
 #define BUFSIZE		1024
@@ -807,7 +839,450 @@  objc_set_method_opt (bool optional)
     }
 }
 
+/* This routine gathers property attribute information from the attribute
+   portion of a property declaration. */
+
 void
+objc_set_property_attr (location_t loc, objc_property_attribute_kind attr,
+			tree ident)
+{
+  static char string[BUFSIZE];
+  switch (attr)
+    {
+    case OBJC_PATTR_INIT: /* init */
+	property_readonly = property_copies = false;
+	property_setter = property_getter = property_ivar = NULL_TREE;
+	break;
+    case OBJC_PATTR_READONLY: /* 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;
+    }
+}
+
+/* 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.
+*/
+
+void
+objc_add_property_variable (tree decl)
+{
+  tree property_decl;
+  tree x;
+  tree interface = NULL_TREE;
+
+  if (objc_implementation_context)
+    {
+      interface = lookup_interface (CLASS_NAME (objc_implementation_context));
+      if (!interface)
+	{
+	  error ("no class property can be implemented without an interface");
+	  return;
+	}
+      if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)
+        {
+	  interface = lookup_category (interface, 
+				     CLASS_SUPER_NAME (objc_implementation_context));	
+	  if (!interface)
+	    {
+	      error ("no category property can be implemented without an interface");
+	      return;
+	    }
+        }
+    }
+  else if (!objc_interface_context)
+    {
+      fatal_error ("property declaration not in @interface or @implementation context");
+      return;
+    }
+
+  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_READONLY (property_decl) = property_readonly 
+					? boolean_true_node 
+					: boolean_false_node;
+  PROPERTY_COPIES (property_decl) = property_copies 
+					? boolean_true_node 
+					: boolean_false_node;
+
+  if (objc_interface_context)
+    {
+      /* Doing the property in interface declaration. */
+
+      /* Issue error if property and an ivar name match. */
+      if (TREE_CODE (objc_interface_context) == CLASS_INTERFACE_TYPE
+	  && is_ivar (CLASS_IVARS (objc_interface_context), DECL_NAME (decl)))
+	error ("property %qD may not have the same name as an ivar in the class", decl);
+      /* must check for duplicate property declarations. */
+      for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
+	{
+	  if (PROPERTY_NAME (x) == DECL_NAME (decl))
+	    {
+	      error ("duplicate property declaration %qD", decl);
+	      return;
+	    }
+	}
+      TREE_CHAIN (property_decl) = CLASS_PROPERTY_DECL (objc_interface_context);
+      CLASS_PROPERTY_DECL (objc_interface_context) = property_decl;
+    }
+  else
+    {
+      /* 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))
+	if (PROPERTY_NAME (x) == DECL_NAME (decl))
+	  break;
+      if (!x)
+	{
+	  error ("no declaration of property %qD found in the interface", decl);
+	  return;
+	}
+      /* readonlys must also match. */
+      if (PROPERTY_READONLY (x) != PROPERTY_READONLY (property_decl))
+	{
+	  error ("property %qD %<readonly%> attribute conflicts with its" 
+		 " interface version", decl);
+	}
+      /* copies must also match. */
+      if (PROPERTY_COPIES (x) != PROPERTY_COPIES (property_decl))
+	{
+	  error ("property %qD %<copies%> attribute conflicts with its" 
+		 " interface version", decl);
+	}
+      /* Cannot have readonly and setter attribute for the same property. */
+      if (PROPERTY_READONLY (property_decl) == boolean_true_node &&
+	  PROPERTY_SETTER_NAME (property_decl))
+	{
+	  warning (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. */
+      TREE_CHAIN (property_decl) = IMPL_PROPERTY_DECL (objc_implementation_context);
+      IMPL_PROPERTY_DECL (objc_implementation_context) = property_decl;
+    }
+}
+
+/* This routine looks for a given PROPERTY in a list of CLASS, CATEGORY, or
+   PROTOCOL.
+*/
+static tree
+lookup_property_in_list (tree chain, tree property)
+{
+  tree x;
+  for (x = CLASS_PROPERTY_DECL (chain); x; x = TREE_CHAIN (x))
+    if (PROPERTY_NAME (x) == property)
+      return x;
+  return NULL_TREE;
+}
+
+/* This routine looks for a given PROPERTY in the tree chain of RPROTO_LIST. */
+
+static tree lookup_property_in_protocol_list (tree rproto_list, tree property)
+{
+  tree rproto, x;
+  for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
+    {
+      tree p = TREE_VALUE (rproto);
+      if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
+	{
+	  if ((x = lookup_property_in_list (p, property)))
+	    return x;
+	  if (PROTOCOL_LIST (p))
+	    return lookup_property_in_protocol_list (PROTOCOL_LIST (p), property);
+	}
+      else
+	{
+	  ; /* An identifier...if we could not find a protocol.  */
+	}
+    }
+  return NULL_TREE;
+}
+
+/* This routine looks up the PROPERTY in current INTERFACE, its categories and up the
+   chain of interface hierarchy.
+*/
+static tree
+lookup_property (tree interface_type, tree property)
+{
+  tree inter = interface_type;
+  while (inter)
+    {
+      tree x, category;
+      if ((x = lookup_property_in_list (inter, property)))
+	return x;
+      /* Failing that, look for the property in each category of the class.  */
+      category = inter;
+      while ((category = CLASS_CATEGORY_LIST (category)))
+	if ((x = lookup_property_in_list (category, property)))
+	  return x;
+
+      /*  Failing to find in categories, look for property in protocol list. */
+      if (CLASS_PROTOCOL_LIST (inter) 
+	  && (x = lookup_property_in_protocol_list (
+		    CLASS_PROTOCOL_LIST (inter), property)))
+	return x;
+      
+      /* Failing that, climb up the inheritance hierarchy.  */
+      inter = lookup_interface (CLASS_SUPER_NAME (inter));
+    }
+  return inter;
+}
+
+/* This routine recognizes a dot-notation for a propery reference and generates a call to
+   the getter function for this property. In all other cases, it returns a NULL_TREE.
+*/
+
+tree
+objc_build_getter_call (tree receiver, tree component)
+{
+  tree x = NULL_TREE;
+  tree rtype;
+
+  if (receiver == NULL_TREE 
+      || receiver == error_mark_node 
+      || (rtype = TREE_TYPE (receiver)) == NULL_TREE)
+    return NULL_TREE;
+
+  if (component == NULL_TREE
+      || component == error_mark_node
+      || TREE_CODE (component) != IDENTIFIER_NODE)
+    return NULL_TREE;
+
+  if (objc_is_id (rtype))
+    {
+      tree rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype))
+		      ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype))
+		      : NULL_TREE);
+      if (rprotos)
+	x = lookup_property_in_protocol_list (rprotos, component);
+    }
+  else
+    {
+      tree basetype = TYPE_MAIN_VARIANT (rtype);
+
+      if (basetype != NULL_TREE && TREE_CODE (basetype) == POINTER_TYPE)
+	basetype = TREE_TYPE (basetype);
+      else
+	return NULL_TREE;
+
+      while (basetype != NULL_TREE
+	     && TREE_CODE (basetype) == RECORD_TYPE 
+	     && OBJC_TYPE_NAME (basetype)
+	     && TREE_CODE (OBJC_TYPE_NAME (basetype)) == TYPE_DECL
+	     && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (basetype)))
+	basetype = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (basetype));
+
+      if (basetype != NULL_TREE && TYPED_OBJECT (basetype))
+	{
+	  tree interface_type = TYPE_OBJC_INTERFACE (basetype);
+	  if (!interface_type)
+	    return NULL_TREE;
+	  x = lookup_property (interface_type, component);
+	}
+    }
+
+  if (x)
+    {
+      tree call_exp, getter;
+      /* Get the getter name. */
+      gcc_assert (PROPERTY_NAME (x));
+      getter = objc_finish_message_expr (receiver, PROPERTY_NAME (x), 
+					 NULL_TREE);
+      call_exp = getter;
+#ifdef OBJCPLUS
+      /* In C++, a getter which returns an aggregate value results in a 
+	 target_expr which initializes a temporary to the call expression.  */
+      if (TREE_CODE (getter) == TARGET_EXPR)
+	{
+	  gcc_assert (MAYBE_CLASS_TYPE_P (TREE_TYPE (getter)));
+	  gcc_assert (TREE_CODE (TREE_OPERAND (getter,0)) == VAR_DECL);
+	  call_exp = TREE_OPERAND (getter,1);
+	}
+#endif
+      gcc_assert (TREE_CODE (call_exp) == CALL_EXPR);
+
+      CALL_EXPR_OBJC_PROPERTY_GETTER (call_exp) = 1;
+      return getter;
+    }
+  return NULL_TREE;
+}
+
+/* This routine builds a call to property's 'setter' function.  RECEIVER is the
+   receiving object for 'setter'.  PROPERTY_IDENT is name of the property and
+   RHS is the argument passed to the 'setter' function.  */
+
+static tree
+objc_setter_func_call (tree receiver, tree property_ident, tree rhs)
+{
+  tree setter_argument = build_tree_list (NULL_TREE, rhs);
+  char *setter_name = objc_build_property_setter_name (property_ident, true);
+  tree setter;
+  in_objc_property_setter_name_context = true;
+  setter = objc_finish_message_expr (receiver, get_identifier (setter_name),
+				     setter_argument);
+  in_objc_property_setter_name_context = false;
+  return setter;
+}
+
+/* Find the selector identifier from a reference.  A somewhat tortuous way of
+   obtaining  the information to allow a setter to be written, given an
+   existing getter.  */
+
+static tree
+get_selector_from_reference (tree selref)
+{
+  tree chain;
+
+  if (flag_next_runtime)
+    {
+      /* Run through the selectors until we find the one we're looking for.  */
+      for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
+	if (TREE_PURPOSE (chain) == selref)
+	  return TREE_VALUE (chain);
+    }
+  else
+    {
+      /* To find our way back to the selector for the GNU runtime is harder
+         work, we need to decompose the representation of SELECTOR_TABLE[n]
+         to find 'n'.  This representation is in several forms.  */
+      if (TREE_CODE (selref) == POINTER_PLUS_EXPR) 
+	{
+	  /* We need the element size to decode the array offset expression 
+	     into an index.  */
+	  unsigned size = (unsigned) TREE_INT_CST_LOW  
+			      (TYPE_SIZE_UNIT 
+				(TREE_TYPE 
+				  (TREE_TYPE 
+				    (TREE_OPERAND 
+				      (TREE_OPERAND 
+					(TREE_OPERAND (selref, 0), 0), 0)))));
+	  unsigned index = 
+	  	(unsigned) TREE_INT_CST_LOW (TREE_OPERAND (selref, 1)) 
+	  		   / size;
+	  for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
+	    if (!index--)
+	      return TREE_VALUE (chain);
+	}
+      else if (TREE_CODE (selref) == NOP_EXPR)
+	{
+	  /* Either we have a base an index, or we have just a base (when the 
+	     index is 0.  */
+	  if (TREE_CODE (TREE_OPERAND (selref, 0)) == ADDR_EXPR
+	      && TREE_CODE 
+		   (TREE_OPERAND 
+		     (TREE_OPERAND (selref, 0), 0)) == ARRAY_REF)
+	    {
+	      /* The Nth.  */
+	      unsigned index = (unsigned) TREE_INT_CST_LOW
+					(TREE_OPERAND 
+					  (TREE_OPERAND 
+					    (TREE_OPERAND (selref, 0), 0), 1));
+	      for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
+		if (!index--)
+		  return TREE_VALUE (chain);
+	    }
+	  else
+	    return TREE_VALUE (sel_ref_chain);
+	} /* Else we don't know how to figure this out - which will produce a
+	     parse error - saying that the LHS is not writeable.  */
+    }
+  return NULL_TREE;
+}
+
+/* This routine converts a previously synthesized 'getter' function call for
+   a property and converts it to a 'setter' function call for the same
+   property.  */
+
+tree
+objc_build_setter_call (tree lhs, tree rhs)
+{
+  if (lhs 
+      && TREE_CODE (lhs) == CALL_EXPR
+      && CALL_EXPR_OBJC_PROPERTY_GETTER (lhs))
+    {
+      tree selector;
+      /* Get the Object.  */
+      tree receiver = TREE_OPERAND (lhs, 3);
+      /* Get the selector reference.  */
+      tree selector_reference = TREE_OPERAND (lhs, 4);
+      gcc_assert (receiver && selector_reference);
+      /* The style of the selector reference is different for GNU & NeXT.  */
+      selector = get_selector_from_reference (selector_reference);
+      if (selector)
+        return objc_setter_func_call (receiver, selector, rhs);
+    }
+  return NULL_TREE;
+}
+
+/* This routine checks to see if ID is a property name. If so, it
+   returns property declaration. */
+
+static tree 
+is_property (tree klass, tree id)
+{
+  tree x;
+
+  for (x = CLASS_PROPERTY_DECL (klass); x; x = TREE_CHAIN (x))
+    if (PROPERTY_NAME (x) == id)
+      return x;
+  return NULL_TREE;
+}
+
+/* This routine returns call to property's getter when a property is
+   used stand-alone (without self. notation). */
+
+static tree
+build_property_reference (tree property, tree id)
+{
+  tree getter;
+  if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
+    {
+      error ("property %qs accessed in class method",
+               IDENTIFIER_POINTER (id));
+      return error_mark_node;
+    }
+
+  getter = objc_finish_message_expr (self_decl, PROPERTY_NAME (property), NULL_TREE);
+  CALL_EXPR_OBJC_PROPERTY_GETTER (getter) = 1;
+  return getter;
+}
+
+void
 objc_set_method_type (enum tree_code type)
 {
   objc_inherit_code = (type == PLUS_EXPR
@@ -6511,9 +6986,11 @@  objc_finish_message_expr (tree receiver, tree sel_
 	      || CONVERT_EXPR_P (rtype)
 	      || TREE_CODE (rtype) == COMPONENT_REF)
     rtype = TREE_OPERAND (rtype, 0);
+
   self = (rtype == self_decl);
   super = (rtype == UOBJC_SUPER_decl);
   rtype = TREE_TYPE (receiver);
+
   have_cast = (TREE_CODE (receiver) == NOP_EXPR
 	       || (TREE_CODE (receiver) == COMPOUND_EXPR
 		   && !IS_SUPER (rtype)));
@@ -6663,7 +7140,9 @@  objc_finish_message_expr (tree receiver, tree sel_
 	  = lookup_method_in_hash_lists (sel_name, class_tree != NULL_TREE);
     }
 
-  if (!method_prototype)
+  if (!method_prototype && in_objc_property_setter_name_context)
+      error ("readonly property can not be set");
+  else if (!method_prototype) 
     {
       static bool warn_missing_methods = false;
 
@@ -7968,6 +8447,309 @@  continue_class (tree klass)
     return error_mark_node;
 }
 
+/* This routine builds a property ivar name. */
+
+static char *
+objc_build_property_ivar_name (tree property_decl)
+{
+  static char string[BUFSIZE];
+  sprintf (string, "_%s", IDENTIFIER_POINTER (PROPERTY_NAME (property_decl)));
+  return string;
+}
+
+/* This routine builds name of the setter synthesized function. */
+
+static char *
+objc_build_property_setter_name (tree ident, bool delimit_colon)
+{
+  static char string[BUFSIZE];
+  if (delimit_colon)
+    sprintf (string, "set%s:", IDENTIFIER_POINTER (ident));
+  else
+    sprintf (string, "set%s", IDENTIFIER_POINTER (ident));
+  string[3] = TOUPPER (string[3]);
+  return string;
+}
+
+/* This routine does all the work for generating data and code per each 
+   property declared in current implementation. */
+
+static void
+objc_gen_one_property_datum (tree klass, tree property, tree class_methods, bool *ivar_added)
+{
+  tree mth;
+
+  /* If getter, check that it is already declared in user code. */
+  if (PROPERTY_GETTER_NAME (property))
+    {
+      mth = lookup_method (CLASS_NST_METHODS (class_methods), 
+			   PROPERTY_GETTER_NAME (property));
+      if (!mth)
+	error ("property getter %qs not declared in class %qs",  
+		IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property)), 
+		IDENTIFIER_POINTER (CLASS_NAME (class_methods)));
+    }
+  /* If setter, check that it is already declared in user code. */
+  if (PROPERTY_SETTER_NAME (property))
+    {
+      mth = lookup_method (CLASS_NST_METHODS (class_methods), 
+			   PROPERTY_SETTER_NAME (property));
+      if (!mth)
+	error ("property setter %qs not declared in class %qs",  
+		IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property)), 
+		IDENTIFIER_POINTER (CLASS_NAME (class_methods)));
+    }
+  /* If ivar attribute specified, check that it is already declared. */
+  if (PROPERTY_IVAR_NAME (property))
+    {
+      if (!is_ivar (CLASS_IVARS (klass), 
+	   PROPERTY_IVAR_NAME (property)))
+	error ("ivar %qs in property declaration must be an existing ivar", 
+   	       IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property)));
+    }
+  else if (!PROPERTY_GETTER_NAME (property) 
+	   || (PROPERTY_READONLY (property) == boolean_false_node 
+	       && !PROPERTY_SETTER_NAME (property)))
+    {
+      /* Setter and/or getter must be synthesize and there was no user-specified
+	 ivar. Must create an ivar and add to to current class's ivar list. */
+      tree record = CLASS_STATIC_TEMPLATE (klass);
+      tree type = TREE_TYPE (property);
+      tree field_decl, field;
+      field_decl = create_field_decl (type, 
+				      objc_build_property_ivar_name (property));
+      DECL_CONTEXT (field_decl) = record;
+      (void) add_instance_variable (klass, 
+				    1, field_decl);
+      /* Unfortunately, CLASS_IVARS is completed when interface is completed.
+	 Must add the new ivar by hand to its list here. */
+      
+      CLASS_IVARS (klass) = 
+			chainon (CLASS_IVARS (klass), 
+				 copy_node (field_decl));
+      gcc_assert (record);
+      /* Must also add this ivar to the end of list of fields for this class. */
+      field = TYPE_FIELDS (record);
+      if (field && field != CLASS_IVARS (klass))
+        /* class has a hidden field, attach ivar list after the hiddent field. */
+        TREE_CHAIN (field) = CLASS_IVARS (klass);
+      else
+        TYPE_FIELDS (record) = CLASS_IVARS (klass);
+      *ivar_added = true;
+    }
+}
+
+/* This routine processes an existing getter or setter attribute.
+   It aliases internal property getter or setter to the user implemented 
+   getter or setter.
+*/
+
+static void 
+objc_process_getter_setter (tree klass, tree property, bool getter)
+{
+  tree prop_mth_decl;
+  tree prop_getter_mth_decl;
+  tree name_ident;
+
+  if (getter)
+    /* getter name is same as property name. */
+    name_ident = PROPERTY_NAME (property);
+  else
+    /* Must synthesize setter name from property name. */
+    name_ident = get_identifier (objc_build_property_setter_name (
+				   PROPERTY_NAME (property), true));
+
+  /* Find declaration of instance method for the property in its class. */
+  prop_mth_decl = lookup_method (CLASS_NST_METHODS (klass), name_ident);
+
+  if (!prop_mth_decl)
+    return;
+
+  prop_getter_mth_decl = lookup_method (CLASS_NST_METHODS (objc_implementation_context),
+					getter ? PROPERTY_GETTER_NAME (property) 
+					       : PROPERTY_SETTER_NAME (property));
+
+  if (!prop_getter_mth_decl)
+    return;
+
+  if (!match_proto_with_proto (prop_getter_mth_decl, prop_mth_decl, 1))
+    {
+      error ("User %s %qs does not match property %qs type", 
+		getter ? "getter" : "setter",
+		IDENTIFIER_POINTER (DECL_NAME (prop_getter_mth_decl)), 
+		IDENTIFIER_POINTER (PROPERTY_NAME (property)));
+      return;
+    }
+  /* We alias internal property getter to the user implemented getter by copying relevant
+     entries from user's implementation to the internal one. */
+  prop_mth_decl = copy_node (prop_mth_decl);
+  METHOD_ENCODING (prop_mth_decl) = METHOD_ENCODING (prop_getter_mth_decl);
+  METHOD_DEFINITION (prop_mth_decl) = METHOD_DEFINITION (prop_getter_mth_decl);
+  objc_add_method (objc_implementation_context, prop_mth_decl, 0, 0);
+}
+
+/* This routine synthesizes a 'getter' method. */
+
+static void
+objc_synthesize_getter (tree klass, tree class_method, tree property)
+{
+  tree fn, decl;
+  tree body;
+  tree ret_val;
+  tree ivar_ident;
+
+  /* If user has implemented a getter with same name then do nothing. */
+  if (lookup_method (CLASS_NST_METHODS (objc_implementation_context),
+		     PROPERTY_NAME (property)))
+    return;
+
+  /* Find declaration of the property in the interface. There must be one. */
+  decl = lookup_method (CLASS_NST_METHODS (class_method),
+                        PROPERTY_NAME (property));
+
+  /* If one not declared in the interface, this condition has already been reported
+     as user error (because property was not declared in the interface). */
+  if (!decl)
+    return;
+
+  objc_inherit_code = INSTANCE_METHOD_DECL;
+  /* For now no attributes.  */
+  objc_start_method_definition (copy_node (decl), NULL_TREE);
+
+  body = c_begin_compound_stmt (true);
+  /* return self->_property_name; */
+  /* If user specified an ivar, use it in generation of the getter. */
+  ivar_ident = PROPERTY_IVAR_NAME (property) 
+		? PROPERTY_IVAR_NAME (property) 
+		: get_identifier (objc_build_property_ivar_name (property));
+
+  /* objc_ivar_chain might not be up to date in the case that property 'ivar'
+     is added *after* user ivar is parsed and objc_continue_implementation 
+     has already been called. */
+  objc_ivar_chain = CLASS_IVARS (klass);
+  ret_val = objc_lookup_ivar (NULL_TREE, ivar_ident);
+  /* If ivar attribute is not a user declared attribute, this condition has
+     already been repored as error. */
+  gcc_assert (ret_val || PROPERTY_IVAR_NAME (property));
+
+  if (ret_val)
+    {
+#ifdef OBJCPLUS
+      finish_return_stmt (ret_val);
+#else
+      (void)c_finish_return (input_location, ret_val, NULL);
+#endif
+    }
+  add_stmt (c_end_compound_stmt (input_location, body, true));
+  fn = current_function_decl;
+#ifdef OBJCPLUS
+  finish_function ();
+#endif
+  objc_finish_method_definition (fn);
+}
+
+/* This routine synthesizes a 'setter' method.  */
+
+static void
+objc_synthesize_setter (tree klass, tree class_method, tree property)
+{
+  tree fn, decl, ivar_ident, lhs, rhs;
+  tree body;
+  char *setter_name = objc_build_property_setter_name (
+			PROPERTY_NAME (property), true);
+  tree setter_ident = get_identifier (setter_name);
+
+  /* If user has implemented a setter with same name then do nothing. */
+  if (lookup_method (CLASS_NST_METHODS (objc_implementation_context),
+		     setter_ident))
+    return;
+
+  /* Find declaration of the property in the interface. There must be one. */
+  decl = lookup_method (CLASS_NST_METHODS (class_method), setter_ident);
+
+  /* If one not declared in the inerface, this condition has already been reported
+     as user error (because property was not declared in the interface. */
+  if (!decl)
+    return;
+
+  objc_inherit_code = INSTANCE_METHOD_DECL;
+  /* For now, no attributes.  */
+  objc_start_method_definition (copy_node (decl), NULL_TREE);
+
+  body = c_begin_compound_stmt (true);
+  /* _property_name = _value; */
+  /* If user specified an ivar, use it in generation of the setter. */
+  ivar_ident = PROPERTY_IVAR_NAME (property) 
+		? PROPERTY_IVAR_NAME (property) 
+		: get_identifier (objc_build_property_ivar_name (property));
+
+  /* objc_ivar_chain might not be up to date in the case that property 'ivar'
+     is added *after* user ivar is parsed and objc_continue_implementation 
+     has already been called. */
+  objc_ivar_chain = CLASS_IVARS (klass);
+  lhs = objc_lookup_ivar (NULL_TREE, ivar_ident);
+  /* If ivar attribute is not a user declared attribute, this condition has
+     already been repored as error. */
+  gcc_assert (lhs || PROPERTY_IVAR_NAME (property));
+  if (lhs)
+    {
+      rhs = lookup_name (get_identifier ("_value"));
+      gcc_assert (rhs);
+      /* FIXME: NULL types to get compile.  */
+      add_stmt (build_modify_expr (input_location, 
+      				   lhs, NULL_TREE, NOP_EXPR, 
+      				   input_location, rhs, NULL_TREE));
+    }
+  add_stmt (c_end_compound_stmt (input_location, body, true));
+  fn = current_function_decl;
+#ifdef OBJCPLUS
+  finish_function ();
+#endif
+  objc_finish_method_definition (fn);
+}
+
+/* Main routine to generate code/data for all the property information for 
+   current implementation (class or category). CLASS is the interface where
+   ivars are declared.  CLASS_METHODS is where methods are found which
+   could be a class or a category depending on whether we are implementing
+   property of a class or a category.  */
+
+static void
+objc_gen_property_data (tree klass, tree class_methods)
+{
+  tree x;
+  bool  ivar_added = false;
+  for (x = IMPL_PROPERTY_DECL (objc_implementation_context); x; x = TREE_CHAIN (x))
+     objc_gen_one_property_datum (klass, x, class_methods, &ivar_added);
+
+  if (ivar_added)
+    {
+      tree record = CLASS_STATIC_TEMPLATE (klass);
+      /* Ugh, must recalculate struct layout since at least one ivar was added. */
+      TYPE_SIZE (record) = 0;
+      layout_type (record);
+    }
+
+  /* Synthesize all getters for properties. */
+  for (x = IMPL_PROPERTY_DECL (objc_implementation_context); x; x = TREE_CHAIN (x))
+    {
+     /* Property has a getter attribute, no need to synthesize one. */
+     if (PROPERTY_GETTER_NAME (x) == NULL_TREE)
+       objc_synthesize_getter (klass, class_methods, x);
+     else
+       objc_process_getter_setter (class_methods, x, true);
+
+     if (PROPERTY_READONLY (x) == boolean_false_node)
+       {
+	 /* not a readonly property. */
+	 if (PROPERTY_SETTER_NAME (x) == NULL_TREE)
+	   objc_synthesize_setter (klass, class_methods, x);
+	 else
+	   objc_process_getter_setter (class_methods, x, false);
+       }
+    }
+}
+
 /* This is called once we see the "@end" in an interface/implementation.  */
 
 static void
@@ -7977,6 +8759,9 @@  finish_class (tree klass)
     {
       /* All code generation is done in finish_objc.  */
 
+      /* Generate what needed for property; setters, getters, etc. */
+      objc_gen_property_data (implementation_template, implementation_template);
+
       if (implementation_template != objc_implementation_context)
 	{
 	  /* Ensure that all method listed in the interface contain bodies.  */
@@ -7998,6 +8783,9 @@  finish_class (tree klass)
 
       if (category)
 	{
+          /* Generate what needed for property; setters, getters, etc. */
+          objc_gen_property_data (implementation_template, category);
+
 	  /* Ensure all method listed in the interface contain bodies.  */
 	  check_methods (CLASS_CLS_METHODS (category),
 			 CLASS_CLS_METHODS (objc_implementation_context), '+');
@@ -8010,6 +8798,60 @@  finish_class (tree klass)
 			     CLASS_SUPER_NAME (objc_implementation_context));
 	}
     }
+  else 
+    {
+      /* Process properties of the class. */
+      tree x;
+      for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
+	{
+	  tree type = TREE_TYPE (x);
+	  tree prop_name = PROPERTY_NAME (x);
+	  /* Build an instance method declaration: - (type) prop_name; */
+	  if (PROPERTY_GETTER_NAME (x) == NULL_TREE)
+	    {
+	      /* No getter attribute specified. Generate an instance method for the 
+		 getter. */
+	      tree rettype = build_tree_list (NULL_TREE, type);
+	      tree getter_decl = build_method_decl (INSTANCE_METHOD_DECL, 
+						    rettype, prop_name, 
+						    NULL_TREE, false);
+	      objc_add_method (objc_interface_context, getter_decl, false, false);
+	      METHOD_PROPERTY_CONTEXT (getter_decl) = x;
+	    }
+	  else
+	    warning (0, "getter = %qs may not be specified in an interface", 
+		     IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (x)));
+
+	  /* Build an instance method declaration: - (void) setName: (type)value; */
+	  if (PROPERTY_SETTER_NAME (x) == NULL_TREE 
+	      && PROPERTY_READONLY (x) == boolean_false_node)
+	    {
+	      /* Declare a setter instance method in the interface. */
+	      tree key_name, arg_type, arg_name;
+	      tree setter_decl, selector;
+	      tree ret_type = build_tree_list (NULL_TREE, void_type_node);
+	      /* setter name. */
+	      key_name = get_identifier (objc_build_property_setter_name (
+					  PROPERTY_NAME (x), false));
+	      arg_type = build_tree_list (NULL_TREE, type);
+	      arg_name = get_identifier ("_value");
+	      /* For now, no attributes.  */
+	      selector = objc_build_keyword_decl (key_name, arg_type, arg_name, NULL);
+	      setter_decl = build_method_decl (INSTANCE_METHOD_DECL, 
+					       ret_type, selector, 
+					       build_tree_list (NULL_TREE, NULL_TREE),
+					       false);
+	      objc_add_method (objc_interface_context, setter_decl, false, false);
+	      METHOD_PROPERTY_CONTEXT (setter_decl) = x;
+	    }
+	  else if (PROPERTY_SETTER_NAME (x))
+	    warning (0, "setter = %qs may not be specified in an interface", 
+		     IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (x)));
+	  if (PROPERTY_IVAR_NAME (x))
+	    warning (0, "ivar  = %qs attribute may not be specified in an interface",
+		     IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (x)));
+	}
+    }
 }
 
 static tree
@@ -8988,13 +9830,19 @@  objc_types_share_size_and_alignment (tree type1, t
 static int
 comp_proto_with_proto (tree proto1, tree proto2, int strict)
 {
-  tree type1, type2;
-
   /* The following test is needed in case there are hashing
      collisions.  */
   if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2))
     return 0;
 
+  return match_proto_with_proto (proto1, proto2, strict);
+}
+
+static int
+match_proto_with_proto (tree proto1, tree proto2, int strict)
+{
+  tree type1, type2;
+
   /* Compare return types.  */
   type1 = TREE_VALUE (TREE_TYPE (proto1));
   type2 = TREE_VALUE (TREE_TYPE (proto2));
@@ -9970,11 +10818,11 @@  generate_objc_image_info (void)
 
 /* Look up ID as an instance variable.  OTHER contains the result of
    the C or C++ lookup, which we may want to use instead.  */
-
+/* Also handle use of property as setter/getter. */
 tree
 objc_lookup_ivar (tree other, tree id)
 {
-  tree ivar;
+  tree ivar, property;
 
   /* If we are not inside of an ObjC method, ivar lookup makes no sense.  */
   if (!objc_method_context)
@@ -9990,12 +10838,19 @@  objc_lookup_ivar (tree other, tree id)
       && other && other != error_mark_node)
     return other;
 
-  /* Look up the ivar, but do not use it if it is not accessible.  */
-  ivar = is_ivar (objc_ivar_chain, id);
+  property = NULL_TREE;
+  if (objc_implementation_context)
+    property = is_property (objc_implementation_context, id);
 
-  if (!ivar || is_private (ivar))
-    return other;
+  if (!property)
+    {
+      /* Look up the ivar, but do not use it if it is not accessible.  */
+      ivar = is_ivar (objc_ivar_chain, id);
 
+      if (!ivar || is_private (ivar))
+	return other;
+    }
+
   /* In an instance method, a local variable (or parameter) may hide the
      instance variable.  */
   if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL
@@ -10006,12 +10861,17 @@  objc_lookup_ivar (tree other, tree id)
       && !DECL_FILE_SCOPE_P (other))
 #endif
     {
-      warning (0, "local declaration of %qE hides instance variable",
-	       id);
+      if (property)
+	warning (0, "local declaration of %qE hides property", id);
+      else
+	warning (0, "local declaration of %qE hides instance variable", id);
 
       return other;
     }
 
+  if (property)
+    return build_property_reference (property, id);
+
   /* At this point, we are either in an instance method with no obscuring
      local definitions, or in a class method with no alternate definitions
      at all.  */
Index: gcc/objc/objc-lang.c
===================================================================
--- gcc/objc/objc-lang.c	(revision 165478)
+++ gcc/objc/objc-lang.c	(working copy)
@@ -69,22 +69,27 @@  objc_init_ts (void)
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_NON_COMMON] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_NON_COMMON] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_NON_COMMON] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_NON_COMMON] = 1;
   
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_WITH_VIS] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_WITH_VIS] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_WITH_VIS] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_WITH_VIS] = 1;
 
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_WRTL] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_WRTL] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_WRTL] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_WRTL] = 1;
   
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_MINIMAL] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_MINIMAL] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_MINIMAL] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_MINIMAL] = 1;
   
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_COMMON] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_COMMON] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_COMMON] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_COMMON] = 1;
 }
 
 void
Index: gcc/objc/objc-act.h
===================================================================
--- gcc/objc/objc-act.h	(revision 165478)
+++ gcc/objc/objc-act.h	(working copy)
@@ -37,8 +37,8 @@  tree objc_eh_personality (void);
 
 /* Objective-C structures */
 
-#define CLASS_LANG_SLOT_ELTS		5
-#define PROTOCOL_LANG_SLOT_ELTS		4
+#define CLASS_LANG_SLOT_ELTS		7
+#define PROTOCOL_LANG_SLOT_ELTS		7
 #define OBJC_INFO_SLOT_ELTS		2
 
 /* KEYWORD_DECL */
@@ -53,7 +53,15 @@  tree objc_eh_personality (void);
 #define METHOD_DEFINITION(DECL) ((DECL)->decl_common.initial)
 #define METHOD_ENCODING(DECL) ((DECL)->decl_minimal.context)
 #define METHOD_TYPE_ATTRIBUTES(DECL) ((DECL)->decl_common.abstract_origin)
+#define METHOD_PROPERTY_CONTEXT(DECL) ((DECL)->decl_common.size_unit)
 
+#define PROPERTY_NAME(DECL) ((DECL)->decl_minimal.name)
+#define PROPERTY_GETTER_NAME(DECL) ((DECL)->decl_non_common.arguments)
+#define PROPERTY_SETTER_NAME(DECL) ((DECL)->decl_non_common.result)
+#define PROPERTY_IVAR_NAME(DECL) ((DECL)->decl_common.initial)
+#define PROPERTY_READONLY(DECL) ((DECL)->decl_minimal.context)
+#define PROPERTY_COPIES(DECL) ((DECL)->decl_common.size_unit)
+
 /* CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
    CATEGORY_INTERFACE_TYPE, CATEGORY_IMPLEMENTATION_TYPE,
    PROTOCOL_INTERFACE_TYPE */
@@ -66,6 +74,8 @@  tree objc_eh_personality (void);
 #define CLASS_STATIC_TEMPLATE(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 2)
 #define CLASS_CATEGORY_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 3)
 #define CLASS_PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 4)
+#define TOTAL_CLASS_RAW_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 5)
+
 #define PROTOCOL_NAME(CLASS) ((CLASS)->type.name)
 #define PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 0)
 #define PROTOCOL_NST_METHODS(CLASS) ((CLASS)->type.minval)
@@ -75,6 +85,11 @@  tree objc_eh_personality (void);
 #define PROTOCOL_OPTIONAL_CLS_METHODS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 2)
 #define PROTOCOL_OPTIONAL_NST_METHODS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 3)
 
+/* For CATEGORY_INTERFACE_TYPE, CLASS_INTERFACE_TYPE or PROTOCOL_INTERFACE_TYPE */
+#define CLASS_PROPERTY_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 6)
+/* For CLASS_IMPLEMENTATION_TYPE or CATEGORY_IMPLEMENTATION_TYPE. */
+#define IMPL_PROPERTY_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 6)
+
 /* ObjC-specific information pertaining to RECORD_TYPEs are stored in
    the LANG_SPECIFIC structures, which may itself need allocating first.  */
 
Index: gcc/objc/objc-tree.def
===================================================================
--- gcc/objc/objc-tree.def	(revision 165478)
+++ gcc/objc/objc-tree.def	(working copy)
@@ -34,6 +34,7 @@  DEFTREECODE (PROTOCOL_INTERFACE_TYPE, "protocol_in
 DEFTREECODE (KEYWORD_DECL, "keyword_decl", tcc_declaration, 0)
 DEFTREECODE (INSTANCE_METHOD_DECL, "instance_method_decl", tcc_declaration, 0)
 DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", tcc_declaration, 0)
+DEFTREECODE (PROPERTY_DECL, "property_decl", tcc_declaration, 0)
 
 /* Objective-C expressions.  */
 DEFTREECODE (MESSAGE_SEND_EXPR, "message_send_expr", tcc_expression, 3)
Index: gcc/objcp/objcp-lang.c
===================================================================
--- gcc/objcp/objcp-lang.c	(revision 165478)
+++ gcc/objcp/objcp-lang.c	(working copy)
@@ -100,22 +100,27 @@  objcxx_init_ts (void)
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_NON_COMMON] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_NON_COMMON] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_NON_COMMON] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_NON_COMMON] = 1;
   
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_WITH_VIS] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_WITH_VIS] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_WITH_VIS] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_WITH_VIS] = 1;
 
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_WRTL] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_WRTL] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_WRTL] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_WRTL] = 1;
   
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_MINIMAL] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_MINIMAL] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_MINIMAL] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_MINIMAL] = 1;
   
   tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_COMMON] = 1;
   tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_COMMON] = 1;
   tree_contains_struct[KEYWORD_DECL][TS_DECL_COMMON] = 1;
+  tree_contains_struct[PROPERTY_DECL][TS_DECL_COMMON] = 1;
   
   /* C++ decls */
   tree_contains_struct[NAMESPACE_DECL][TS_DECL_NON_COMMON] = 1;
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 165478)
+++ gcc/cp/parser.c	(working copy)
@@ -2097,7 +2097,11 @@  static void cp_parser_objc_declaration
 static tree cp_parser_objc_statement
   (cp_parser *);
 static bool cp_parser_objc_valid_prefix_attributes
-  (cp_parser* parser, tree *attrib);
+  (cp_parser *, tree *);
+static void cp_parser_objc_at_property 
+  (cp_parser *) ;
+static void cp_parser_objc_property_decl 
+  (cp_parser *) ;
 
 /* Utility Routines */
 
@@ -21718,6 +21722,8 @@  cp_parser_objc_method_prototype_list (cp_parser* p
 	  objc_add_method_declaration (sig, attributes);
 	  cp_parser_consume_semicolon_at_end_of_statement (parser);
 	}
+      else if (token->keyword == RID_AT_PROPERTY)
+	cp_parser_objc_at_property (parser);
       else if (token->keyword == RID_ATTRIBUTE 
       	       && cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
 	warning_at (cp_lexer_peek_token (parser->lexer)->location, 
@@ -21779,6 +21785,8 @@  cp_parser_objc_method_definition_list (cp_parser*
 	      objc_finish_method_definition (meth);
 	    }
 	}
+      else if (token->keyword == RID_AT_PROPERTY)
+	cp_parser_objc_at_property (parser);
       else if (token->keyword == RID_ATTRIBUTE 
       	       && cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
 	warning_at (token->location, OPT_Wattributes,
@@ -22271,6 +22279,146 @@  cp_parser_objc_valid_prefix_attributes (cp_parser*
   cp_lexer_rollback_tokens (parser->lexer);
   return false;  
 }
+
+/* This routine parses the propery declarations. */
+
+static void
+cp_parser_objc_property_decl (cp_parser *parser)
+{
+  int declares_class_or_enum;
+  cp_decl_specifier_seq declspecs;
+
+  cp_parser_decl_specifier_seq (parser,
+                                CP_PARSER_FLAGS_NONE,
+                                &declspecs,
+                                &declares_class_or_enum);
+  /* Keep going until we hit the `;' at the end of the declaration. */
+  while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+    {
+      tree property;
+      cp_token *token;
+      cp_declarator *declarator
+	= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+				NULL, NULL, false);
+      property = grokdeclarator (declarator, &declspecs, NORMAL,0, NULL);
+      /* Recover from any kind of error in property declaration. */
+      if (property == error_mark_node || property == NULL_TREE)
+	return;
+
+      /* Add to property list. */
+      objc_add_property_variable (copy_node (property));
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type == CPP_COMMA)
+	{
+	  cp_lexer_consume_token (parser->lexer);  /* Eat ','.  */
+	  continue;
+	}
+      else if (token->type == CPP_EOF)
+	break;
+    }
+  /* Eat ';' if present, or issue an error.  */
+  cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+}
+
+/* ObjC @property. */
+/* Parse a comma-separated list of property attributes.  
+   The lexer does not recognize */
+
+static void 
+cp_parser_objc_property_attrlist (cp_parser *parser)
+{
+  cp_token *token;
+  /* Initialize to an empty list.  */
+  objc_set_property_attr (cp_lexer_peek_token (parser->lexer)->location,
+			  OBJC_PATTR_INIT, NULL_TREE);
+
+  /* The list is optional.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
+    return;
+
+  /* Eat the '('.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  token = cp_lexer_peek_token (parser->lexer);
+  while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF)
+    {
+      location_t loc = token->location;
+      tree node = cp_parser_identifier (parser);
+      if (node == ridpointers [(int) RID_READONLY])
+	objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
+      else if (node == ridpointers [(int) RID_GETTER]
+	       || node == ridpointers [(int) RID_SETTER]
+	       || node == ridpointers [(int) RID_IVAR])
+	{
+	  /* Do the getter/setter/ivar attribute. */
+	  token = cp_lexer_consume_token (parser->lexer);
+	  if (token->type == CPP_EQ)
+	    {
+	      tree attr_ident = cp_parser_identifier (parser);
+	      objc_property_attribute_kind pkind;
+	      if (node == ridpointers [(int) RID_GETTER])
+		pkind = OBJC_PATTR_GETTER;
+	      else if (node == ridpointers [(int) RID_SETTER])
+		{
+		  pkind = OBJC_PATTR_SETTER;
+		  /* Consume the ':' which must always follow the setter name. */
+		  if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+		    cp_lexer_consume_token (parser->lexer); 
+		  else
+		    {
+		      error_at (token->location,
+				"setter name must be followed by %<:%>");
+		      break;
+		    }
+		}
+	      else 
+		pkind = OBJC_PATTR_IVAR;
+	      objc_set_property_attr (loc, pkind, attr_ident);	  
+	    }
+	  else
+	    {
+	      error_at (token->location,
+	      	"getter/setter/ivar attribute must be followed by %<=%>");
+	      break;
+	    }
+	}
+      else if (node == ridpointers [(int) RID_COPIES])
+	objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE);
+      else
+	{
+	  error_at (token->location,"unknown property attribute");
+	  break;
+	}
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+	cp_lexer_consume_token (parser->lexer);
+      else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+	warning_at (token->location, 0, 
+		    "property attributes should be separated by a %<,%>");
+      token = cp_lexer_peek_token (parser->lexer);	  
+    }
+
+  if (token->type != CPP_CLOSE_PAREN)
+    error_at (token->location,
+	      "syntax error in @property's attribute declaration");
+  else
+    /* Consume ')' */
+    cp_lexer_consume_token (parser->lexer);
+}
+
+/* This function parses a @property declaration inside an objective class
+   or its implementation. */
+
+static void 
+cp_parser_objc_at_property (cp_parser *parser)
+{
+  /* Consume @property */
+  cp_lexer_consume_token (parser->lexer);
+
+  /* Parse optional attributes list...  */
+  cp_parser_objc_property_attrlist (parser);
+  /* ... and the property declaration(s).  */
+  cp_parser_objc_property_decl (parser);
+}
 
 /* OpenMP 2.5 parsing routines.  */
 
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 165478)
+++ gcc/cp/typeck.c	(working copy)
@@ -2593,7 +2593,11 @@  finish_class_member_access_expr (tree object, tree
 	return build_min_nt (COMPONENT_REF, object, name, NULL_TREE);
       object = build_non_dependent_expr (object);
     }
-
+  else if (c_dialect_objc ()
+	   && TREE_CODE (name) == IDENTIFIER_NODE
+	   && (expr = objc_build_getter_call (object, name)))
+    return expr;
+    
   /* [expr.ref]
 
      The type of the first expression shall be "class object" (of a
@@ -6758,6 +6762,13 @@  cp_build_modify_expr (tree lhs, enum tree_code mod
 
       if (modifycode == NOP_EXPR)
 	{
+	  if (c_dialect_objc ())
+	    {
+	      result = objc_build_setter_call (lhs, rhs);
+	      if (result)
+		return result;
+	    }
+
 	  /* `operator=' is not an inheritable operator.  */
 	  if (! MAYBE_CLASS_TYPE_P (lhstype))
 	    /* Do the default thing.  */;
@@ -6796,6 +6807,12 @@  cp_build_modify_expr (tree lhs, enum tree_code mod
 
 	  /* Now it looks like a plain assignment.  */
 	  modifycode = NOP_EXPR;
+	  if (c_dialect_objc ())
+	    {
+	      result = objc_build_setter_call (lhs, newrhs);
+	      if (result)
+		return result;
+	    }
 	}
       gcc_assert (TREE_CODE (lhstype) != REFERENCE_TYPE);
       gcc_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE);
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 165478)
+++ gcc/c-parser.c	(working copy)
@@ -195,6 +195,9 @@  typedef struct GTY(()) c_parser {
      undesirable to bind an identifier to an Objective-C class, even
      if a class with that name exists.  */
   BOOL_BITFIELD objc_need_raw_identifier : 1;
+  /* True if we are in a context where the Objective-C "Property attribute"
+     keywords are valid.  */
+  BOOL_BITFIELD objc_property_attr_context : 1;
 } c_parser;
 
 
@@ -283,6 +286,20 @@  c_lex_one_token (c_parser *parser, c_token *token)
 		   normal tokens.
 		*/
 	      }
+	    else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code))
+	      {
+		/* We found an Objective-C "property attribute" keyword 
+		   (readonly, copies, getter, setter, ivar). These are 
+		   only valid in the property context.  */
+		if (parser->objc_property_attr_context)
+		  {
+		    token->type = CPP_KEYWORD;
+		    token->keyword = rid_code;
+		    break;
+		  }
+		/* Else they are not special keywords.
+		*/
+	      }
 	    else if (c_dialect_objc () 
 		     && (OBJC_IS_AT_KEYWORD (rid_code)
 			 || OBJC_IS_CXX_KEYWORD (rid_code)))
@@ -573,6 +590,8 @@  c_token_starts_declaration (c_token *token)
     return false;
 }
 
+static c_token *c_parser_peek_2nd_token (c_parser *parser);
+
 /* Return true if the next token from PARSER can start declaration
    specifiers, false otherwise.  */
 static inline bool
@@ -1062,7 +1081,8 @@  static tree c_parser_objc_selector_arg (c_parser *
 static tree c_parser_objc_receiver (c_parser *);
 static tree c_parser_objc_message_args (c_parser *);
 static tree c_parser_objc_keywordexpr (c_parser *);
-static bool c_parser_objc_diagnose_bad_element_prefix 
+static void c_parser_objc_at_property (c_parser *) ;
+static bool c_parser_objc_diagnose_bad_element_prefix
   (c_parser *, struct c_declspecs *);
 
 /* Parse a translation unit (C90 6.7, C99 6.9).
@@ -1161,6 +1181,10 @@  c_parser_external_declaration (c_parser *parser)
 	  gcc_assert (c_dialect_objc ());
 	  c_parser_objc_protocol_definition (parser, NULL_TREE);
 	  break;
+	case RID_AT_PROPERTY:
+	  gcc_assert (c_dialect_objc ());
+	  c_parser_objc_at_property (parser);
+	  break;
 	case RID_AT_END:
 	  gcc_assert (c_dialect_objc ());
 	  c_parser_consume_token (parser);
@@ -1378,6 +1402,17 @@  c_parser_declaration_or_fndef (c_parser *parser, b
 	    return;
 	  }
 	  break;
+	case RID_AT_ALIAS:
+	case RID_AT_CLASS:
+	case RID_AT_END:
+	case RID_AT_PROPERTY:
+	  if (specs->attrs)
+	    {
+	      c_parser_error (parser, 
+	      		      "attributes may not be specified before" );
+	      specs->attrs = NULL;
+	    }
+	  break;
 	default:
 	  break;
 	}
@@ -6942,6 +6977,8 @@  c_parser_objc_methodprotolist (c_parser *parser)
 	default:
 	  if (c_parser_next_token_is_keyword (parser, RID_AT_END))
 	    return;
+	  else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY))
+	    c_parser_objc_at_property (parser);
 	  else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL))
 	    {
 	      objc_set_method_opt (true);
@@ -7517,6 +7554,135 @@  c_parser_objc_diagnose_bad_element_prefix (c_parse
     }
   return false;
 }
+
+/* ObjC @property. */
+
+/* Parse a comma-separated list of property attributes.  */
+
+static void
+c_parser_objc_property_attrlist (c_parser *parser)
+{
+  bool err = false;
+  /* Initialize to an empty list.  */
+  objc_set_property_attr (c_parser_peek_token (parser)->location,
+			  OBJC_PATTR_INIT, NULL_TREE);
+
+  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+    return;
+
+  /* Eat the '(' */
+  c_parser_consume_token (parser);
+  
+  /* Property attribute keywords are valid now.  */
+  parser->objc_property_attr_context = true;
+  while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)
+	 && c_parser_next_token_is_not (parser, CPP_EOF)
+	 && !err)
+    {
+      enum rid keywd;
+      location_t loc;
+      if (c_parser_peek_token (parser)->type != CPP_KEYWORD)
+	{
+	  c_parser_error (parser, "expected a property attribute");
+	  c_parser_consume_token (parser);
+	  err = true;
+	  break;
+	}
+      keywd = c_parser_peek_token (parser)->keyword;
+      /* Initially, make diagnostics point to the attribute.  */
+      loc = c_parser_peek_token (parser)->location;
+      switch (keywd)
+	{
+	  tree ident;
+	  objc_property_attribute_kind pkind;
+	  case RID_READONLY:
+	    objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
+	    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, 
+		  "getter/setter/ivar attribute must be followed by %<=%>");
+		err = true;
+		break;
+	      }
+	    c_parser_consume_token (parser); /* eat the = */
+	    if (c_parser_next_token_is_not (parser, CPP_NAME))
+	      {
+		c_parser_error (parser, "expected an identifier");
+		err = true;
+		break;
+	      }
+	    ident = c_parser_peek_token (parser)->value;
+	    if (keywd == RID_SETTER)
+	      {
+		pkind = OBJC_PATTR_SETTER;
+		/* Eat the identifier, and look for the following : */
+		c_parser_consume_token (parser);
+		if (c_parser_next_token_is_not (parser, CPP_COLON))
+		  {
+		    c_parser_error (parser,
+				"setter name must be followed by %<:%>");
+		    err = true;
+		  }
+	      }
+	    else if (keywd == RID_GETTER)
+	      pkind = OBJC_PATTR_GETTER;
+	    else
+	      pkind = OBJC_PATTR_IVAR;
+	    
+	    objc_set_property_attr (loc, pkind, ident);
+	    break;
+	  case RID_COPIES:
+	    objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE);
+	    break;
+	  default:
+	    c_parser_error (parser, "unknown property attribute");
+	    err = true;
+	    break;
+	}
+      /* Eat the attribute,identifier or colon that's been used.  */
+      c_parser_consume_token (parser);
+      if (err)
+        break;
+
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+	c_parser_consume_token (parser);
+      else if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+	warning_at (c_parser_peek_token (parser)->location, 0, 
+		    "property attributes should be separated by a %<,%>");
+    }  
+  parser->objc_property_attr_context = false;
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+}
+
+/* Parse property attributes and then the definition.  */
+
+static void
+c_parser_objc_at_property (c_parser *parser)
+{
+  tree props;
+  /* We should only arrive here with the property keyword.  */
+  c_parser_require_keyword (parser, RID_AT_PROPERTY, "expected %<@property%>");
+
+  /* Process the optional attribute list...  */
+  c_parser_objc_property_attrlist (parser) ;
+  /* ... and the property var decls.  */
+  props = c_parser_struct_declaration (parser);
+
+  /* Comma-separated properties are chained together in
+     reverse order; add them one by one.  */
+  props = nreverse (props);
+
+  for (; props; props = TREE_CHAIN (props))
+    objc_add_property_variable (copy_node (props));
+
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
 
 /* Handle pragmas.  Some OpenMP pragmas are associated with, and therefore
    should be considered, statements.  ALLOW_STMT is true if we're within
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 165478)
+++ gcc/c-typeck.c	(working copy)
@@ -2130,6 +2130,10 @@  build_component_ref (location_t loc, tree datum, t
   if (!objc_is_public (datum, component))
     return error_mark_node;
 
+  if (c_dialect_objc ()
+      && (ref = objc_build_getter_call (datum, component)))
+    return ref;
+
   /* See if there is a field or component with name COMPONENT.  */
 
   if (code == RECORD_TYPE || code == UNION_TYPE)
@@ -4837,7 +4841,8 @@  build_modify_expr (location_t location, tree lhs,
   if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
     return error_mark_node;
 
-  if (!lvalue_or_else (lhs, lv_assign))
+  /* For ObjC, defer this check until we have assessed CLASS.property.   */
+  if (!c_dialect_objc () && !lvalue_or_else (lhs, lv_assign))
     return error_mark_node;
 
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
@@ -4878,6 +4883,15 @@  build_modify_expr (location_t location, tree lhs,
       rhs_origtype = NULL_TREE;
     }
 
+  if (c_dialect_objc ())
+    {
+      result = objc_build_setter_call (lhs, newrhs);
+      if (result)
+	return result;
+      if (!lvalue_or_else (lhs, lv_assign))
+	return error_mark_node;
+    }
+
   /* Give an error for storing in something that is 'const'.  */
 
   if (TYPE_READONLY (lhstype)