aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c349
1 files changed, 252 insertions, 97 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8ea805d..95be6d3 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: