diff options
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 266 |
1 files changed, 146 insertions, 120 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6e7b982..c4c672e 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: |