aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-family/c-objc.h65
-rw-r--r--gcc/c-family/stub-objc.c21
-rw-r--r--gcc/c/c-parser.c280
-rw-r--r--gcc/cp/parser.c266
-rw-r--r--gcc/objc/objc-act.c295
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-1.mm12
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-29.mm8
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-4.mm10
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-neg-2.mm2
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-1.m12
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-29.m7
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-4.m10
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-5.m2
-rw-r--r--gcc/testsuite/objc.dg/property/property-neg-2.m2
14 files changed, 598 insertions, 394 deletions
diff --git a/gcc/c-family/c-objc.h b/gcc/c-family/c-objc.h
index 4577e4f..a2ca112 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 d017acf..2f53557 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 dedfb84..da8278a8 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 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:
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index c0d07ae..26cdedd 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 6a90471..3325823 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 0f31617..64dfe83 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 941aab8..4083947 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 f730fe8..794f2bd 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 fa12fa2..6dba8f4 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 0f31617..0b34e1c 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 941aab8..4083947 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 1267df3..820f5b3 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 f730fe8..794f2bd 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