OSDN Git Service

In gcc/:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 27 Oct 2010 04:37:47 +0000 (04:37 +0000)
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 27 Oct 2010 04:37:47 +0000 (04:37 +0000)
2010-10-27  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.
        Code rewritten to be much more robust in recovering from syntax
        errors.  Added comments.
        (c_parser_objc_property_attrlist): Removed.
        (c_parser_external_declaration): Updated calls to
        c_parser_objc_at_property, now
        c_parser_objc_at_property_declaration.
        (c_parser_objc_methodprotolist): Same change.

In gcc/c-family/:
2010-10-27  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.

In gcc/cp/:
2010-10-27  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
        missing or invalid declspecs.  Implemented attributes.  Do not eat
        the ';' at the end.  Exit loop whenever a non-comma is parsed, not
        just EOF.
        (cp_parser_objc_at_property): Renamed to
        cp_parser_objc_at_property_declaration.  Updated calls to
        objc_add_property_variable, now objc_add_property_declaration, and
        to cp_parser_objc_property_decl, now
        cp_parser_objc_struct_declaration.  Rewritten all code to be more
        robust in dealing with syntax errors, and almost identical to the
        one in c_parser_objc_at_property_declaration.
        (cp_parser_objc_property_attrlist): Removed.
        (cp_parser_objc_method_prototype_list): Updated call to
        cp_parser_objc_at_property.
        (cp_parser_objc_method_definition_list): Same change.
        (cp_parser_objc_class_ivars): Detect a number of invalid
        declarations of instance variables and produce errors when they
        are found.

In gcc/objc/:
2010-10-27  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
        property declaration is found outside an interface or
        implementation context.

In gcc/testsuite/:
2010-10-27  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.
        * objc.dg/ivar-invalid-type-1.m: New.
        * obj-c++.dg/property/at-property-1.mm: New.
        * obj-c++.dg/property/at-property-2.mm: New.
        * obj-c++.dg/property/at-property-3.mm: New.
        * obj-c++.dg/ivar-invalid-type-1.mm: New.
        * objc.dg/property/property-neg-6.m: Updated testcase for updates
        in error reporting.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@165996 138bc75d-0d04-0410-961f-82ee72b054a4

19 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.h
gcc/c-family/stub-objc.c
gcc/c-parser.c
gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/at-property-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/at-property-2.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/at-property-3.mm [new file with mode: 0644]
gcc/testsuite/objc.dg/ivar-invalid-type-1.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-1.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-2.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-3.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/property-neg-6.m

index 3686a29..22fb34a 100644 (file)
@@ -1,3 +1,16 @@
+2010-10-27  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.
+       Code rewritten to be much more robust in recovering from syntax
+       errors.  Added comments.
+       (c_parser_objc_property_attrlist): Removed.
+       (c_parser_external_declaration): Updated calls to
+       c_parser_objc_at_property, now
+       c_parser_objc_at_property_declaration.
+       (c_parser_objc_methodprotolist): Same change.
+       
 2010-10-26  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/i386.md (split_stack_return): Put back
index b73e45a..d742912 100644 (file)
@@ -1,3 +1,9 @@
+2010-10-27  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.
+       
 2010-10-23  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        * c-common.h (objc_maybe_printable_name): New.
index 8031bb4..5563765 100644 (file)
@@ -1043,7 +1043,7 @@ 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 void objc_add_property_declaration (location_t, 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);
index f808dc7..fb92c7f 100644 (file)
@@ -331,7 +331,7 @@ objc_set_property_attr (location_t ARG_UNUSED (loc),
 }
 
 void
-objc_add_property_variable (tree ARG_UNUSED (prop))
+objc_add_property_declaration (location_t ARG_UNUSED (loc), tree ARG_UNUSED (prop))
 {
 }
 
index e4efd38..c885c8a 100644 (file)
@@ -1081,7 +1081,7 @@ 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 void c_parser_objc_at_property (c_parser *) ;
+static void c_parser_objc_at_property_declaration (c_parser *);
 static void c_parser_objc_at_synthesize_declaration (c_parser *);
 static void c_parser_objc_at_dynamic_declaration (c_parser *);
 static bool c_parser_objc_diagnose_bad_element_prefix
@@ -1185,7 +1185,7 @@ c_parser_external_declaration (c_parser *parser)
          break;
        case RID_AT_PROPERTY:
          gcc_assert (c_dialect_objc ());
-         c_parser_objc_at_property (parser);
+         c_parser_objc_at_property_declaration (parser);
          break;
        case RID_AT_SYNTHESIZE:
          gcc_assert (c_dialect_objc ());
@@ -6997,7 +6997,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
          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);
+           c_parser_objc_at_property_declaration (parser);
          else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL))
            {
              objc_set_method_opt (true);
@@ -7574,132 +7574,178 @@ c_parser_objc_diagnose_bad_element_prefix (c_parser *parser,
   return false;
 }
 
-/* ObjC @property. */
+/* Parse an Objective-C @property declaration.  The syntax is:
 
-/* Parse a comma-separated list of property attributes.  */
+   objc-property-declaration:
+     '@property' objc-property-attributes[opt] struct-declaration ;
 
+   objc-property-attributes:
+    '(' objc-property-attribute-list ')'
+
+   objc-property-attribute-list:
+     objc-property-attribute
+     objc-property-attribute-list, objc-property-attribute
+
+   objc-property-attribute
+     'getter' = identifier
+     'setter' = identifier
+     'readonly'
+     'readwrite'
+     'assign'
+     'retain'
+     'copy'
+     'nonatomic'
+
+  For example:
+    @property NSString *name;
+    @property (readonly) id object;
+    @property (retain, nonatomic, getter=getTheName) id name;
+    @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.  */
 static void
-c_parser_objc_property_attrlist (c_parser *parser)
+c_parser_objc_at_property_declaration (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);
+  tree properties;
+  location_t loc;
+  loc = c_parser_peek_token (parser)->location;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY));
 
-  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
-    return;
+  c_parser_consume_token (parser);  /* Eat '@property'.  */
 
-  /* 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)
+  /* 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))
     {
-      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)
+      /* Eat the '(' */
+      c_parser_consume_token (parser);
+      
+      /* Property attribute keywords are valid now.  */
+      parser->objc_property_attr_context = true;
+
+      while (true)
        {
-         tree ident;
-         objc_property_attribute_kind pkind;
-         case RID_READONLY:
-           objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
+         bool syntax_error = false;
+         c_token *token = c_parser_peek_token (parser);
+         enum rid keyword;
+
+         if (token->type != CPP_KEYWORD)
+           {
+             if (token->type == CPP_CLOSE_PAREN)
+               c_parser_error (parser, "expected identifier");
+             else
+               {
+                 c_parser_consume_token (parser);
+                 c_parser_error (parser, "unknown property attribute");
+               }
+             break;
+           }
+         keyword = token->keyword;
+         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_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 %<=%>");
+                 syntax_error = true;
+                 break;
+               }
+             c_parser_consume_token (parser); /* eat the = */
+             if (c_parser_next_token_is_not (parser, CPP_NAME))
+               {
+                 c_parser_error (parser, "expected identifier");
+                 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;
+                   }
+                 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
+               {
+                 c_parser_consume_token (parser);
+                 c_parser_error (parser, "unknown property attribute");
+               }
+             syntax_error = true;
+             break;
+           }
+
+         if (syntax_error)
            break;
-         case RID_GETTER:
-         case RID_SETTER:
-         case RID_IVAR:
+         
+         if (c_parser_next_token_is (parser, CPP_COMMA))
            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;
+         else
            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);
+      parser->objc_property_attr_context = false;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  /* ... and the property declaration(s).  */
+  properties = c_parser_struct_declaration (parser);
 
-  /* Comma-separated properties are chained together in
-     reverse order; add them one by one.  */
-  props = nreverse (props);
+  if (properties == error_mark_node)
+    {
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+      parser->error = false;
+      return;
+    }
 
-  for (; props; props = TREE_CHAIN (props))
-    objc_add_property_variable (copy_node (props));
+  if (properties == NULL_TREE)
+    c_parser_error (parser, "expected identifier");
+  else
+    {
+      /* Comma-separated properties are chained together in
+        reverse order; add them one by one.  */
+      properties = nreverse (properties);
+      
+      for (; properties; properties = TREE_CHAIN (properties))
+       objc_add_property_declaration (loc, copy_node (properties));
+    }
 
   c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+  parser->error = false;
 }
 
 /* Parse an Objective-C @synthesize declaration.  The syntax is:
index 94acfbc..582e5c8 100644 (file)
@@ -1,3 +1,26 @@
+2010-10-27  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
+       missing or invalid declspecs.  Implemented attributes.  Do not eat
+       the ';' at the end.  Exit loop whenever a non-comma is parsed, not
+       just EOF.
+       (cp_parser_objc_at_property): Renamed to
+       cp_parser_objc_at_property_declaration.  Updated calls to
+       objc_add_property_variable, now objc_add_property_declaration, and
+       to cp_parser_objc_property_decl, now
+       cp_parser_objc_struct_declaration.  Rewritten all code to be more
+       robust in dealing with syntax errors, and almost identical to the
+       one in c_parser_objc_at_property_declaration.
+       (cp_parser_objc_property_attrlist): Removed.
+       (cp_parser_objc_method_prototype_list): Updated call to
+       cp_parser_objc_at_property.
+       (cp_parser_objc_method_definition_list): Same change.
+       (cp_parser_objc_class_ivars): Detect a number of invalid
+       declarations of instance variables and produce errors when they
+       are found.
+       
 2010-10-26  Jason Merrill  <jason@redhat.com>
 
        * tree.c (build_vec_init_expr): Split out from...
index 8ea805d..95be6d3 100644 (file)
@@ -2098,13 +2098,13 @@ static tree cp_parser_objc_statement
   (cp_parser *);
 static bool cp_parser_objc_valid_prefix_attributes
   (cp_parser *, tree *);
-static void cp_parser_objc_at_property 
+static void cp_parser_objc_at_property_declaration 
   (cp_parser *) ;
 static void cp_parser_objc_at_synthesize_declaration 
   (cp_parser *) ;
 static void cp_parser_objc_at_dynamic_declaration
   (cp_parser *) ;
-static void cp_parser_objc_property_decl 
+static tree cp_parser_objc_struct_declaration
   (cp_parser *) ;
 
 /* Utility Routines */
@@ -21930,7 +21930,7 @@ cp_parser_objc_method_prototype_list (cp_parser* parser)
          cp_parser_consume_semicolon_at_end_of_statement (parser);
        }
       else if (token->keyword == RID_AT_PROPERTY)
-       cp_parser_objc_at_property (parser);
+       cp_parser_objc_at_property_declaration (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, 
@@ -21997,8 +21997,10 @@ cp_parser_objc_method_definition_list (cp_parser* parser)
              objc_finish_method_definition (meth);
            }
        }
+      /* The following case will be removed once @synthesize is
+        completely implemented.  */
       else if (token->keyword == RID_AT_PROPERTY)
-       cp_parser_objc_at_property (parser);
+       cp_parser_objc_at_property_declaration (parser);
       else if (token->keyword == RID_AT_SYNTHESIZE)
        cp_parser_objc_at_synthesize_declaration (parser);
       else if (token->keyword == RID_AT_DYNAMIC)
@@ -22051,6 +22053,28 @@ cp_parser_objc_class_ivars (cp_parser* parser)
                                    CP_PARSER_FLAGS_OPTIONAL,
                                    &declspecs,
                                    &decl_class_or_enum_p);
+
+      /* auto, register, static, extern, mutable.  */
+      if (declspecs.storage_class != sc_none)
+       {
+         cp_parser_error (parser, "invalid type for instance variable");         
+         declspecs.storage_class = sc_none;
+       }
+
+      /* __thread.  */
+      if (declspecs.specs[(int) ds_thread])
+       {
+         cp_parser_error (parser, "invalid type for instance variable");
+         declspecs.specs[(int) ds_thread] = 0;
+       }
+      
+      /* typedef.  */
+      if (declspecs.specs[(int) ds_typedef])
+       {
+         cp_parser_error (parser, "invalid type for instance variable");
+         declspecs.specs[(int) ds_typedef] = 0;
+       }
+
       prefix_attributes = declspecs.attributes;
       declspecs.attributes = NULL_TREE;
 
@@ -22496,144 +22520,275 @@ cp_parser_objc_valid_prefix_attributes (cp_parser* parser, tree *attrib)
   return false;  
 }
 
-/* This routine parses the propery declarations. */
+/* This routine is a minimal replacement for
+   c_parser_struct_declaration () used when parsing the list of
+   types/names or ObjC++ properties.  For example, when parsing the
+   code
 
-static void
-cp_parser_objc_property_decl (cp_parser *parser)
+   @property (readonly) int a, b, c;
+
+   this function is responsible for parsing "int a, int b, int c" and
+   returning the declarations as CHAIN of DECLs.
+
+   TODO: Share this code with cp_parser_objc_class_ivars.  It's very
+   similar parsing.  */
+static tree
+cp_parser_objc_struct_declaration (cp_parser *parser)
 {
-  int declares_class_or_enum;
+  tree decls = NULL_TREE;
   cp_decl_specifier_seq declspecs;
+  int decl_class_or_enum_p;
+  tree prefix_attributes;
 
   cp_parser_decl_specifier_seq (parser,
-                                CP_PARSER_FLAGS_NONE,
-                                &declspecs,
-                                &declares_class_or_enum);
+                               CP_PARSER_FLAGS_NONE,
+                               &declspecs,
+                               &decl_class_or_enum_p);
+
+  if (declspecs.type == error_mark_node)
+    return error_mark_node;
+
+  /* auto, register, static, extern, mutable.  */
+  if (declspecs.storage_class != sc_none)
+    {
+      cp_parser_error (parser, "invalid type for property");
+      declspecs.storage_class = sc_none;
+    }
+  
+  /* __thread.  */
+  if (declspecs.specs[(int) ds_thread])
+    {
+      cp_parser_error (parser, "invalid type for property");
+      declspecs.specs[(int) ds_thread] = 0;
+    }
+  
+  /* typedef.  */
+  if (declspecs.specs[(int) ds_typedef])
+    {
+      cp_parser_error (parser, "invalid type for property");
+      declspecs.specs[(int) ds_typedef] = 0;
+    }
+
+  prefix_attributes = declspecs.attributes;
+  declspecs.attributes = NULL_TREE;
+
   /* 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;
+      tree attributes, first_attribute, decl;
+      cp_declarator *declarator;
       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));
+      /* Parse the declarator.  */
+      declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+                                        NULL, NULL, false);
+
+      /* Look for attributes that apply to the ivar.  */
+      attributes = cp_parser_attributes_opt (parser);
+      /* Remember which attributes are prefix attributes and
+        which are not.  */
+      first_attribute = attributes;
+      /* Combine the attributes.  */
+      attributes = chainon (prefix_attributes, attributes);
+      
+      decl = grokfield (declarator, &declspecs,
+                       NULL_TREE, /*init_const_expr_p=*/false,
+                       NULL_TREE, attributes);
+
+      if (decl == error_mark_node || decl == NULL_TREE)
+       return error_mark_node;
+      
+      /* Reset PREFIX_ATTRIBUTES.  */
+      while (attributes && TREE_CHAIN (attributes) != first_attribute)
+       attributes = TREE_CHAIN (attributes);
+      if (attributes)
+       TREE_CHAIN (attributes) = NULL_TREE;
+
+      DECL_CHAIN (decl) = decls;
+      decls = decl;
+
       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)
+      else
        break;
     }
-  /* Eat ';' if present, or issue an error.  */
-  cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+  return decls;
 }
 
-/* ObjC @property. */
-/* Parse a comma-separated list of property attributes.  
-   The lexer does not recognize */
+/* Parse an Objective-C @property declaration.  The syntax is:
+
+   objc-property-declaration:
+     '@property' objc-property-attributes[opt] struct-declaration ;
+
+   objc-property-attributes:
+    '(' objc-property-attribute-list ')'
+
+   objc-property-attribute-list:
+     objc-property-attribute
+     objc-property-attribute-list, objc-property-attribute
+
+   objc-property-attribute
+     'getter' = identifier
+     'setter' = identifier
+     'readonly'
+     'readwrite'
+     'assign'
+     'retain'
+     'copy'
+     'nonatomic'
+
+  For example:
+    @property NSString *name;
+    @property (readonly) id object;
+    @property (retain, nonatomic, getter=getTheName) id name;
+    @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.  */
 static void 
-cp_parser_objc_property_attrlist (cp_parser *parser)
+cp_parser_objc_at_property_declaration (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);
+  tree properties;
+  location_t loc;
+  loc = cp_lexer_peek_token (parser->lexer)->location;
 
-  /* The list is optional.  */
-  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
-    return;
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@property'.  */
 
-  /* Eat the '('.  */
-  cp_lexer_consume_token (parser->lexer);
+  /* Initialize attributes to an empty list.  */
+  objc_set_property_attr (loc, OBJC_PATTR_INIT, NULL_TREE);
 
-  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])
+  /* Parse the optional attribute list...  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      /* Eat the '('.  */
+      cp_lexer_consume_token (parser->lexer);
+
+      while (true)
        {
-         /* Do the getter/setter/ivar attribute. */
-         token = cp_lexer_consume_token (parser->lexer);
-         if (token->type == CPP_EQ)
+         bool syntax_error = false;
+         cp_token *token = cp_lexer_peek_token (parser->lexer);
+         enum rid keyword;
+
+         if (token->type != CPP_NAME)
            {
-             tree attr_ident = cp_parser_identifier (parser);
+             cp_parser_error (parser, "expected identifier");
+             break;
+           }
+         keyword = C_RID_CODE (token->u.value);
+         switch (keyword)
+           {
+             tree ident;
              objc_property_attribute_kind pkind;
-             if (node == ridpointers [(int) RID_GETTER])
-               pkind = OBJC_PATTR_GETTER;
-             else if (node == ridpointers [(int) RID_SETTER])
+           case RID_READONLY:
+             cp_lexer_consume_token (parser->lexer);
+             objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
+             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,
+                                  "getter/setter/ivar attribute must be followed by %<=%>");
+                 syntax_error = true;
+                 break;
+               }
+             cp_lexer_consume_token (parser->lexer); /* eat the = */
+             if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+               {
+                 cp_parser_error (parser, "expected identifier");
+                 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;
-                 /* 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
+                 /* Eat the identifier, and look for the following : */
+                 if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
                    {
-                     error_at (token->location,
-                               "setter name must be followed by %<:%>");
+                     cp_parser_error (parser,
+                                     "setter name must be followed by %<:%>");
+                     syntax_error = true;
                      break;
                    }
+                 cp_lexer_consume_token (parser->lexer);
                }
-             else 
+             else if (keyword == RID_GETTER)
+               pkind = OBJC_PATTR_GETTER;
+             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 %<=%>");
+             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
+               {
+                 cp_lexer_consume_token (parser->lexer);
+                 cp_parser_error (parser, "unknown property attribute");
+               }
+             syntax_error = true;
              break;
            }
+
+         if (syntax_error)
+           break;
+         
+         if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+           cp_lexer_consume_token (parser->lexer);
+         else
+           break;
        }
-      else if (node == ridpointers [(int) RID_COPIES])
-       objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE);
-      else
+
+      if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
        {
-         error_at (token->location,"unknown property attribute");
-         break;
+         cp_parser_skip_to_closing_parenthesis (parser,
+                                                /*recovering=*/true,
+                                                /*or_comma=*/false,
+                                                /*consume_paren=*/true);
        }
-      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. */
+  /* ... and the property declaration(s).  */
+  properties = cp_parser_objc_struct_declaration (parser);
 
-static void 
-cp_parser_objc_at_property (cp_parser *parser)
-{
-  /* Consume @property */
-  cp_lexer_consume_token (parser->lexer);
+  if (properties == error_mark_node)
+    {
+      cp_parser_skip_to_end_of_statement (parser);
+      /* If the next token is now a `;', consume it.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+       cp_lexer_consume_token (parser->lexer);
+      return;
+    }
 
-  /* Parse optional attributes list...  */
-  cp_parser_objc_property_attrlist (parser);
-  /* ... and the property declaration(s).  */
-  cp_parser_objc_property_decl (parser);
+  if (properties == NULL_TREE)
+    cp_parser_error (parser, "expected identifier");
+  else
+    {
+      /* Comma-separated properties are chained together in
+        reverse order; add them one by one.  */
+      properties = nreverse (properties);
+      
+      for (; properties; properties = TREE_CHAIN (properties))
+       objc_add_property_declaration (loc, copy_node (properties));
+    }
+  
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
 }
 
 /* Parse an Objective-C++ @synthesize declaration.  The syntax is:
index 9e79359..de29539 100644 (file)
@@ -1,3 +1,11 @@
+2010-10-27  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
+       property declaration is found outside an interface or
+       implementation context.
+       
 2010-10-24  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        * objc-act.c (objc_build_keyword_decl): Updated comments.  Do not
index 242fe17..efdf17f 100644 (file)
@@ -871,7 +871,7 @@ objc_set_property_attr (location_t loc, objc_property_attribute_kind attr,
 */
 
 void
-objc_add_property_variable (tree decl)
+objc_add_property_declaration (location_t location, tree decl)
 {
   tree property_decl;
   tree x;
@@ -882,7 +882,7 @@ objc_add_property_variable (tree decl)
       interface = lookup_interface (CLASS_NAME (objc_implementation_context));
       if (!interface)
        {
-         error ("no class property can be implemented without an interface");
+         error_at (location, "no class property can be implemented without an interface");
          return;
        }
       if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)
@@ -891,14 +891,14 @@ objc_add_property_variable (tree decl)
                                     CLASS_SUPER_NAME (objc_implementation_context));   
          if (!interface)
            {
-             error ("no category property can be implemented without an interface");
+             error_at (location, "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");
+      error_at (location, "property declaration not in @interface or @implementation context");
       return;
     }
 
@@ -923,13 +923,13 @@ objc_add_property_variable (tree decl)
       /* 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);
+       error_at (location, "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);
+             error_at (location, "duplicate property declaration %qD", decl);
              return;
            }
        }
@@ -945,26 +945,26 @@ objc_add_property_variable (tree decl)
          break;
       if (!x)
        {
-         error ("no declaration of property %qD found in the interface", decl);
+         error_at (location, "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);
+         error_at (location, "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);
+         error_at (location, "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)");
+         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. */
index 96e557f..2a82488 100644 (file)
@@ -1,3 +1,16 @@
+2010-10-27  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.
+       * objc.dg/ivar-invalid-type-1.m: New.
+       * obj-c++.dg/property/at-property-1.mm: New.
+       * obj-c++.dg/property/at-property-2.mm: New.
+       * obj-c++.dg/property/at-property-3.mm: New.    
+       * obj-c++.dg/ivar-invalid-type-1.mm: New.
+       * objc.dg/property/property-neg-6.m: Updated testcase for updates
+       in error reporting.
+
 2010-10-26  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
 
        PR libgfortran/46010
diff --git a/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm b/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm
new file mode 100644 (file)
index 0000000..bd2094a
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@end
+
+@interface MySubClass
+{
+  volatile int a;  /* This is allowed */
+  extern int b;    /* { dg-error "invalid type" } */
+  static int c;    /* { dg-error "invalid type" } */
+  inline int d;    /* { dg-error "declared as an .inline." } */
+  typedef int e;   /* { dg-error "invalid type" } */
+  __thread int f;  /* dg-error "invalid type" */ /* FIXME: The compiler generates this message, but the testsuite does not match it.  */
+}
+@end
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-1.mm b/gcc/testsuite/obj-c++.dg/property/at-property-1.mm
new file mode 100644 (file)
index 0000000..c3be5d8
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property;                      /* { dg-error "expected identifier" } */
+@property int;                  /* { dg-error "expected identifier" } */
+@property int a;
+@property int b, c;
+@property () int d;             /* { dg-error "expected identifier" } */
+@property (readonly) int e;
+@property (readonly,) int f;    /* { dg-error "expected identifier" } */
+@property (xxx) int g;          /* { dg-error "unknown property attribute" } */
+@property (readonly,xxx) int h; /* { dg-error "unknown property attribute" } */
+/* FIXME - there is a problem with the testuite in running the following test.  The compiler
+   generates the messages, but the testsuite still complains.  */
+/*@property ( int i;*/          /* dg-error "unknown property attribute" */
+                                /* dg-error "expected ... "       "" { target *-*-* } 18 */
+                                /* dg-error "expected identfier " "" { target *-*-* } 18 */
+@end
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-2.mm b/gcc/testsuite/obj-c++.dg/property/at-property-2.mm
new file mode 100644 (file)
index 0000000..7442251
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property id name __attribute__((deprecated));
+@property id table __attribute__((xxx));        /* { dg-warning ".xxx. attribute directive ignored" } */
+@property void function (void);                 /* { dg-error "can.t make .function. into a method" } */
+@property typedef int j;                        /* { dg-error "invalid type for property" } */
+@end
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-3.mm b/gcc/testsuite/obj-c++.dg/property/at-property-3.mm
new file mode 100644 (file)
index 0000000..adf4dd0
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property volatile int a;  /* This is allowed */
+@property extern int b;    /* { dg-error "invalid type" } */
+@property static int c;    /* { dg-error "invalid type" } */
+@property inline int d;    /* { dg-error "declared as an .inline." } */
+@property typedef int e;   /* { dg-error "invalid type" } */
+@property __thread int f;  /* { dg-error "invalid type" } */
+@end
diff --git a/gcc/testsuite/objc.dg/ivar-invalid-type-1.m b/gcc/testsuite/objc.dg/ivar-invalid-type-1.m
new file mode 100644 (file)
index 0000000..3e7785d
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@end
+
+@interface MySubClass
+{
+  volatile int a;  /* This is allowed */
+  extern int b;    /* { dg-error "expected" } */
+  static int c;    /* { dg-error "expected" } */
+  inline int d;    /* { dg-error "expected" } */
+  typedef int e;   /* { dg-error "expected" } */
+  __thread int f;  /* { dg-error "expected" } */
+}
+@end
diff --git a/gcc/testsuite/objc.dg/property/at-property-1.m b/gcc/testsuite/objc.dg/property/at-property-1.m
new file mode 100644 (file)
index 0000000..4ff269d
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property;                      /* { dg-error "expected" } */
+@property int;                  /* { dg-error "expected identifier" } */
+                                /* { dg-warning "declaration does not declare anything" "" { target *-*-* } 10 } */
+@property int a;
+@property int b, c;
+@property () int d;             /* { dg-error "expected identifier" } */
+@property (readonly) int e;
+@property (readonly,) int f;    /* { dg-error "expected identifier" } */
+@property (xxx) int g;          /* { dg-error "unknown property attribute" } */
+@property (readonly,xxx) int h; /* { dg-error "unknown property attribute" } */
+@property ( int i;              /* { dg-error "unknown property attribute" } */
+/* Because the last syntax error opens a '(' and never closes it, we get to the end of input.  */
+@end                            /* { dg-error "expected ..end. at end of input" } */
diff --git a/gcc/testsuite/objc.dg/property/at-property-2.m b/gcc/testsuite/objc.dg/property/at-property-2.m
new file mode 100644 (file)
index 0000000..23bd485
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property id name __attribute__((deprecated));
+@property id table __attribute__((xxx));        /* { dg-warning ".xxx. attribute directive ignored" } */
+@property void function (void);                 /* { dg-error "declared as a function" } */
+@property typedef int j;                        /* { dg-error "expected" } */
+@end
diff --git a/gcc/testsuite/objc.dg/property/at-property-3.m b/gcc/testsuite/objc.dg/property/at-property-3.m
new file mode 100644 (file)
index 0000000..70b522c
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property volatile int a;  /* This is allowed */
+@property extern int b;    /* { dg-error "expected" } */
+@property static int c;    /* { dg-error "expected" } */
+@property inline int d;    /* { dg-error "expected" } */
+@property typedef int e;   /* { dg-error "expected" } */
+@property __thread int f;  /* { dg-error "expected" } */
+@end
index 335fe1d..7059a56 100644 (file)
@@ -6,3 +6,4 @@
   int iVar;
 }
 @property int FooBar /* { dg-error "expected ':', ',', ';', '\}' or '__attribute__' at end of input" } */
+/* { dg-error "expected ..end. at end of input" "" { target *-*-* } 8 } */