diff --git a/gcc/c-family/c-objc.h b/gcc/c-family/c-objc.h index 4577e4f1c7f570579a0063b6a32decd1f5a1ae0d..a2ca112dcc6cfb731cf61a74edd50f95d564f464 100644 --- a/gcc/c-family/c-objc.h +++ b/gcc/c-family/c-objc.h @@ -28,6 +28,67 @@ enum GTY(()) objc_ivar_visibility_kind { OBJC_IVAR_VIS_PACKAGE = 3 }; +/* ObjC property attribute kinds. + These have two fields; a unique value (that identifies which attribute) + and a group key that indicates membership of an exclusion group. + Only one member may be present from an exclusion group in a given attribute + list. + getters and setters have additional rules, since they are excluded from + non-overlapping group sets. */ + +enum objc_property_attribute_group +{ + OBJC_PROPATTR_GROUP_UNKNOWN = 0, + OBJC_PROPATTR_GROUP_GETTER, + OBJC_PROPATTR_GROUP_SETTER, + OBJC_PROPATTR_GROUP_READWRITE, + OBJC_PROPATTR_GROUP_ASSIGN, + OBJC_PROPATTR_GROUP_ATOMIC, + OBJC_PROPATTR_GROUP_MAX +}; + +enum objc_property_attribute_kind +{ + OBJC_PROPERTY_ATTR_UNKNOWN = 0|OBJC_PROPATTR_GROUP_UNKNOWN, + OBJC_PROPERTY_ATTR_GETTER = ( 1 << 8)|OBJC_PROPATTR_GROUP_GETTER, + OBJC_PROPERTY_ATTR_SETTER = ( 2 << 8)|OBJC_PROPATTR_GROUP_SETTER, + OBJC_PROPERTY_ATTR_READONLY = ( 3 << 8)|OBJC_PROPATTR_GROUP_READWRITE, + OBJC_PROPERTY_ATTR_READWRITE = ( 4 << 8)|OBJC_PROPATTR_GROUP_READWRITE, + OBJC_PROPERTY_ATTR_ASSIGN = ( 5 << 8)|OBJC_PROPATTR_GROUP_ASSIGN, + OBJC_PROPERTY_ATTR_RETAIN = ( 6 << 8)|OBJC_PROPATTR_GROUP_ASSIGN, + OBJC_PROPERTY_ATTR_COPY = ( 7 << 8)|OBJC_PROPATTR_GROUP_ASSIGN, + OBJC_PROPERTY_ATTR_ATOMIC = ( 8 << 8)|OBJC_PROPATTR_GROUP_ATOMIC, + OBJC_PROPERTY_ATTR_NONATOMIC = ( 9 << 8)|OBJC_PROPATTR_GROUP_ATOMIC, + OBJC_PROPERTY_ATTR_MAX = (255 << 8|OBJC_PROPATTR_GROUP_MAX) +}; + +#define OBJC_PROPATTR_GROUP_MASK 0x0f + +/* To contain parsed, but unverified, information about a single property + attribute. */ +struct property_attribute_info +{ + property_attribute_info () = default; + property_attribute_info (tree name, location_t loc, + enum objc_property_attribute_kind k) + : name (name), ident (NULL_TREE), prop_loc (loc), prop_kind (k), + parse_error (false) {} + + enum objc_property_attribute_group group () + { + return (enum objc_property_attribute_group) + ((unsigned)prop_kind & OBJC_PROPATTR_GROUP_MASK); + } + + tree name; /* Name of the attribute. */ + tree ident; /* For getter/setter cases, the method/selector name. */ + location_t prop_loc; /* Extended location covering the parsed attr. */ + enum objc_property_attribute_kind prop_kind : 16; + unsigned parse_error : 1; /* The C/C++ parser saw an error in this attr. */ +}; + +extern enum objc_property_attribute_kind objc_prop_attr_kind_for_rid (enum rid); + /* Objective-C / Objective-C++ entry points. */ /* The following ObjC/ObjC++ functions are called by the C and/or C++ @@ -90,8 +151,8 @@ extern tree objc_generate_write_barrier (tree, enum tree_code, tree); extern void objc_set_method_opt (bool); extern void objc_finish_foreach_loop (location_t, tree, tree, tree, tree, tree); extern bool objc_method_decl (enum tree_code); -extern void objc_add_property_declaration (location_t, tree, bool, bool, bool, - bool, bool, bool, tree, tree); +extern void objc_add_property_declaration (location_t, tree, + vec<property_attribute_info *>&); extern tree objc_maybe_build_component_ref (tree, tree); extern tree objc_build_class_component_ref (tree, tree); extern tree objc_maybe_build_modify_expr (tree, tree); diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c index d017acfd6fe857ca5c2b491c4eef8672bf2947a3..2f535578789712c987d457cbdb319f8c9d3d8aef 100644 --- a/gcc/c-family/stub-objc.c +++ b/gcc/c-family/stub-objc.c @@ -23,6 +23,12 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tree.h" +#include "vec.h" + +/* Provide a dummy type for the RID enum used as an argument to + objc_prop_attr_kind_for_rid () */ +enum rid { DUMMY }; + #include "c-objc.h" tree @@ -314,14 +320,8 @@ objc_get_class_ivars (tree ARG_UNUSED (name)) void objc_add_property_declaration (location_t ARG_UNUSED (location), tree ARG_UNUSED (decl), - bool ARG_UNUSED (parsed_property_readonly), - bool ARG_UNUSED (parsed_property_readwrite), - bool ARG_UNUSED (parsed_property_assign), - bool ARG_UNUSED (parsed_property_retain), - bool ARG_UNUSED (parsed_property_copy), - bool ARG_UNUSED (parsed_property_nonatomic), - tree ARG_UNUSED (parsed_property_getter_ident), - tree ARG_UNUSED (parsed_property_setter_ident)) + vec<property_attribute_info *>& + /*prop_attr_list*/) { } @@ -465,3 +465,8 @@ void objc_maybe_warn_exceptions (location_t ARG_UNUSED (loc)) { } + +enum objc_property_attribute_kind objc_prop_attr_kind_for_rid (enum rid) +{ + return OBJC_PROPERTY_ATTR_UNKNOWN; +} diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index dedfb8472d0ebbf83f9121d1074d3d66033d56e9..da8278a8257c4ffc8be3d9d2ba300abc87d06f08 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -11958,158 +11958,196 @@ c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, static void c_parser_objc_at_property_declaration (c_parser *parser) { - /* The following variables hold the attributes of the properties as - parsed. They are 'false' or 'NULL_TREE' if the attribute was not - seen. When we see an attribute, we set them to 'true' (if they - are boolean properties) or to the identifier (if they have an - argument, ie, for getter and setter). Note that here we only - parse the list of attributes, check the syntax and accumulate the - attributes that we find. objc_add_property_declaration() will - then process the information. */ - bool property_assign = false; - bool property_copy = false; - tree property_getter_ident = NULL_TREE; - bool property_nonatomic = false; - bool property_readonly = false; - bool property_readwrite = false; - bool property_retain = false; - tree property_setter_ident = NULL_TREE; - - /* 'properties' is the list of properties that we read. Usually a - single one, but maybe more (eg, in "@property int a, b, c;" there - are three). */ - tree properties; - location_t loc; - - loc = c_parser_peek_token (parser)->location; gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); - + location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); /* Eat '@property'. */ - /* Parse the optional attribute list... */ + /* Parse the optional attribute list. + + A list of parsed, but not verified, attributes. */ + vec<property_attribute_info *> prop_attr_list = vNULL; + + bool syntax_error = false; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { matching_parens parens; + location_t attr_start = c_parser_peek_token (parser)->location; /* Eat the '(' */ parens.consume_open (parser); /* Property attribute keywords are valid now. */ parser->objc_property_attr_context = true; - while (true) + /* Allow @property (), with a warning. */ + location_t attr_end = c_parser_peek_token (parser)->location; + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - bool syntax_error = false; - c_token *token = c_parser_peek_token (parser); - enum rid keyword; + location_t attr_comb = make_location (attr_end, attr_start, attr_end); + warning_at (attr_comb, OPT_Wattributes, + "empty property attribute list"); + } + else + while (true) + { + c_token *token = c_parser_peek_token (parser); + attr_start = token->location; + attr_end = get_finish (token->location); + location_t attr_comb = make_location (attr_start, attr_start, + attr_end); - 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; - c_parser_consume_token (parser); - switch (keyword) - { - case RID_ASSIGN: property_assign = true; break; - case RID_COPY: property_copy = true; break; - case RID_NONATOMIC: property_nonatomic = true; break; - case RID_READONLY: property_readonly = true; break; - case RID_READWRITE: property_readwrite = true; break; - case RID_RETAIN: property_retain = true; break; - - case RID_GETTER: - case RID_SETTER: - if (c_parser_next_token_is_not (parser, CPP_EQ)) - { - if (keyword == RID_GETTER) - c_parser_error (parser, - "missing %<=%> (after %<getter%> attribute)"); - else - c_parser_error (parser, - "missing %<=%> (after %<setter%> attribute)"); - 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; + if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) + { + warning_at (attr_comb, OPT_Wattributes, + "missing property attribute"); + if (token->type == CPP_CLOSE_PAREN) break; - } - if (keyword == RID_SETTER) - { - if (property_setter_ident != NULL_TREE) - c_parser_error (parser, "the %<setter%> attribute may only be specified once"); - else - property_setter_ident = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_COLON)) - c_parser_error (parser, "setter name must terminate with %<:%>"); - else - c_parser_consume_token (parser); - } - else - { - if (property_getter_ident != NULL_TREE) - c_parser_error (parser, "the %<getter%> attribute may only be specified once"); - else - property_getter_ident = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - } - break; - default: - c_parser_error (parser, "unknown property attribute"); - syntax_error = true; - break; + c_parser_consume_token (parser); + continue; + } + + tree attr_name = NULL_TREE; + enum rid keyword = RID_MAX; /* Not a valid property attribute. */ + bool add_at = false; + if (token->type == CPP_KEYWORD) + { + keyword = token->keyword; + if (OBJC_IS_AT_KEYWORD (keyword)) + { + /* For '@' keywords the token value has the keyword, + prepend the '@' for diagnostics. */ + attr_name = token->value; + add_at = true; + } + else + attr_name = ridpointers[(int)keyword]; + } + else if (token->type == CPP_NAME) + attr_name = token->value; + c_parser_consume_token (parser); + + enum objc_property_attribute_kind prop_kind + = objc_prop_attr_kind_for_rid (keyword); + property_attribute_info *prop + = new property_attribute_info (attr_name, attr_comb, prop_kind); + prop_attr_list.safe_push (prop); + + tree meth_name; + switch (prop->prop_kind) + { + default: break; + case OBJC_PROPERTY_ATTR_UNKNOWN: + if (attr_name) + error_at (attr_comb, "unknown property attribute %<%s%s%>", + add_at ? "@" : "", IDENTIFIER_POINTER (attr_name)); + else + error_at (attr_comb, "unknown property attribute"); + prop->parse_error = syntax_error = true; + break; + + case OBJC_PROPERTY_ATTR_GETTER: + case OBJC_PROPERTY_ATTR_SETTER: + if (c_parser_next_token_is_not (parser, CPP_EQ)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %<=%> after Objective-C %qE", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + token = c_parser_peek_token (parser); + attr_end = token->location; + c_parser_consume_token (parser); /* eat the = */ + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %qE selector name", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + /* Get the end of the method name, and consume the name. */ + token = c_parser_peek_token (parser); + attr_end = get_finish (token->location); + meth_name = token->value; + c_parser_consume_token (parser); + if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER) + { + if (c_parser_next_token_is_not (parser, CPP_COLON)) + { + attr_comb = make_location (attr_end, attr_start, + attr_end); + error_at (attr_comb, "setter method names must" + " terminate with %<:%>"); + prop->parse_error = syntax_error = true; + } + else + { + attr_end = get_finish (c_parser_peek_token + (parser)->location); + c_parser_consume_token (parser); + } + attr_comb = make_location (attr_start, attr_start, + attr_end); + } + else + attr_comb = make_location (attr_start, attr_start, + attr_end); + prop->ident = meth_name; + /* Updated location including all that was successfully + parsed. */ + prop->prop_loc = attr_comb; + break; } - if (syntax_error) - break; - + /* If we see a comma here, then keep going - even if we already + saw a syntax error. For simple mistakes e.g. (asign, getter=x) + this makes a more useful output and avoid spurious warnings about + missing attributes that are, in fact, specified after the one with + the syntax error. */ if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else break; } parser->objc_property_attr_context = false; - parens.skip_until_found_close (parser); - } - /* ... and the property declaration(s). */ - properties = c_parser_struct_declaration (parser); - if (properties == error_mark_node) - { - c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); - parser->error = false; - return; + if (syntax_error && c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + /* We don't really want to chew the whole of the file looking for a + matching closing parenthesis, so we will try to read the decl and + let the error handling for that close out the statement. */ + ; + else + syntax_error = false, parens.skip_until_found_close (parser); } - if (properties == NULL_TREE) - c_parser_error (parser, "expected identifier"); + /* 'properties' is the list of properties that we read. Usually a + single one, but maybe more (eg, in "@property int a, b, c;" there + are three). */ + tree properties = c_parser_struct_declaration (parser); + + if (properties == error_mark_node) + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); 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), - property_readonly, property_readwrite, - property_assign, property_retain, - property_copy, property_nonatomic, - property_getter_ident, property_setter_ident); + 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), + prop_attr_list); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + while (!prop_attr_list.is_empty()) + delete prop_attr_list.pop (); + prop_attr_list.release (); parser->error = false; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6e7b982f073d1ae55636c6ac4be140b81e367ed4..c4c672efa09584395ee39415f8992f5e86b80d5c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -34001,30 +34001,11 @@ cp_parser_objc_struct_declaration (cp_parser *parser) static void cp_parser_objc_at_property_declaration (cp_parser *parser) { - /* The following variables hold the attributes of the properties as - parsed. They are 'false' or 'NULL_TREE' if the attribute was not - seen. When we see an attribute, we set them to 'true' (if they - are boolean properties) or to the identifier (if they have an - argument, ie, for getter and setter). Note that here we only - parse the list of attributes, check the syntax and accumulate the - attributes that we find. objc_add_property_declaration() will - then process the information. */ - bool property_assign = false; - bool property_copy = false; - tree property_getter_ident = NULL_TREE; - bool property_nonatomic = false; - bool property_readonly = false; - bool property_readwrite = false; - bool property_retain = false; - tree property_setter_ident = NULL_TREE; + /* Parse the optional attribute list. - /* 'properties' is the list of properties that we read. Usually a - single one, but maybe more (eg, in "@property int a, b, c;" there - are three). */ - tree properties; - location_t loc; - - loc = cp_lexer_peek_token (parser->lexer)->location; + A list of parsed, but not verified, attributes. */ + vec<property_attribute_info *> prop_attr_list = vNULL; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@property'. */ @@ -34033,127 +34014,172 @@ cp_parser_objc_at_property_declaration (cp_parser *parser) { /* Eat the '('. */ matching_parens parens; + location_t attr_start = cp_lexer_peek_token (parser->lexer)->location; parens.consume_open (parser); bool syntax_error = false; - while (true) + /* Allow empty @property attribute lists, but with a warning. */ + location_t attr_end = cp_lexer_peek_token (parser->lexer)->location; + location_t attr_comb; + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) { - cp_token *token = cp_lexer_peek_token (parser->lexer); - enum rid keyword; + attr_comb = make_location (attr_end, attr_start, attr_end); + warning_at (attr_comb, OPT_Wattributes, + "empty property attribute list"); + } + else + while (true) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + attr_start = token->location; + attr_end = get_finish (token->location); + attr_comb = make_location (attr_start, attr_start, attr_end); - if (token->type != CPP_NAME) - { - cp_parser_error (parser, "expected identifier"); - syntax_error = true; - break; - } - keyword = C_RID_CODE (token->u.value); - cp_lexer_consume_token (parser->lexer); - switch (keyword) - { - case RID_ASSIGN: property_assign = true; break; - case RID_COPY: property_copy = true; break; - case RID_NONATOMIC: property_nonatomic = true; break; - case RID_READONLY: property_readonly = true; break; - case RID_READWRITE: property_readwrite = true; break; - case RID_RETAIN: property_retain = true; break; - - case RID_GETTER: - case RID_SETTER: - if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) - { - if (keyword == RID_GETTER) - cp_parser_error (parser, - "missing %<=%> (after %<getter%> attribute)"); - else - cp_parser_error (parser, - "missing %<=%> (after %<setter%> attribute)"); - syntax_error = true; - break; - } - cp_lexer_consume_token (parser->lexer); /* eat the = */ - if (!cp_parser_objc_selector_p (cp_lexer_peek_token (parser->lexer)->type)) - { - cp_parser_error (parser, "expected identifier"); - syntax_error = true; + if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) + { + warning_at (attr_comb, OPT_Wattributes, + "missing property attribute"); + if (token->type == CPP_CLOSE_PAREN) break; - } - if (keyword == RID_SETTER) - { - if (property_setter_ident != NULL_TREE) - { - cp_parser_error (parser, "the %<setter%> attribute may only be specified once"); - cp_lexer_consume_token (parser->lexer); - } - else - property_setter_ident = cp_parser_objc_selector (parser); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) - cp_parser_error (parser, "setter name must terminate with %<:%>"); - else - cp_lexer_consume_token (parser->lexer); - } - else - { - if (property_getter_ident != NULL_TREE) - { - cp_parser_error (parser, "the %<getter%> attribute may only be specified once"); - cp_lexer_consume_token (parser->lexer); - } - else - property_getter_ident = cp_parser_objc_selector (parser); - } - break; - default: - cp_parser_error (parser, "unknown property attribute"); - syntax_error = true; - break; - } + cp_lexer_consume_token (parser->lexer); + continue; + } - if (syntax_error) - break; + tree attr_name = NULL_TREE; + if (identifier_p (token->u.value)) + attr_name = token->u.value; - if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + enum rid keyword; + if (token->type == CPP_NAME) + keyword = C_RID_CODE (token->u.value); + else + keyword = RID_MAX; /* By definition, an unknown property. */ cp_lexer_consume_token (parser->lexer); - else - break; - } + + enum objc_property_attribute_kind prop_kind + = objc_prop_attr_kind_for_rid (keyword); + property_attribute_info *prop + = new property_attribute_info (attr_name, attr_comb, prop_kind); + prop_attr_list.safe_push (prop); + + tree meth_name; + switch (prop->prop_kind) + { + default: break; + case OBJC_PROPERTY_ATTR_UNKNOWN: + if (attr_name) + error_at (attr_start, "unknown property attribute %qE", + attr_name); + else + error_at (attr_start, "unknown property attribute"); + prop->parse_error = syntax_error = true; + break; + + case OBJC_PROPERTY_ATTR_GETTER: + case OBJC_PROPERTY_ATTR_SETTER: + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %<=%> after Objective-C %qE", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + + token = cp_lexer_peek_token (parser->lexer); + attr_end = token->location; + cp_lexer_consume_token (parser->lexer); /* eat the = */ + + if (!cp_parser_objc_selector_p + (cp_lexer_peek_token (parser->lexer)->type)) + { + attr_comb = make_location (attr_end, attr_start, attr_end); + error_at (attr_comb, "expected %qE selector name", + attr_name); + prop->parse_error = syntax_error = true; + break; + } + + /* Get the end of the method name, and consume the name. */ + token = cp_lexer_peek_token (parser->lexer); + attr_end = get_finish (token->location); + /* Because method names may contain C++ keywords, we have a + routine to fetch them (this also consumes the token). */ + meth_name = cp_parser_objc_selector (parser); + + if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER) + { + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) + { + attr_comb = make_location (attr_end, attr_start, + attr_end); + error_at (attr_comb, "setter method names must" + " terminate with %<:%>"); + prop->parse_error = syntax_error = true; + } + else + { + attr_end = get_finish (cp_lexer_peek_token + (parser->lexer)->location); + cp_lexer_consume_token (parser->lexer); + } + attr_comb = make_location (attr_start, attr_start, + attr_end); + } + else + attr_comb = make_location (attr_start, attr_start, + attr_end); + prop->ident = meth_name; + /* Updated location including all that was successfully + parsed. */ + prop->prop_loc = attr_comb; + break; + } + + /* If we see a comma here, then keep going - even if we already + saw a syntax error. For simple mistakes e.g. (asign, getter=x) + this makes a more useful output and avoid spurious warnings + about missing attributes that are, in fact, specified after the + one with the syntax error. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else + break; + } if (syntax_error || !parens.require_close (parser)) - cp_parser_skip_to_closing_parenthesis (parser, - /*recovering=*/true, - /*or_comma=*/false, - /*consume_paren=*/true); + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); } - /* ... and the property declaration(s). */ - properties = cp_parser_objc_struct_declaration (parser); + /* 'properties' is the list of properties that we read. Usually a + single one, but maybe more (eg, in "@property int a, b, c;" there + are three). + TODO: Update this parsing so that it accepts (erroneous) bitfields so + that we can issue a meaningful and consistent (between C/C++) error + message from objc_add_property_declaration (). */ + tree 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); - return; - } - - if (properties == NULL_TREE) + cp_parser_skip_to_end_of_statement (parser); + else 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. */ + /* 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), - property_readonly, property_readwrite, - property_assign, property_retain, - property_copy, property_nonatomic, - property_getter_ident, property_setter_ident); + prop_attr_list); } cp_parser_consume_semicolon_at_end_of_statement (parser); + + while (!prop_attr_list.is_empty()) + delete prop_attr_list.pop (); + prop_attr_list.release (); } /* Parse an Objective-C++ @synthesize declaration. The syntax is: diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index c0d07ae9182ad8fa903155af43841971a69aec75..26cdeddfc5af63bf961618b6a5abcd0ae036c0a9 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -804,119 +804,74 @@ lookup_property (tree interface_type, tree property) return inter; } +/* This routine returns a PROPERTY_KIND for the front end RID code supplied. */ + +enum objc_property_attribute_kind +objc_prop_attr_kind_for_rid (enum rid prop_rid) +{ + switch (prop_rid) + { + default: return OBJC_PROPERTY_ATTR_UNKNOWN; + case RID_GETTER: return OBJC_PROPERTY_ATTR_GETTER; + case RID_SETTER: return OBJC_PROPERTY_ATTR_SETTER; + + case RID_READONLY: return OBJC_PROPERTY_ATTR_READONLY; + case RID_READWRITE: return OBJC_PROPERTY_ATTR_READWRITE; + + case RID_ASSIGN: return OBJC_PROPERTY_ATTR_ASSIGN; + case RID_RETAIN: return OBJC_PROPERTY_ATTR_RETAIN; + case RID_COPY: return OBJC_PROPERTY_ATTR_COPY; + + case RID_NONATOMIC: return OBJC_PROPERTY_ATTR_NONATOMIC; + + } +} + /* This routine is called by the parser when a @property... declaration is found. 'decl' is the declaration of the property (type/identifier), and the other arguments represent property attributes that may have been specified in the Objective-C declaration. 'parsed_property_readonly' is 'true' if the attribute 'readonly' was specified, and 'false' if not; similarly for the - other bool parameters. 'parsed_property_getter_ident' is NULL_TREE + other bool parameters. 'property_getter_ident' is NULL_TREE if the attribute 'getter' was not specified, and is the identifier corresponding to the specified getter if it was; similarly for - 'parsed_property_setter_ident'. */ + 'property_setter_ident'. */ void objc_add_property_declaration (location_t location, tree decl, - bool parsed_property_readonly, bool parsed_property_readwrite, - bool parsed_property_assign, bool parsed_property_retain, - bool parsed_property_copy, bool parsed_property_nonatomic, - tree parsed_property_getter_ident, tree parsed_property_setter_ident) + vec<property_attribute_info *>& prop_attr_list) { - tree property_decl; - tree x; - /* 'property_readonly' and 'property_assign_semantics' are the final - attributes of the property after all parsed attributes have been - considered (eg, if we parsed no 'readonly' and no 'readwrite', ie - parsed_property_readonly = false and parsed_property_readwrite = - false, then property_readonly will be false because the default - is readwrite). */ - bool property_readonly = false; - objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN; - bool property_extension_in_class_extension = false; - if (flag_objc1_only) - error_at (input_location, "%<@property%> is not available in Objective-C 1.0"); - - if (parsed_property_readonly && parsed_property_readwrite) - { - error_at (location, "%<readonly%> attribute conflicts with %<readwrite%> attribute"); - /* In case of conflicting attributes (here and below), after - producing an error, we pick one of the attributes and keep - going. */ - property_readonly = false; - } - else - { - if (parsed_property_readonly) - property_readonly = true; - - if (parsed_property_readwrite) - property_readonly = false; - } - - if (parsed_property_readonly && parsed_property_setter_ident) - { - error_at (location, "%<readonly%> attribute conflicts with %<setter%> attribute"); - property_readonly = false; - } - - if (parsed_property_assign && parsed_property_retain) - { - error_at (location, "%<assign%> attribute conflicts with %<retain%> attribute"); - property_assign_semantics = OBJC_PROPERTY_RETAIN; - } - else if (parsed_property_assign && parsed_property_copy) - { - error_at (location, "%<assign%> attribute conflicts with %<copy%> attribute"); - property_assign_semantics = OBJC_PROPERTY_COPY; - } - else if (parsed_property_retain && parsed_property_copy) - { - error_at (location, "%<retain%> attribute conflicts with %<copy%> attribute"); - property_assign_semantics = OBJC_PROPERTY_COPY; - } - else - { - if (parsed_property_assign) - property_assign_semantics = OBJC_PROPERTY_ASSIGN; - - if (parsed_property_retain) - property_assign_semantics = OBJC_PROPERTY_RETAIN; - - if (parsed_property_copy) - property_assign_semantics = OBJC_PROPERTY_COPY; - } + /* FIXME: we probably ought to bail out at this point. */ + error_at (location, "%<@property%> is not available in Objective-C 1.0"); + /* We must be in an interface, category, or protocol. */ if (!objc_interface_context) { - error_at (location, "property declaration not in @interface or @protocol context"); + error_at (location, "property declaration not in %<@interface%>," + " %<@protocol%> or %<category%> context"); return; } - /* At this point we know that we are either in an interface, a - category, or a protocol. */ + /* Do some spot-checks for the most obvious invalid cases. */ + + gcc_checking_assert (decl && TREE_CODE (decl) == FIELD_DECL); - /* We expect a FIELD_DECL from the parser. Make sure we didn't get - something else, as that would confuse the checks below. */ - if (TREE_CODE (decl) != FIELD_DECL) + if (decl && !DECL_NAME (decl)) { - error_at (location, "invalid property declaration"); + error_at (location, "properties must be named"); return; } - /* Do some spot-checks for the most obvious invalid types. */ - + location_t decl_loc = DECL_SOURCE_LOCATION (decl); + decl_loc = make_location (decl_loc, location, decl_loc); if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) { - error_at (location, "property cannot be an array"); + error_at (decl_loc, "property cannot be an array"); return; } - /* The C++/ObjC++ parser seems to reject the ':' for a bitfield when - parsing, while the C/ObjC parser accepts it and gives us a - FIELD_DECL with a DECL_INITIAL set. So we use the DECL_INITIAL - to check for a bitfield when doing ObjC. */ -#ifndef OBJCPLUS - if (DECL_INITIAL (decl)) + if (DECL_C_BIT_FIELD (decl)) { /* A @property is not an actual variable, but it is a way to describe a pair of accessor methods, so its type (which is @@ -925,10 +880,110 @@ objc_add_property_declaration (location_t location, tree decl, and arguments of functions cannot be bitfields). The underlying instance variable could be a bitfield, but that is a different matter. */ - error_at (location, "property cannot be a bit-field"); + error_at (decl_loc, "property cannot be a bit-field"); return; } -#endif + + /* The final results of parsing the (growing number) of property + attributes. */ + property_attribute_info *attrs[OBJC_PROPATTR_GROUP_MAX] = { nullptr }; + + tree property_getter_ident = NULL_TREE; + tree property_setter_ident = NULL_TREE; + for (unsigned pn = 0; pn < prop_attr_list.length (); ++pn) + { + if (prop_attr_list[pn]->parse_error) + continue; /* Ignore attributes known to be wrongly parsed. */ + + switch (int g = (int) prop_attr_list[pn]->group()) + { + case OBJC_PROPATTR_GROUP_UNKNOWN: + continue; + case OBJC_PROPATTR_GROUP_SETTER: + case OBJC_PROPATTR_GROUP_GETTER: + if (attrs[g]) + { + warning_at (prop_attr_list[pn]->prop_loc, OPT_Wattributes, + "multiple property %qE methods specified, the latest" + " one will be used", attrs[g]->name); + inform (attrs[g]->prop_loc, "previous specification"); + } + attrs[g] = prop_attr_list[pn]; + if (g == OBJC_PROPATTR_GROUP_SETTER) + property_setter_ident = attrs[g]->ident; + else + property_getter_ident = attrs[g]->ident; + continue; + default: + { + if (!attrs[g]) + ; + else if (attrs[g]->prop_kind != prop_attr_list[pn]->prop_kind) + { + error_at (prop_attr_list[pn]->prop_loc, + "%qE attribute conflicts with %qE attribute", + prop_attr_list[pn]->name, attrs[g]->name); + inform (attrs[g]->prop_loc, "%qE specified here", + attrs[g]->name ); + } + else + { + warning_at (prop_attr_list[pn]->prop_loc, OPT_Wattributes, + "duplicate %qE attribute", attrs[g]->name); + inform (attrs[g]->prop_loc, "first specified here"); + } + attrs[g] = prop_attr_list[pn]; + } + continue; + } + } + + /* The defaults for atomicity (atomic) and write-ability (readwrite) apply + even if the user provides no specified attributes. */ + bool property_nonatomic = false; + bool property_readonly = false; + + /* Set the values from any specified by the user; these are easy, only two + states. */ + if (attrs[OBJC_PROPATTR_GROUP_ATOMIC]) + property_nonatomic = attrs[OBJC_PROPATTR_GROUP_ATOMIC]->prop_kind + == OBJC_PROPERTY_ATTR_NONATOMIC; + + if (attrs[OBJC_PROPATTR_GROUP_READWRITE]) + property_readonly = attrs[OBJC_PROPATTR_GROUP_READWRITE]->prop_kind + == OBJC_PROPERTY_ATTR_READONLY; + + /* One can't set a readonly value; we issue an error, but force the property + to readwrite as well. */ + if (property_readonly && property_setter_ident) + { + error_at (attrs[OBJC_PROPATTR_GROUP_READWRITE]->prop_loc, "%<readonly%>" + " attribute conflicts with %<setter%> attribute"); + gcc_checking_assert (attrs[OBJC_PROPATTR_GROUP_SETTER]); + inform (attrs[OBJC_PROPATTR_GROUP_SETTER]->prop_loc, "%<setter%>" + " specified here"); + property_readonly = false; + } + + /* Assign semantics is a tri-state property, and also needs some further + checking against the object type. */ + objc_property_assign_semantics property_assign_semantics + = OBJC_PROPERTY_ASSIGN; + + if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]) + { + if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind + == OBJC_PROPERTY_ATTR_ASSIGN) + property_assign_semantics = OBJC_PROPERTY_ASSIGN; + else if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind + == OBJC_PROPERTY_ATTR_RETAIN) + property_assign_semantics = OBJC_PROPERTY_RETAIN; + else if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind + == OBJC_PROPERTY_ATTR_COPY) + property_assign_semantics = OBJC_PROPERTY_COPY; + else + gcc_unreachable (); + } /* TODO: Check that the property type is an Objective-C object or a "POD". */ @@ -950,69 +1005,77 @@ objc_add_property_declaration (location_t location, tree decl, for non-{Objective-C objects}, and to 'retain' for Objective-C objects. But that would break compatibility with other compilers. */ - if (!parsed_property_assign && !parsed_property_retain && !parsed_property_copy) + if (!attrs[OBJC_PROPATTR_GROUP_ASSIGN]) { /* Use 'false' so we do not warn for Class objects. */ if (objc_type_valid_for_messaging (TREE_TYPE (decl), false)) { - warning_at (location, - 0, - "object property %qD has no %<assign%>, %<retain%> or %<copy%> attribute; assuming %<assign%>", - decl); - inform (location, - "%<assign%> can be unsafe for Objective-C objects; please state explicitly if you need it"); + warning_at (decl_loc, 0, "object property %qD has no %<assign%>," + " %<retain%> or %<copy%> attribute; assuming" + " %<assign%>", decl); + inform (decl_loc, "%<assign%> can be unsafe for Objective-C" + " objects; please state explicitly if you need it"); } } } - if (property_assign_semantics == OBJC_PROPERTY_RETAIN - && !objc_type_valid_for_messaging (TREE_TYPE (decl), true)) - error_at (location, "%<retain%> attribute is only valid for Objective-C objects"); + /* Some attributes make no sense unless applied to an Objective-C object. */ + bool prop_objc_object_p + = objc_type_valid_for_messaging (TREE_TYPE (decl), true); + if (!prop_objc_object_p) + { + tree p_name = NULL_TREE; + if (property_assign_semantics == OBJC_PROPERTY_RETAIN + || property_assign_semantics == OBJC_PROPERTY_COPY) + p_name = attrs[OBJC_PROPATTR_GROUP_ASSIGN]->name; - if (property_assign_semantics == OBJC_PROPERTY_COPY - && !objc_type_valid_for_messaging (TREE_TYPE (decl), true)) - error_at (location, "%<copy%> attribute is only valid for Objective-C objects"); + if (p_name) + error_at (decl_loc, "%qE attribute is only valid for Objective-C" + " objects", p_name); + } /* Now determine the final property getter and setter names. They will be stored in the PROPERTY_DECL, from which they'll always be extracted and used. */ /* Adjust, or fill in, setter and getter names. We overwrite the - parsed_property_setter_ident and parsed_property_getter_ident + property_setter_ident and property_getter_ident with the final setter and getter identifiers that will be used. */ - if (parsed_property_setter_ident) + if (property_setter_ident) { /* The setter should be terminated by ':', but the parser only gives us an identifier without ':'. So, we need to add ':' at the end. */ - const char *parsed_setter = IDENTIFIER_POINTER (parsed_property_setter_ident); + const char *parsed_setter = IDENTIFIER_POINTER (property_setter_ident); size_t length = strlen (parsed_setter); char *final_setter = (char *)alloca (length + 2); sprintf (final_setter, "%s:", parsed_setter); - parsed_property_setter_ident = get_identifier (final_setter); + property_setter_ident = get_identifier (final_setter); } else { if (!property_readonly) - parsed_property_setter_ident = get_identifier (objc_build_property_setter_name + property_setter_ident = get_identifier (objc_build_property_setter_name (DECL_NAME (decl))); } - if (!parsed_property_getter_ident) - parsed_property_getter_ident = DECL_NAME (decl); + if (!property_getter_ident) + property_getter_ident = DECL_NAME (decl); /* Check for duplicate property declarations. We first check the immediate context for a property with the same name. Any such declarations are an error, unless this is a class extension and we are extending a property from readonly to readwrite. */ + bool property_extension_in_class_extension = false; + tree x = NULL_TREE; for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) { if (PROPERTY_NAME (x) == DECL_NAME (decl)) { if (objc_in_class_extension - && property_readonly == 0 + && !property_readonly && PROPERTY_READONLY (x) == 1) { /* This is a class extension, and we are extending an @@ -1087,7 +1150,7 @@ objc_add_property_declaration (location_t location, tree decl, types, or it is compatible. */ location_t original_location = DECL_SOURCE_LOCATION (x); - if (PROPERTY_NONATOMIC (x) != parsed_property_nonatomic) + if (PROPERTY_NONATOMIC (x) != property_nonatomic) { warning_at (location, 0, "%<nonatomic%> attribute of property %qD conflicts with " @@ -1098,7 +1161,7 @@ objc_add_property_declaration (location_t location, tree decl, return; } - if (PROPERTY_GETTER_NAME (x) != parsed_property_getter_ident) + if (PROPERTY_GETTER_NAME (x) != property_getter_ident) { warning_at (location, 0, "%<getter%> attribute of property %qD conflicts with " @@ -1112,7 +1175,7 @@ objc_add_property_declaration (location_t location, tree decl, /* We can only compare the setter names if both the old and new property have a setter. */ if (!property_readonly && !PROPERTY_READONLY(x)) { - if (PROPERTY_SETTER_NAME (x) != parsed_property_setter_ident) + if (PROPERTY_SETTER_NAME (x) != property_setter_ident) { warning_at (location, 0, "%<setter%> attribute of property %qD conflicts with " @@ -1190,13 +1253,13 @@ objc_add_property_declaration (location_t location, tree decl, if (property_extension_in_class_extension) { PROPERTY_READONLY (x) = 0; - PROPERTY_SETTER_NAME (x) = parsed_property_setter_ident; + PROPERTY_SETTER_NAME (x) = property_setter_ident; return; } } /* Create a PROPERTY_DECL node. */ - property_decl = make_node (PROPERTY_DECL); + tree property_decl = make_node (PROPERTY_DECL); /* Copy the basic information from the original decl. */ TREE_TYPE (property_decl) = TREE_TYPE (decl); @@ -1205,10 +1268,10 @@ objc_add_property_declaration (location_t location, tree decl, /* Add property-specific information. */ PROPERTY_NAME (property_decl) = DECL_NAME (decl); - PROPERTY_GETTER_NAME (property_decl) = parsed_property_getter_ident; - PROPERTY_SETTER_NAME (property_decl) = parsed_property_setter_ident; + PROPERTY_GETTER_NAME (property_decl) = property_getter_ident; + PROPERTY_SETTER_NAME (property_decl) = property_setter_ident; PROPERTY_READONLY (property_decl) = property_readonly; - PROPERTY_NONATOMIC (property_decl) = parsed_property_nonatomic; + PROPERTY_NONATOMIC (property_decl) = property_nonatomic; PROPERTY_ASSIGN_SEMANTICS (property_decl) = property_assign_semantics; PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (property_decl) = 0; diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-1.mm b/gcc/testsuite/obj-c++.dg/property/at-property-1.mm index 6a90471d89cf344d03e237f3998d4bce104eb73e..332582384a383b495ced7bf221df08105e04276f 100644 --- a/gcc/testsuite/obj-c++.dg/property/at-property-1.mm +++ b/gcc/testsuite/obj-c++.dg/property/at-property-1.mm @@ -6,14 +6,18 @@ { Class isa; } -@property; /* { dg-error "expected identifier" } */ +@property; /* { dg-error "expected" } */ @property int; /* { dg-error "expected identifier" } */ + @property int a; @property int b, c; -@property () int d; /* { dg-error "expected identifier" } */ +@property () int d; /* { dg-warning "empty property attribute list" } */ @property (readonly) int e; -@property (readonly,) int f; /* { dg-error "expected identifier" } */ +@property (readonly,) int f; /* { dg-warning "missing property attribute" } */ @property (xxx) int g; /* { dg-error "unknown property attribute" } */ @property (readonly,xxx) int h; /* { dg-error "unknown property attribute" } */ -@property ( int i; /* { dg-error "expected identifier" } */ +@property ( int i; /* { dg-error "unknown property attribute" } */ + /* { dg-error "expected" "" { target *-*-* } .-1 } */ +@property (assign,,nonatomic) int j; /* { dg-warning "missing property attribute" } */ +@property (assign nonatomic) int k; /* { dg-error {expected } } */ @end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-29.mm b/gcc/testsuite/obj-c++.dg/property/at-property-29.mm index 0f31617f841d7f2dc43ad09d01ed93e58238be4b..64dfe83cd5957097ca407ed5bddd48a229239fd8 100644 --- a/gcc/testsuite/obj-c++.dg/property/at-property-29.mm +++ b/gcc/testsuite/obj-c++.dg/property/at-property-29.mm @@ -8,7 +8,9 @@ Class isa; } /* Test missing '=' in setter/getter attributes. */ -@property (getter) int property_a; /* { dg-error "missing .=. .after .getter. attribute." } */ -@property (setter) int property_b; /* { dg-error "missing .=. .after .setter. attribute." } */ -@property (assign, getter) int property_c; /* { dg-error "missing .=. .after .getter. attribute." } */ +@property (getter) int property_a; /* { dg-error {expected '=' after Objective-C 'getter'} } */ +@property (setter) int property_b; /* { dg-error {expected '=' after Objective-C 'setter'} } */ +@property (assign, getter) int property_c; /* { dg-error {expected '=' after Objective-C 'getter'} } */ +@property (retain, getter=) id x; /* { dg-error {expected 'getter' selector name} } */ +@property (retain, setter=) id y; /* { dg-error {expected 'setter' selector name} } */ @end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm index 941aab8e33cec418456c544242c0c738efdeade9..4083947de71d3cab5e7d43a3fd54e0aaf5b9e612 100644 --- a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm +++ b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm @@ -27,14 +27,14 @@ /* Now test various problems. */ -@property (readonly, readwrite) int a; /* { dg-error ".readonly. attribute conflicts with .readwrite. attribute" } */ +@property (readonly, readwrite) int a; /* { dg-error ".readwrite. attribute conflicts with .readonly. attribute" } */ @property (readonly, setter=mySetterB:) int b; /* { dg-error ".readonly. attribute conflicts with .setter. attribute" } */ -@property (assign, retain) id c; /* { dg-error ".assign. attribute conflicts with .retain. attribute" } */ -@property (assign, copy) id d; /* { dg-error ".assign. attribute conflicts with .copy. attribute" } */ +@property (assign, retain) id c; /* { dg-error ".retain. attribute conflicts with .assign. attribute" } */ +@property (assign, copy) id d; /* { dg-error ".copy. attribute conflicts with .assign. attribute" } */ @property (copy, retain) id e; /* { dg-error ".retain. attribute conflicts with .copy. attribute" } */ -@property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-error ".setter. attribute may only be specified once" } */ -@property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-error ".getter. attribute may only be specified once" } */ +@property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-warning {multiple property 'setter' methods specified, the latest one will be used} } */ +@property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-warning {multiple property 'getter' methods specified, the latest one will be used} } */ @end diff --git a/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm index f730fe846442ffd8238ad391a64511ed3082743a..794f2bd0e965f789092fecd958bebc1608c714d2 100644 --- a/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm +++ b/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm @@ -4,5 +4,5 @@ @end @implementation Bar -@property int FooBar; /* { dg-error "property declaration not in @interface or @protocol context" } */ +@property int FooBar; /* { dg-error {property declaration not in '@interface', '@protocol' or 'category' context} } */ @end diff --git a/gcc/testsuite/objc.dg/property/at-property-1.m b/gcc/testsuite/objc.dg/property/at-property-1.m index fa12fa282c63ad66c8a2429ca70163c4723ff401..6dba8f4b84a2f9d141f04a5678f53d5e7ecafa9d 100644 --- a/gcc/testsuite/objc.dg/property/at-property-1.m +++ b/gcc/testsuite/objc.dg/property/at-property-1.m @@ -11,11 +11,15 @@ /* { dg-warning "declaration does not declare anything" "" { target *-*-* } .-1 } */ @property int a; @property int b, c; -@property () int d; /* { dg-error "expected identifier" } */ +@property () int d; /* { dg-warning "empty property attribute list" } */ @property (readonly) int e; -@property (readonly,) int f; /* { dg-error "expected identifier" } */ +@property (readonly,) int f; /* { dg-warning "missing property attribute" } */ @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" } */ + /* { dg-error "expected" "" { target *-*-* } .-1 } */ +@property (assign,,nonatomic) int j; /* { dg-warning "missing property attribute" } */ +@property (assign nonatomic) int k; /* { dg-error {expected } } */ +@property (assign) int l[4]; /* { dg-error {property cannot be an array} } */ +@property (assign) int : 5; /* { dg-error {properties must be named} } */ +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-29.m b/gcc/testsuite/objc.dg/property/at-property-29.m index 0f31617f841d7f2dc43ad09d01ed93e58238be4b..0b34e1cf67199b516dfbf6a1cfa0dac9ca779b90 100644 --- a/gcc/testsuite/objc.dg/property/at-property-29.m +++ b/gcc/testsuite/objc.dg/property/at-property-29.m @@ -8,7 +8,8 @@ Class isa; } /* Test missing '=' in setter/getter attributes. */ -@property (getter) int property_a; /* { dg-error "missing .=. .after .getter. attribute." } */ -@property (setter) int property_b; /* { dg-error "missing .=. .after .setter. attribute." } */ -@property (assign, getter) int property_c; /* { dg-error "missing .=. .after .getter. attribute." } */ +@property (getter) int property_a; /* { dg-error {expected '=' after Objective-C 'getter'} } */ +@property (setter) int property_b; /* { dg-error {expected '=' after Objective-C 'setter'} } */ +@property (assign, getter) int property_c; /* { dg-error {expected '=' after Objective-C 'getter'} } */ +@property (retain, getter=) id x; /* { dg-error {expected 'getter' selector name} } */ @end diff --git a/gcc/testsuite/objc.dg/property/at-property-4.m b/gcc/testsuite/objc.dg/property/at-property-4.m index 941aab8e33cec418456c544242c0c738efdeade9..4083947de71d3cab5e7d43a3fd54e0aaf5b9e612 100644 --- a/gcc/testsuite/objc.dg/property/at-property-4.m +++ b/gcc/testsuite/objc.dg/property/at-property-4.m @@ -27,14 +27,14 @@ /* Now test various problems. */ -@property (readonly, readwrite) int a; /* { dg-error ".readonly. attribute conflicts with .readwrite. attribute" } */ +@property (readonly, readwrite) int a; /* { dg-error ".readwrite. attribute conflicts with .readonly. attribute" } */ @property (readonly, setter=mySetterB:) int b; /* { dg-error ".readonly. attribute conflicts with .setter. attribute" } */ -@property (assign, retain) id c; /* { dg-error ".assign. attribute conflicts with .retain. attribute" } */ -@property (assign, copy) id d; /* { dg-error ".assign. attribute conflicts with .copy. attribute" } */ +@property (assign, retain) id c; /* { dg-error ".retain. attribute conflicts with .assign. attribute" } */ +@property (assign, copy) id d; /* { dg-error ".copy. attribute conflicts with .assign. attribute" } */ @property (copy, retain) id e; /* { dg-error ".retain. attribute conflicts with .copy. attribute" } */ -@property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-error ".setter. attribute may only be specified once" } */ -@property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-error ".getter. attribute may only be specified once" } */ +@property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-warning {multiple property 'setter' methods specified, the latest one will be used} } */ +@property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-warning {multiple property 'getter' methods specified, the latest one will be used} } */ @end diff --git a/gcc/testsuite/objc.dg/property/at-property-5.m b/gcc/testsuite/objc.dg/property/at-property-5.m index 1267df318ede19a663024e4f562a31fb3ac0b645..820f5b3101cb9e881af8f2ecb3486a56ec22a83a 100644 --- a/gcc/testsuite/objc.dg/property/at-property-5.m +++ b/gcc/testsuite/objc.dg/property/at-property-5.m @@ -31,4 +31,4 @@ /* { dg-message "originally specified here" "" { target *-*-* } property_e_first } */ @end -@property id test; /* { dg-error "property declaration not in .interface or .protocol context" } */ +@property id test; /* { dg-error {property declaration not in '@interface', '@protocol' or 'category' context} } */ diff --git a/gcc/testsuite/objc.dg/property/property-neg-2.m b/gcc/testsuite/objc.dg/property/property-neg-2.m index f730fe846442ffd8238ad391a64511ed3082743a..794f2bd0e965f789092fecd958bebc1608c714d2 100644 --- a/gcc/testsuite/objc.dg/property/property-neg-2.m +++ b/gcc/testsuite/objc.dg/property/property-neg-2.m @@ -4,5 +4,5 @@ @end @implementation Bar -@property int FooBar; /* { dg-error "property declaration not in @interface or @protocol context" } */ +@property int FooBar; /* { dg-error {property declaration not in '@interface', '@protocol' or 'category' context} } */ @end