===================================================================
@@ -1,3 +1,9 @@
+2010-10-25 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_add_property_variable): Renamed to
+ objc_add_property_declaration. Added location argument.
+ * stub-objc.c (objc_add_property_variable): Same change.
+
2010-10-23 Nicola Pero <nicola.pero@meta-innovation.com>
* c-common.h (objc_maybe_printable_name): New.
===================================================================
@@ -1043,7 +1043,7 @@ extern void objc_finish_foreach_loop (location_t,
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);
===================================================================
@@ -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))
{
}
===================================================================
@@ -871,7 +871,7 @@ objc_set_property_attr (location_t loc, objc_prope
*/
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 @@ void
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 @@ void
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 @@ void
/* 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 @@ void
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. */
===================================================================
@@ -1,3 +1,11 @@
+2010-10-25 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc-act.c (objc_add_property_variable): Renamed to
+ objc_add_property_declaration. Added location argument. Updated
+ warnings and errors to use it. Use error, not fatal_error, if a
+ 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
===================================================================
@@ -1,3 +1,16 @@
+2010-10-25 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-parser.c (c_parser_objc_at_property): Renamed to
+ c_parser_objc_at_property_declaration. Updated calls to
+ objc_add_property_variable, now objc_add_property_declaration.
+ 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-25 Eric Botcazou <ebotcazou@adacore.com>
* configure.ac: Use $cpu_type instead of $target to define the nop.
===================================================================
@@ -1,3 +1,16 @@
+2010-10-25 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc.dg/property/at-property-1.m: New.
+ * objc.dg/property/at-property-2.m: New.
+ * objc.dg/property/at-property-3.m: New.
+ * 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-25 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/in_out_parameter2.adb: New test.
===================================================================
@@ -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" } */
===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -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 } */
===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -1,3 +1,26 @@
+2010-10-25 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * parser.c (cp_parser_objc_property_decl): Renamed to
+ cp_parser_objc_struct_declaration. Return the parsed trees
+ instead of calling objc_add_property_variable directly. Detect
+ 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-24 Nicola Pero <nicola.pero@meta-innovation.com>
Removed Objective-C++ specific replacement of cxx_printable_name.
===================================================================
@@ -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 */
@@ -21752,7 +21752,7 @@ cp_parser_objc_method_prototype_list (cp_parser* p
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,
@@ -21819,8 +21819,10 @@ cp_parser_objc_method_definition_list (cp_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)
@@ -21873,6 +21875,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;
@@ -22318,146 +22342,277 @@ cp_parser_objc_valid_prefix_attributes (cp_parser*
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)
+ /* Parse the optional attribute list... */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
- 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])
+ /* 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);
+ 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
- {
- error_at (token->location,
- "getter/setter/ivar attribute must be followed by %<=%>");
- break;
- }
+ 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))
+ }
+
+ /* ... and the property declaration(s). */
+ properties = cp_parser_objc_struct_declaration (parser);
+
+ 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);
- 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);
+ return;
}
- if (token->type != CPP_CLOSE_PAREN)
- error_at (token->location,
- "syntax error in @property's attribute declaration");
+ if (properties == NULL_TREE)
+ cp_parser_error (parser, "expected identifier");
else
- /* Consume ')' */
- cp_lexer_consume_token (parser->lexer);
+ {
+ /* 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);
}
-/* 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);
-}
-
/* Parse an Objective-C++ @synthesize declaration. The syntax is:
objc-synthesize-declaration:
===================================================================
@@ -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_parse
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)
+ /* Eat the '(' */
+ c_parser_consume_token (parser);
+
+ /* Property attribute keywords are valid now. */
+ parser->objc_property_attr_context = true;
+
+ while (true)
{
- 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);
+ 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);
+ else
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;
+ 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);
- 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 %<)%>");
-}
+ if (properties == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ parser->error = false;
+ return;
+ }
-/* Parse property attributes and then the definition. */
+ 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));
+ }
-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 %<;%>");
+ parser->error = false;
}
/* Parse an Objective-C @synthesize declaration. The syntax is: