From f614132bc795c4773957e0d7fec7ee9dfd127274 Mon Sep 17 00:00:00 2001 From: Nicola Pero Date: Wed, 27 Oct 2010 04:37:47 +0000 Subject: [PATCH] In gcc/: 2010-10-27 Nicola Pero In gcc/: 2010-10-27 Nicola Pero * 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 * 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 * 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 * 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 * 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. From-SVN: r165996 --- gcc/ChangeLog | 13 + gcc/c-family/ChangeLog | 6 + gcc/c-family/c-common.h | 2 +- gcc/c-family/stub-objc.c | 2 +- gcc/c-parser.c | 272 +++++++++------- gcc/cp/ChangeLog | 23 ++ gcc/cp/parser.c | 349 +++++++++++++++------ gcc/objc/ChangeLog | 8 + gcc/objc/objc-act.c | 24 +- gcc/testsuite/ChangeLog | 13 + gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm | 19 ++ gcc/testsuite/obj-c++.dg/property/at-property-1.mm | 23 ++ gcc/testsuite/obj-c++.dg/property/at-property-2.mm | 13 + gcc/testsuite/obj-c++.dg/property/at-property-3.mm | 15 + gcc/testsuite/objc.dg/ivar-invalid-type-1.m | 19 ++ gcc/testsuite/objc.dg/property/at-property-1.m | 21 ++ gcc/testsuite/objc.dg/property/at-property-2.m | 13 + gcc/testsuite/objc.dg/property/at-property-3.m | 15 + gcc/testsuite/objc.dg/property/property-neg-6.m | 1 + 19 files changed, 627 insertions(+), 224 deletions(-) create mode 100644 gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-1.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-2.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/at-property-3.mm create mode 100644 gcc/testsuite/objc.dg/ivar-invalid-type-1.m create mode 100644 gcc/testsuite/objc.dg/property/at-property-1.m create mode 100644 gcc/testsuite/objc.dg/property/at-property-2.m create mode 100644 gcc/testsuite/objc.dg/property/at-property-3.m diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3686a295f6b..22fb34a4c27 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2010-10-27 Nicola Pero + + * 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 * config/i386/i386.md (split_stack_return): Put back diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index b73e45a8f54..d742912f8ab 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2010-10-27 Nicola Pero + + * 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 * c-common.h (objc_maybe_printable_name): New. diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 8031bb44a34..55637659946 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -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); diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c index f808dc76f6b..fb92c7fc0bb 100644 --- a/gcc/c-family/stub-objc.c +++ b/gcc/c-family/stub-objc.c @@ -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)) { } diff --git a/gcc/c-parser.c b/gcc/c-parser.c index e4efd38cac6..c885c8a9610 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -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: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 94acfbc8966..582e5c871e0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2010-10-27 Nicola Pero + + * 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 * tree.c (build_vec_init_expr): Split out from... diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8ea805d6c37..95be6d324b9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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: diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 9e79359eae8..de29539c575 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,11 @@ +2010-10-27 Nicola Pero + + * 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 * objc-act.c (objc_build_keyword_decl): Updated comments. Do not diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 242fe174d75..efdf17f709e 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -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 % attribute conflicts with its" - " interface version", decl); + error_at (location, "property %qD % attribute conflicts with its" + " interface version", decl); } /* copies must also match. */ if (PROPERTY_COPIES (x) != PROPERTY_COPIES (property_decl)) { - error ("property %qD % attribute conflicts with its" - " interface version", decl); + error_at (location, "property %qD % 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 % property cannot have a setter (ignored)"); + warning_at (location, 0, "a % property cannot have a setter (ignored)"); PROPERTY_SETTER_NAME (property_decl) = NULL_TREE; } /* Add the property to the list of properties for current implementation. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 96e557f6955..2a824880995 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2010-10-27 Nicola Pero + + * 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 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 index 00000000000..bd2094ade07 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +#include + +@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 index 00000000000..c3be5d81c2e --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-1.mm @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +#include + +@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 index 00000000000..7442251377a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-2.mm @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +#include + +@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 index 00000000000..adf4dd0366b --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-3.mm @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +#include + +@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 index 00000000000..3e7785db86f --- /dev/null +++ b/gcc/testsuite/objc.dg/ivar-invalid-type-1.m @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +#include + +@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 index 00000000000..4ff269d0f5a --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-1.m @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include + +@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 index 00000000000..23bd4850310 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-2.m @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +#include + +@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 index 00000000000..70b522cbabf --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-3.m @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +#include + +@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 diff --git a/gcc/testsuite/objc.dg/property/property-neg-6.m b/gcc/testsuite/objc.dg/property/property-neg-6.m index 335fe1dee3f..7059a56f094 100644 --- a/gcc/testsuite/objc.dg/property/property-neg-6.m +++ b/gcc/testsuite/objc.dg/property/property-neg-6.m @@ -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 } */ -- 2.11.4.GIT