diff options
author | Iain Sandoe <iain@sandoe.co.uk> | 2020-10-31 20:53:34 +0000 |
---|---|---|
committer | Iain Sandoe <iain@sandoe.co.uk> | 2020-11-06 19:49:23 +0000 |
commit | 9a34a5cce6b50fc3527e7c7ab356808ed435883c (patch) | |
tree | a1b114d1c1f375371c8eb1cf69025a15d99dfb80 /gcc/cp/parser.c | |
parent | 6c282c14d1be0bba2bf5d49acd074b349f28ad17 (diff) | |
download | gcc-9a34a5cce6b50fc3527e7c7ab356808ed435883c.zip gcc-9a34a5cce6b50fc3527e7c7ab356808ed435883c.tar.gz gcc-9a34a5cce6b50fc3527e7c7ab356808ed435883c.tar.bz2 |
Objective-C/C++ (parsers) : Update @property attribute parsing.
At present, we are missing parsing and checking for around
half of the property attributes in use. The existing ad hoc scheme
for the parser's communication with the Objective C validation
is not suitable for extending to cover all the missing cases.
Additionally:
1/ We were declaring errors in two cases that the reference
implementation warns (or is silent).
I've elected to warn for both those cases, (Wattributes) it
could be that we should implement Wobjc-xxx-property warning
masks (TODO).
2/ We were emitting spurious complaints about missing property
attributes when these were not being parsed because we gave
up on the first syntax error.
3/ The quality of the diagnostic locations was poor (that's
true for much of Objective-C, we will have to improve it as
we modernise areas).
We continue to attempt to keep the code, warning and error output
similar (preferably identical output) between the C and C++ front
ends.
The interface to the Objective-C-specific parts of the parsing is
simplified to a vector of parsed (but not fully-checked) property
attributes, this will simplify the addition of new attributes.
gcc/c-family/ChangeLog:
* c-objc.h (enum objc_property_attribute_group): New
(enum objc_property_attribute_kind): New.
(OBJC_PROPATTR_GROUP_MASK): New.
(struct property_attribute_info): Small class encapsulating
parser output from property attributes.
(objc_prop_attr_kind_for_rid): New
(objc_add_property_declaration): Simplify interface.
* stub-objc.c (enum rid): Dummy type.
(objc_add_property_declaration): Simplify interface.
(objc_prop_attr_kind_for_rid): New.
gcc/c/ChangeLog:
* c-parser.c (c_parser_objc_at_property_declaration):
Improve parsing fidelity. Associate better location info
with @property attributes. Clean up the interface to
objc_add_property_declaration ().
gcc/cp/ChangeLog:
* parser.c (cp_parser_objc_at_property_declaration):
Improve parsing fidelity. Associate better location info
with @property attributes. Clean up the interface to
objc_add_property_declaration ().
gcc/objc/ChangeLog:
* objc-act.c (objc_prop_attr_kind_for_rid): New.
(objc_add_property_declaration): Adjust to consume the
parser output using a vector of parsed attributes.
gcc/testsuite/ChangeLog:
* obj-c++.dg/property/at-property-1.mm: Adjust expected
diagnostics.
* obj-c++.dg/property/at-property-29.mm: Likewise.
* obj-c++.dg/property/at-property-4.mm: Likewise.
* obj-c++.dg/property/property-neg-2.mm: Likewise.
* objc.dg/property/at-property-1.m: Likewise.
* objc.dg/property/at-property-29.m: Likewise.
* objc.dg/property/at-property-4.m: Likewise.
* objc.dg/property/at-property-5.m: Likewise.
* objc.dg/property/property-neg-2.m: Likewise.
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: |