aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/c-family/ChangeLog18
-rw-r--r--gcc/c-family/c-common.c3
-rw-r--r--gcc/c-family/c-common.h11
-rw-r--r--gcc/c-family/stub-objc.c14
-rw-r--r--gcc/c-parser.c22
-rw-r--r--gcc/c-typeck.c13
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/parser.c20
-rw-r--r--gcc/cp/typeck.c6
-rw-r--r--gcc/objc/ChangeLog91
-rw-r--r--gcc/objc/objc-act.c1346
-rw-r--r--gcc/objc/objc-act.h58
-rw-r--r--gcc/objc/objc-tree.def18
-rw-r--r--gcc/testsuite/ChangeLog61
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-10.mm100
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-11.mm43
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-2.mm4
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-4.mm31
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-5.mm38
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-6.mm60
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-7.mm57
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-8.mm57
-rw-r--r--gcc/testsuite/obj-c++.dg/property/at-property-9.mm49
-rw-r--r--gcc/testsuite/obj-c++.dg/property/dynamic-1.mm8
-rw-r--r--gcc/testsuite/obj-c++.dg/property/dynamic-2.mm46
-rw-r--r--gcc/testsuite/obj-c++.dg/property/fsf-property-basic.mm45
-rw-r--r--gcc/testsuite/obj-c++.dg/property/fsf-property-method-access.mm30
-rw-r--r--gcc/testsuite/obj-c++.dg/property/fsf-property-named-ivar.mm27
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-1.mm5
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-neg-1.mm9
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-neg-2.mm3
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-neg-3.mm12
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-neg-4.mm9
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-neg-5.mm4
-rw-r--r--gcc/testsuite/obj-c++.dg/property/property-neg-7.mm7
-rw-r--r--gcc/testsuite/obj-c++.dg/property/synthesize-1.mm28
-rw-r--r--gcc/testsuite/obj-c++.dg/property/synthesize-2.mm51
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-10.m100
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-11.m43
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-2.m4
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-4.m31
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-5.m34
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-6.m60
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-7.m57
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-8.m57
-rw-r--r--gcc/testsuite/objc.dg/property/at-property-9.m49
-rw-r--r--gcc/testsuite/objc.dg/property/dynamic-1.m8
-rw-r--r--gcc/testsuite/objc.dg/property/dynamic-2.m44
-rw-r--r--gcc/testsuite/objc.dg/property/fsf-property-basic.m33
-rw-r--r--gcc/testsuite/objc.dg/property/fsf-property-method-access.m28
-rw-r--r--gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m25
-rw-r--r--gcc/testsuite/objc.dg/property/property-1.m5
-rw-r--r--gcc/testsuite/objc.dg/property/property-2.m2
-rw-r--r--gcc/testsuite/objc.dg/property/property-neg-1.m9
-rw-r--r--gcc/testsuite/objc.dg/property/property-neg-2.m3
-rw-r--r--gcc/testsuite/objc.dg/property/property-neg-3.m8
-rw-r--r--gcc/testsuite/objc.dg/property/property-neg-4.m8
-rw-r--r--gcc/testsuite/objc.dg/property/property-neg-5.m4
-rw-r--r--gcc/testsuite/objc.dg/property/property-neg-7.m7
-rw-r--r--gcc/testsuite/objc.dg/property/synthesize-1.m28
-rw-r--r--gcc/testsuite/objc.dg/property/synthesize-2.m50
62 files changed, 2199 insertions, 930 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 22bc595..22ded87 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2010-10-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
+ * c-parser.c (c_parser_objc_at_property_declaration): Removed
+ parsing of RID_COPIES and RID_IVAR. Updated call to
+ objc_add_property_declaration.
+ * c-typecheck.c (build_component_ref): Call
+ objc_maybe_build_component_ref instead of objc_build_setter_call.
+ Use objc_is_property_ref to improve Objective-C checks.
+ (cp_build_modify_expr): Call objc_maybe_build_modify_expr instead
+ of objc_build_getter_call.
+
2010-10-29 Paul Koning <ni1d@arrl.net>
* doc/tm.texi.in (REGNO_OK_FOR_BASE_P, REGNO_MODE_OK_FOR_BASE_P,
@@ -437,6 +449,11 @@
2010-10-27 Nicola Pero <nicola.pero@meta-innovation.com>
+ * c-parser.c (cp_parser_objc_at_property_declaration): Removed
+ parsing of RID_COPIES and RID_IVAR.
+
+2010-10-27 Nicola Pero <nicola.pero@meta-innovation.com>
+
* c-parser.c (c_parser_objc_at_property_declaration): Recognize
RID_ASSIGN, RID_COPY, RID_RETAIN, RID_READWRITE and RID_NONATOMIC.
Do not use objc_set_property_attr, but use local variables
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 51b7b32..83a27c2 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,21 @@
+2010-10-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
+ * c-common.h (enum rid): Removed RID_COPIES and RID_IVAR.
+ (objc_add_property_declaration): Removed arguments for copies and
+ ivar.
+ (objc_build_getter_call): Renamed to
+ objc_maybe_build_component_ref.
+ (objc_build_setter_call): Renamed to objc_maybe_build_modify_expr.
+ (objc_is_property_ref): New.
+ * c-common.c (c_common_reswords): Removed copies and ivar.
+ * stub-objc.c (objc_add_property_declaration): Removed arguments
+ for copies and ivar.
+ (objc_build_getter_call): Renamed to
+ objc_maybe_build_component_ref.
+ (objc_build_setter_call): Renamed to objc_maybe_build_modify_expr.
+ (objc_is_property_ref): New.
+
2010-10-29 Arnaud Charlet <charlet@adacore.com>
Matthew Gingell <gingell@adacore.com>
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 3cdc663..1b76d74 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -565,9 +565,6 @@ const struct c_common_resword c_common_reswords[] =
{ "readwrite", RID_READWRITE, D_OBJC },
{ "retain", RID_RETAIN, D_OBJC },
{ "setter", RID_SETTER, D_OBJC },
- /* The following two will be removed once @synthesize is fully implemented. */
- { "copies", RID_COPIES, D_OBJC },
- { "ivar", RID_IVAR, D_OBJC },
};
const unsigned int num_c_common_reswords =
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index f2c6958..7a04d10 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -85,9 +85,6 @@ enum rid
RID_GETTER, RID_SETTER,
RID_READONLY, RID_READWRITE,
RID_ASSIGN, RID_RETAIN, RID_COPY,
- /* RID_IVAR and RID_COPIES will be removed once @synthesize is
- completed. */
- RID_COPIES, RID_IVAR,
RID_NONATOMIC,
/* C (reserved and imaginary types not implemented, so any use is a
@@ -1038,13 +1035,13 @@ 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,
- bool, tree);
-extern tree objc_build_getter_call (tree, tree);
-extern tree objc_build_setter_call (tree, tree);
+ bool, bool, bool, tree, tree);
+extern tree objc_maybe_build_component_ref (tree, tree);
+extern tree objc_maybe_build_modify_expr (tree, tree);
extern void objc_add_synthesize_declaration (location_t, tree);
extern void objc_add_dynamic_declaration (location_t, tree);
extern const char * objc_maybe_printable_name (tree, int);
+extern bool objc_is_property_ref (tree);
/* The following are provided by the C and C++ front-ends, and called by
ObjC/ObjC++. */
diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c
index d4a4e58..52ecc99 100644
--- a/gcc/c-family/stub-objc.c
+++ b/gcc/c-family/stub-objc.c
@@ -333,20 +333,24 @@ objc_add_property_declaration (location_t ARG_UNUSED (location),
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),
- bool ARG_UNUSED (parsed_property_copies),
- tree ARG_UNUSED (parsed_property_ivar_ident))
+ tree ARG_UNUSED (parsed_property_setter_ident))
{
}
+bool
+objc_is_property_ref (tree ARG_UNUSED (node))
+{
+ return 0;
+}
+
tree
-objc_build_getter_call (tree ARG_UNUSED (datum), tree ARG_UNUSED (component))
+objc_maybe_build_component_ref (tree ARG_UNUSED (datum), tree ARG_UNUSED (component))
{
return 0;
}
tree
-objc_build_setter_call (tree ARG_UNUSED (lhs), tree ARG_UNUSED (rhs))
+objc_maybe_build_modify_expr (tree ARG_UNUSED (lhs), tree ARG_UNUSED (rhs))
{
return 0;
}
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 932ab31..0e56b18 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -7623,10 +7623,6 @@ c_parser_objc_at_property_declaration (c_parser *parser)
bool property_readwrite = false;
bool property_retain = false;
tree property_setter_ident = NULL_TREE;
- /* The following two will be removed once @synthesize is
- implemented. */
- bool property_copies = false;
- tree property_ivar_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
@@ -7670,7 +7666,6 @@ c_parser_objc_at_property_declaration (c_parser *parser)
switch (keyword)
{
case RID_ASSIGN: property_assign = true; break;
- case RID_COPIES: property_copies = true; break;
case RID_COPY: property_copy = true; break;
case RID_NONATOMIC: property_nonatomic = true; break;
case RID_READONLY: property_readonly = true; break;
@@ -7679,11 +7674,10 @@ c_parser_objc_at_property_declaration (c_parser *parser)
case RID_GETTER:
case RID_SETTER:
- case RID_IVAR:
if (c_parser_next_token_is_not (parser, CPP_EQ))
{
c_parser_error (parser,
- "getter/setter/ivar attribute must be followed by %<=%>");
+ "getter/setter attribute must be followed by %<=%>");
syntax_error = true;
break;
}
@@ -7706,7 +7700,7 @@ c_parser_objc_at_property_declaration (c_parser *parser)
else
c_parser_consume_token (parser);
}
- else if (keyword == RID_GETTER)
+ else
{
if (property_getter_ident != NULL_TREE)
c_parser_error (parser, "the %<getter%> attribute may only be specified once");
@@ -7714,14 +7708,6 @@ c_parser_objc_at_property_declaration (c_parser *parser)
property_getter_ident = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
}
- else /* RID_IVAR, this case will go away. */
- {
- if (property_ivar_ident != NULL_TREE)
- c_parser_error (parser, "the %<ivar%> attribute may only be specified once");
- else
- property_ivar_ident = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
- }
break;
default:
c_parser_error (parser, "unknown property attribute");
@@ -7763,9 +7749,7 @@ c_parser_objc_at_property_declaration (c_parser *parser)
property_readonly, property_readwrite,
property_assign, property_retain,
property_copy, property_nonatomic,
- property_getter_ident, property_setter_ident,
- /* The following two will be removed. */
- property_copies, property_ivar_ident);
+ property_getter_ident, property_setter_ident);
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 70d9be7..4c53ef0 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -2130,8 +2130,9 @@ build_component_ref (location_t loc, tree datum, tree component)
if (!objc_is_public (datum, component))
return error_mark_node;
+ /* Detect Objective-C property syntax object.property. */
if (c_dialect_objc ()
- && (ref = objc_build_getter_call (datum, component)))
+ && (ref = objc_maybe_build_component_ref (datum, component)))
return ref;
/* See if there is a field or component with name COMPONENT. */
@@ -4869,8 +4870,8 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
- /* For ObjC, defer this check until we have assessed CLASS.property. */
- if (!c_dialect_objc () && !lvalue_or_else (lhs, lv_assign))
+ /* For ObjC properties, defer this check. */
+ if (!objc_is_property_ref (lhs) && !lvalue_or_else (lhs, lv_assign))
return error_mark_node;
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
@@ -4913,9 +4914,13 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
if (c_dialect_objc ())
{
- result = objc_build_setter_call (lhs, newrhs);
+ /* Check if we are modifying an Objective-C property reference;
+ if so, we need to generate setter calls. */
+ result = objc_maybe_build_modify_expr (lhs, newrhs);
if (result)
return result;
+
+ /* Else, do the check that we postponed for Objective-C. */
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
}
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 8a94ad0..cc213f2 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2010-10-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
+ * parser.c (cp_parser_objc_at_property_declaration): Removed
+ parsing of RID_COPIES and RID_IVAR. Updated call to
+ objc_add_property_declaration.
+ * typecheck.c (finish_class_member_access_expr): Call
+ objc_maybe_build_component_ref instead of objc_build_setter_call.
+ (cp_build_modify_expr): Call objc_maybe_build_modify_expr instead
+ of objc_build_getter_call.
+
2010-10-27 Jason Merrill <jason@redhat.com>
* cp-tree.h (cp_trait_kind): Add CPTK_IS_LITERAL_TYPE.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 360e197..851e9c4 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -22717,10 +22717,6 @@ cp_parser_objc_at_property_declaration (cp_parser *parser)
bool property_readwrite = false;
bool property_retain = false;
tree property_setter_ident = NULL_TREE;
- /* The following two will be removed once @synthesize is
- implemented. */
- bool property_copies = false;
- tree property_ivar_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
@@ -22754,7 +22750,6 @@ cp_parser_objc_at_property_declaration (cp_parser *parser)
switch (keyword)
{
case RID_ASSIGN: property_assign = true; break;
- case RID_COPIES: property_copies = true; break;
case RID_COPY: property_copy = true; break;
case RID_NONATOMIC: property_nonatomic = true; break;
case RID_READONLY: property_readonly = true; break;
@@ -22763,7 +22758,6 @@ cp_parser_objc_at_property_declaration (cp_parser *parser)
case RID_GETTER:
case RID_SETTER:
- case RID_IVAR:
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
{
cp_parser_error (parser,
@@ -22790,7 +22784,7 @@ cp_parser_objc_at_property_declaration (cp_parser *parser)
else
cp_lexer_consume_token (parser->lexer);
}
- else if (keyword == RID_GETTER)
+ else
{
if (property_getter_ident != NULL_TREE)
cp_parser_error (parser, "the %<getter%> attribute may only be specified once");
@@ -22798,14 +22792,6 @@ cp_parser_objc_at_property_declaration (cp_parser *parser)
property_getter_ident = cp_lexer_peek_token (parser->lexer)->u.value;
cp_lexer_consume_token (parser->lexer);
}
- else /* RID_IVAR, this case will go away. */
- {
- if (property_ivar_ident != NULL_TREE)
- cp_parser_error (parser, "the %<ivar%> attribute may only be specified once");
- else
- property_ivar_ident = cp_lexer_peek_token (parser->lexer)->u.value;
- cp_lexer_consume_token (parser->lexer);
- }
break;
default:
cp_parser_error (parser, "unknown property attribute");
@@ -22856,9 +22842,7 @@ cp_parser_objc_at_property_declaration (cp_parser *parser)
property_readonly, property_readwrite,
property_assign, property_retain,
property_copy, property_nonatomic,
- property_getter_ident, property_setter_ident,
- /* The following two will be removed. */
- property_copies, property_ivar_ident);
+ property_getter_ident, property_setter_ident);
}
cp_parser_consume_semicolon_at_end_of_statement (parser);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 160198b..19cedd9 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2595,7 +2595,7 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
}
else if (c_dialect_objc ()
&& TREE_CODE (name) == IDENTIFIER_NODE
- && (expr = objc_build_getter_call (object, name)))
+ && (expr = objc_maybe_build_component_ref (object, name)))
return expr;
/* [expr.ref]
@@ -6764,7 +6764,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
{
if (c_dialect_objc ())
{
- result = objc_build_setter_call (lhs, rhs);
+ result = objc_maybe_build_modify_expr (lhs, rhs);
if (result)
return result;
}
@@ -6809,7 +6809,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
modifycode = NOP_EXPR;
if (c_dialect_objc ())
{
- result = objc_build_setter_call (lhs, newrhs);
+ result = objc_maybe_build_modify_expr (lhs, newrhs);
if (result)
return result;
}
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index aa58764..0484133 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -1,3 +1,94 @@
+2010-10-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
+ * objc-tree.def (PROPERTY_REF): New.
+ * objc-act.h: Added comments for all the PROPERTY_ macros.
+ (PROPERTY_NAME): Use DECL_NAME.
+ (PROPERTY_COPIES): Removed.
+ (PROPERTY_READONLY): Use DECL_LANG_FLAG_0 for it.
+ (PROPERTY_NONATOMIC): New.
+ (objc_property_assign_semantics): Make it a typedef.
+ (PROPERTY_ASSIGN_SEMANTICS): New.
+ (PROPERTY_DYNAMIC): New.
+ (PROPERTY_REF_OBJECT): New.
+ (PROPERTY_REF_PROPERTY_DECL): New.
+ * objc-act.c (CALL_EXPR_OBJC_PROPERTY_GETTER): Removed.
+ (in_objc_property_setter_name_context): Removed.
+ (objc_add_property_declaration): Removed copies and ivar arguments
+ and code supporting them. Fixed recovering when readonly and
+ setter attributes are specified. Removed support for @property in
+ @implementation context. Updated error message. Double-check
+ that a property does not have a DECL_INITIAL. Validate the
+ property assign semantics and emit appropriate errors and
+ warnings. Check for duplicate property declarations. Set
+ DECL_SOURCE_LOCATION, TREE_DEPRECATED, PROPERTY_NONATOMIC,
+ PROPERTY_ASSIGN_SEMANTICS and PROPERTY_DYNAMIC of the new
+ PROPERTY_DECL. Do not set PROPERTY_COPIES. Set
+ PROPERTY_IVAR_NAME to NULL_TREE.
+ (objc_build_getter_call): Renamed to
+ objc_maybe_build_component_ref. If the property is not found in
+ the interface, search in the protocol list. Do not generate the
+ getter call; instead, build and return a PROPERTY_REF.
+ (objc_is_property_ref): New.
+ (objc_setter_func_call): Removed.
+ (get_selector_from_reference): Removed.
+ (is_property): Removed.
+ (objc_build_setter_call): Renamed to objc_maybe_build_modify_expr.
+ Updated to work on a PROPERTY_REF and use the PROPERTY_DECL from
+ the PROPERTY_REF. Generate an error if the property is read-only.
+ (build_property_reference): Removed.
+ (objc_finish_message_expr): Removed check to produce "readonly
+ property can not be set" error when
+ in_objc_property_setter_name_context. We now generate the error
+ earlier, in objc_maybe_build_modify_expr, which will only generate
+ the setter call if the property is readwrite.
+ (check_methods): Recognize dynamic properties.
+ (check_methods_accessible): Same change.
+ (objc_build_property_ivar_name): Removed.
+ (objc_build_property_setter_name): Dropped bool argument. Always
+ add the ':' at the end.
+ (objc_gen_one_property_datum): Removed.
+ (objc_process_getter_setter): Removed.
+ (objc_synthesize_getter): Mark 'klass' argument as unused. Use
+ PROPERTY_GETTER_NAME instead of PROPERTY_NAME. Set the
+ DECL_SOURCE_LOCATION of the new method to be the same as the one
+ for the @synthesize. Always use PROPERTY_IVAR_NAME as it is
+ instead of trying to guess what it should be. Removed use of
+ CLASS_IVARS. Use the location of @synthesize for c_finish_return
+ and c_end_compound_statement.
+ (objc_synthesize_setter): Mark 'klass' argument as unused. Use
+ PROPERTY_SETTER_NAME instead of trying to guess what it should be.
+ Set the DECL_SOURCE_LOCATION of the new method to be the same as
+ the one for the @synthesize. Always use PROPERTY_IVAR_NAME as it
+ is instead of trying to guess what it should be. Removed use of
+ CLASS_IVARS. Use the location of @synthesize for c_finish_return
+ and c_end_compound_statement. Emit an error and keep going,
+ instead of aborting, if the setter prototype does not have the
+ expected argument.
+ (objc_add_synthesize_declaration_for_property): New.
+ (objc_add_synthesize_declaration): Removed ATTRIBUTE_UNUSED from
+ all arguments. Improved error message. Filled in the rest of the
+ function, which used to be a placeholder, with an actual
+ implementation.
+ (objc_add_dynamic_declaration_for_property): New.
+ (objc_add_dynamic_declaration): Removed ATTRIBUTE_UNUSED from all
+ arguments. Improved error message. Filled in the rest of the
+ function, which used to be a placeholder, with an actual
+ implementation.
+ (objc_gen_property_data): Rewritten.
+ (finish_class): Added explicit switch cases for
+ CLASS_INTERFACE_TYPE, CATEGORY_INTERFACE_TYPE and
+ PROTOCOL_INTERFACE_TYPE. Added a default switch case which is
+ gcc_unreachable. Rewritten the processing of properties, in
+ particular to not synthesize prototypes for getters and setters if
+ they already exist and to install the getter and setter names into
+ PROPERTY_GETTER_NAME and PROPERTY_SETTER_NAME. Do not generate
+ warnings about setter, getter and ivar property attributes.
+ (objc_lookup_ivar): Removed support for properties.
+ (objc_gimplify_property_ref): New.
+ (objc_gimplify_expr): Use a switch. In case of a PROPERTY_REF, call
+ objc_gimplify_property_ref.
+
2010-10-27 Nicola Pero <nicola.pero@meta-innovation.com>
* objc-act.c (objc_add_property_declaration): Added arguments to
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 674b77e..e564da5 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -170,24 +170,14 @@ static bool objc_derived_from_p (tree, tree);
#endif
/* Property. */
-static void objc_gen_one_property_datum (tree, tree, tree, bool*);
static void objc_gen_property_data (tree, tree);
static void objc_synthesize_getter (tree, tree, tree);
-static void objc_process_getter_setter (tree, tree, bool);
static void objc_synthesize_setter (tree, tree, tree);
-static char *objc_build_property_ivar_name (tree);
-static char *objc_build_property_setter_name (tree, bool);
+static char *objc_build_property_setter_name (tree);
static int match_proto_with_proto (tree, tree, int);
static tree lookup_property (tree, tree);
static tree lookup_property_in_list (tree, tree);
static tree lookup_property_in_protocol_list (tree, tree);
-static tree objc_setter_func_call (tree, tree, tree);
-static tree build_property_reference (tree, tree);
-static tree is_property (tree, tree);
-/* Set on a CALL_EXPR if it is for call to a getter function represented by an
- objective-c property declaration. */
-#define CALL_EXPR_OBJC_PROPERTY_GETTER(NODE) \
- (CALL_EXPR_CHECK(NODE)->base.deprecated_flag)
static void objc_xref_basetypes (tree, tree);
@@ -406,8 +396,6 @@ static int method_slot = 0;
required. */
static bool objc_method_optional_flag = false;
-static bool in_objc_property_setter_name_context = false;
-
static int objc_collecting_ivars = 0;
#define BUFSIZE 1024
@@ -825,20 +813,18 @@ 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,
- /* The following two will be removed. */
- bool parsed_property_copies, tree parsed_property_ivar_ident)
+ tree parsed_property_getter_ident, tree parsed_property_setter_ident)
{
tree property_decl;
tree x;
- tree interface = NULL_TREE;
- /* 'property_readonly' is the final readonly/rewrite attribute of
- the property declaration after all things have been
- considered. */
+ /* '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;
- enum objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN;
- /* The following will be removed once @synthesize is implemented. */
- bool property_copies = false;
+ objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN;
if (parsed_property_readonly && parsed_property_readwrite)
{
@@ -859,9 +845,9 @@ objc_add_property_declaration (location_t location, tree decl,
if (parsed_property_readonly && parsed_property_setter_ident)
{
- /* Maybe this should be an error ? */
+ /* Maybe this should be an error ? The Apple documentation says it is a warning. */
warning_at (location, 0, "%<readonly%> attribute conflicts with %<setter%> attribute");
- parsed_property_readonly = false;
+ property_readonly = false;
}
if (parsed_property_assign && parsed_property_retain)
@@ -891,50 +877,19 @@ objc_add_property_declaration (location_t location, tree decl,
property_assign_semantics = OBJC_PROPERTY_COPY;
}
- /* This will be removed when @synthesize is implemented. */
- if (parsed_property_copies)
- property_copies = true;
-
- /* This case will be removed when @synthesize is implemented; then
- @property will only be allowed in an @interface context. */
- if (objc_implementation_context)
- {
- interface = lookup_interface (CLASS_NAME (objc_implementation_context));
- if (!interface)
- {
- error_at (location, "no class property can be implemented without an interface");
- return;
- }
- if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)
- {
- interface = lookup_category (interface,
- CLASS_SUPER_NAME (objc_implementation_context));
- if (!interface)
- {
- error_at (location, "no category property can be implemented without an interface");
- return;
- }
- }
- }
- else if (objc_interface_context)
- {
- /* This will be removed when ivar is removed. */
- if (parsed_property_ivar_ident)
- {
- warning_at (location, 0, "the %<ivar%> attribute is ignored in an @interface");
- parsed_property_ivar_ident = NULL_TREE;
- }
- }
- else if (!objc_interface_context)
+ if (!objc_interface_context)
{
- error_at (location, "property declaration not in @interface or @implementation context");
+ error_at (location, "property declaration not in @interface or @protocol context");
return;
}
+ /* At this point we know that we are either in an interface, a
+ category, or a protocol. */
+
if (parsed_property_setter_ident)
{
/* The setter should be terminated by ':', but the parser only
- passes us an identifier without ':'. So, we need to add ':'
+ gives us an identifier without ':'. So, we need to add ':'
at the end. */
const char *parsed_setter = IDENTIFIER_POINTER (parsed_property_setter_ident);
size_t length = strlen (parsed_setter);
@@ -944,97 +899,98 @@ objc_add_property_declaration (location_t location, tree decl,
parsed_property_setter_ident = get_identifier (final_setter);
}
- property_decl = make_node (PROPERTY_DECL);
- TREE_TYPE (property_decl) = TREE_TYPE (decl);
+ /* Check that the property does not have an initial value specified.
+ This should never happen as the parser doesn't allow this, but
+ it's just in case. */
+ if (DECL_INITIAL (decl))
+ {
+ error_at (location, "property can not have an initial value");
+ return;
+ }
- 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_IVAR_NAME (property_decl) = parsed_property_ivar_ident;
- PROPERTY_READONLY (property_decl) = property_readonly
- ? boolean_true_node
- : boolean_false_node;
- PROPERTY_COPIES (property_decl) = property_copies
- ? boolean_true_node
- : boolean_false_node;
-
- /* TODO: The following is temporary code that will be removed when
- property_assign_semantics and property_nonatomic are
- implemented. */
- if (objc_implementation_context && objc_interface_context)
- {
- /* This branch is impossible but the compiler can't know it. Do
- something with property_assign_semantics and
- parsed_property_nonatomic (not implemented yet) to convince
- the compiler we're using them and prevent it from generating
- warnings and breaking bootstrap. */
- PROPERTY_COPIES (property_decl) = property_assign_semantics ? boolean_true_node : boolean_false_node;
- PROPERTY_READONLY (property_decl) = parsed_property_nonatomic ? boolean_true_node : boolean_false_node;
- }
-
- if (objc_interface_context)
- {
- /* Doing the property in interface declaration. */
-
- /* Issue error if property and an ivar name match. */
- if (TREE_CODE (objc_interface_context) == CLASS_INTERFACE_TYPE
- && is_ivar (CLASS_IVARS (objc_interface_context), DECL_NAME (decl)))
- error_at (location, "property %qD may not have the same name as an ivar in the class", decl);
- /* must check for duplicate property declarations. */
- for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
+ /* TODO: Check that the property type is an Objective-C object or a "POD". */
+
+ if (property_assign_semantics == OBJC_PROPERTY_ASSIGN)
+ {
+ /* If garbage collection is not being used, then 'assign' is
+ valid for objects (and typically used for delegates) but it
+ is wrong in most cases (since most objects need to be
+ retained or copied in setters). Warn users when 'assign' is
+ used implicitly. */
+ /* Please note that it would make sense to default to 'assign'
+ for non-{Objective-C objects}, and to 'retain' for
+ Objective-C objects. But that would break compatibility with
+ other compilers. */
+ if (!flag_objc_gc)
{
- if (PROPERTY_NAME (x) == DECL_NAME (decl))
+ if (!parsed_property_assign && !parsed_property_retain && !parsed_property_copy)
{
- error_at (location, "duplicate property declaration %qD", decl);
- return;
+ if (objc_type_valid_for_messaging (TREE_TYPE (decl)))
+ {
+ 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");
+ }
}
}
- TREE_CHAIN (property_decl) = CLASS_PROPERTY_DECL (objc_interface_context);
- CLASS_PROPERTY_DECL (objc_interface_context) = property_decl;
}
- else
- {
- /* This case will go away once @syhtensize is implemented. */
+
+ if (property_assign_semantics == OBJC_PROPERTY_RETAIN
+ && !objc_type_valid_for_messaging (TREE_TYPE (decl)))
+ error_at (location, "%<retain%> attribute is only valid for Objective-C objects");
+
+ if (property_assign_semantics == OBJC_PROPERTY_COPY
+ && !objc_type_valid_for_messaging (TREE_TYPE (decl)))
+ error_at (location, "%<copy%> attribute is only valid for Objective-C objects");
- /* Doing the property in implementation context. */
- /* If property is not declared in the interface issue error. */
- for (x = CLASS_PROPERTY_DECL (interface); x; x = TREE_CHAIN (x))
- if (PROPERTY_NAME (x) == DECL_NAME (decl))
- break;
- if (!x)
+ /* Check for duplicate property declarations. We first check the
+ immediate context for a property with the same name. */
+ for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
+ {
+ if (PROPERTY_NAME (x) == DECL_NAME (decl))
{
- error_at (location, "no declaration of property %qD found in the interface", decl);
+ location_t original_location = DECL_SOURCE_LOCATION (x);
+
+ error_at (location, "redeclaration of property %qD", decl);
+
+ if (original_location != UNKNOWN_LOCATION)
+ inform (original_location, "originally declared here");
return;
- }
- /* readonlys must also match. */
- if (PROPERTY_READONLY (x) != PROPERTY_READONLY (property_decl))
- {
- error_at (location, "property %qD %<readonly%> attribute conflicts with its"
- " interface version", decl);
- }
- /* copies must also match. */
- if (PROPERTY_COPIES (x) != PROPERTY_COPIES (property_decl))
- {
- error_at (location, "property %qD %<copies%> attribute conflicts with its"
- " interface version", decl);
- }
- /* Cannot have readonly and setter attribute for the same property. */
- if (PROPERTY_READONLY (property_decl) == boolean_true_node &&
- PROPERTY_SETTER_NAME (property_decl))
- {
- /* This error is already reported up there. */
- /* warning_at (location, 0, "a %<readonly%> property cannot have a setter (ignored)"); */
- PROPERTY_SETTER_NAME (property_decl) = NULL_TREE;
- }
- /* Add the property to the list of properties for current implementation. */
- TREE_CHAIN (property_decl) = IMPL_PROPERTY_DECL (objc_implementation_context);
- IMPL_PROPERTY_DECL (objc_implementation_context) = property_decl;
+ }
}
+
+ /* TODO: Shall we check here for other property declaractions (in
+ the superclass, other categories or protocols) with the same name
+ and conflicting types ? */
+
+ /* Create a PROPERTY_DECL node. */
+ property_decl = make_node (PROPERTY_DECL);
+
+ /* Copy the basic information from the original decl. */
+ TREE_TYPE (property_decl) = TREE_TYPE (decl);
+ DECL_SOURCE_LOCATION (property_decl) = DECL_SOURCE_LOCATION (decl);
+ TREE_DEPRECATED (property_decl) = TREE_DEPRECATED (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_READONLY (property_decl) = property_readonly;
+ PROPERTY_NONATOMIC (property_decl) = parsed_property_nonatomic;
+ PROPERTY_ASSIGN_SEMANTICS (property_decl) = property_assign_semantics;
+ PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
+ PROPERTY_DYNAMIC (property_decl) = 0;
+
+ /* Add the PROPERTY_DECL to the list of properties for the class. */
+ TREE_CHAIN (property_decl) = CLASS_PROPERTY_DECL (objc_interface_context);
+ CLASS_PROPERTY_DECL (objc_interface_context) = property_decl;
}
/* This routine looks for a given PROPERTY in a list of CLASS, CATEGORY, or
- PROTOCOL.
-*/
+ PROTOCOL. */
static tree
lookup_property_in_list (tree chain, tree property)
{
@@ -1046,7 +1002,6 @@ lookup_property_in_list (tree chain, tree property)
}
/* This routine looks for a given PROPERTY in the tree chain of RPROTO_LIST. */
-
static tree lookup_property_in_protocol_list (tree rproto_list, tree property)
{
tree rproto, x;
@@ -1069,8 +1024,7 @@ static tree lookup_property_in_protocol_list (tree rproto_list, tree property)
}
/* This routine looks up the PROPERTY in current INTERFACE, its categories and up the
- chain of interface hierarchy.
-*/
+ chain of interface hierarchy. */
static tree
lookup_property (tree interface_type, tree property)
{
@@ -1098,33 +1052,42 @@ lookup_property (tree interface_type, tree property)
return inter;
}
-/* This routine recognizes a dot-notation for a property reference and generates a call to
- the getter function for this property. In all other cases, it returns a NULL_TREE.
-*/
+/* This hook routine is invoked by the parser when an expression such
+ as 'xxx.yyy' is parsed. We get a chance to process these
+ expressions in a way that is specified to Objective-C (to implement
+ properties, or non-fragile ivars). If the expression is not an
+ Objective-C specified expression, we should return NULL_TREE; else
+ we return the expression.
+
+ At the moment this only implements properties (not non-fragile
+ ivars yet), ie 'object.property'. */
tree
-objc_build_getter_call (tree receiver, tree component)
+objc_maybe_build_component_ref (tree object, tree property_ident)
{
tree x = NULL_TREE;
tree rtype;
- if (receiver == NULL_TREE
- || receiver == error_mark_node
- || (rtype = TREE_TYPE (receiver)) == NULL_TREE)
+ /* Try to determine quickly if 'object' is an Objective-C object or
+ not. If not, return. */
+ if (object == NULL_TREE || object == error_mark_node
+ || (rtype = TREE_TYPE (object)) == NULL_TREE)
return NULL_TREE;
-
- if (component == NULL_TREE
- || component == error_mark_node
- || TREE_CODE (component) != IDENTIFIER_NODE)
+
+ if (property_ident == NULL_TREE || property_ident == error_mark_node
+ || TREE_CODE (property_ident) != IDENTIFIER_NODE)
return NULL_TREE;
+ /* TODO: Implement super.property. */
+
+ /* TODO: Carefully review the following code. */
if (objc_is_id (rtype))
{
tree rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype))
? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype))
: NULL_TREE);
if (rprotos)
- x = lookup_property_in_protocol_list (rprotos, component);
+ x = lookup_property_in_protocol_list (rprotos, property_ident);
}
else
{
@@ -1145,176 +1108,100 @@ objc_build_getter_call (tree receiver, tree component)
if (basetype != NULL_TREE && TYPED_OBJECT (basetype))
{
tree interface_type = TYPE_OBJC_INTERFACE (basetype);
- if (!interface_type)
- return NULL_TREE;
- x = lookup_property (interface_type, component);
+ tree protocol_list = TYPE_OBJC_PROTOCOL_LIST (basetype);
+
+ x = lookup_property (interface_type, property_ident);
+
+ if (x == NULL_TREE)
+ x = lookup_property_in_protocol_list (protocol_list, property_ident);
}
}
if (x)
{
- tree call_exp, getter;
- /* Get the getter name. */
- gcc_assert (PROPERTY_NAME (x));
- getter = objc_finish_message_expr (receiver, PROPERTY_NAME (x),
- NULL_TREE);
- call_exp = getter;
-#ifdef OBJCPLUS
- /* In C++, a getter which returns an aggregate value results in a
- target_expr which initializes a temporary to the call expression. */
- if (TREE_CODE (getter) == TARGET_EXPR)
- {
- gcc_assert (MAYBE_CLASS_TYPE_P (TREE_TYPE (getter)));
- gcc_assert (TREE_CODE (TREE_OPERAND (getter,0)) == VAR_DECL);
- call_exp = TREE_OPERAND (getter,1);
- }
-#endif
- gcc_assert (TREE_CODE (call_exp) == CALL_EXPR);
-
- CALL_EXPR_OBJC_PROPERTY_GETTER (call_exp) = 1;
- return getter;
+ tree expression;
+
+ expression = build2 (PROPERTY_REF, TREE_TYPE(x), object, x);
+ SET_EXPR_LOCATION (expression, input_location);
+ TREE_SIDE_EFFECTS (expression) = 1;
+
+ /* We have an additional nasty problem here; if this
+ PROPERTY_REF needs to become a 'getter', then the conversion
+ from PROPERTY_REF into a getter call happens in gimplify,
+ after the selector table has already been generated and it is
+ too late to add another selector to it. To work around the
+ problem, we always put the selector in the table at this
+ stage, as if we were building the method call here. And the
+ easiest way to do this is precisely to build the method call,
+ then discard it. Note that if the PROPERTY_REF becomes a
+ 'setter' instead of a 'getter', then we have added a selector
+ too many to the selector table. This is a little
+ inefficient.
+
+ TODO: This can be made more efficient; in particular we don't
+ need to build the whole message call, we could just work on
+ the selector. */
+ objc_finish_message_expr (object,
+ PROPERTY_GETTER_NAME (x),
+ NULL_TREE);
+
+ return expression;
}
- return NULL_TREE;
-}
-
-/* This routine builds a call to property's 'setter' function. RECEIVER is the
- receiving object for 'setter'. PROPERTY_IDENT is name of the property and
- RHS is the argument passed to the 'setter' function. */
-static tree
-objc_setter_func_call (tree receiver, tree property_ident, tree rhs)
-{
- tree setter_argument = build_tree_list (NULL_TREE, rhs);
- char *setter_name = objc_build_property_setter_name (property_ident, true);
- tree setter;
- in_objc_property_setter_name_context = true;
- setter = objc_finish_message_expr (receiver, get_identifier (setter_name),
- setter_argument);
- in_objc_property_setter_name_context = false;
- return setter;
+ return NULL_TREE;
}
-/* Find the selector identifier from a reference. A somewhat tortuous way of
- obtaining the information to allow a setter to be written, given an
- existing getter. */
-
-static tree
-get_selector_from_reference (tree selref)
+/* This is used because we don't want to expose PROPERTY_REF to the
+ C/C++ frontends. Maybe we should! */
+bool
+objc_is_property_ref (tree node)
{
- tree chain;
-
- if (flag_next_runtime)
- {
- /* Run through the selectors until we find the one we're looking for. */
- for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
- if (TREE_PURPOSE (chain) == selref)
- return TREE_VALUE (chain);
- }
+ if (node && TREE_CODE (node) == PROPERTY_REF)
+ return true;
else
- {
- /* To find our way back to the selector for the GNU runtime is harder
- work, we need to decompose the representation of SELECTOR_TABLE[n]
- to find 'n'. This representation is in several forms. */
- if (TREE_CODE (selref) == POINTER_PLUS_EXPR)
- {
- /* We need the element size to decode the array offset expression
- into an index. */
- unsigned size = (unsigned) TREE_INT_CST_LOW
- (TYPE_SIZE_UNIT
- (TREE_TYPE
- (TREE_TYPE
- (TREE_OPERAND
- (TREE_OPERAND
- (TREE_OPERAND (selref, 0), 0), 0)))));
- unsigned index =
- (unsigned) TREE_INT_CST_LOW (TREE_OPERAND (selref, 1))
- / size;
- for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
- if (!index--)
- return TREE_VALUE (chain);
- }
- else if (TREE_CODE (selref) == NOP_EXPR)
- {
- /* Either we have a base an index, or we have just a base (when the
- index is 0. */
- if (TREE_CODE (TREE_OPERAND (selref, 0)) == ADDR_EXPR
- && TREE_CODE
- (TREE_OPERAND
- (TREE_OPERAND (selref, 0), 0)) == ARRAY_REF)
- {
- /* The Nth. */
- unsigned index = (unsigned) TREE_INT_CST_LOW
- (TREE_OPERAND
- (TREE_OPERAND
- (TREE_OPERAND (selref, 0), 0), 1));
- for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
- if (!index--)
- return TREE_VALUE (chain);
- }
- else
- return TREE_VALUE (sel_ref_chain);
- } /* Else we don't know how to figure this out - which will produce a
- parse error - saying that the LHS is not writeable. */
- }
- return NULL_TREE;
-}
-
-/* This routine converts a previously synthesized 'getter' function call for
- a property and converts it to a 'setter' function call for the same
- property. */
-
-tree
-objc_build_setter_call (tree lhs, tree rhs)
-{
- if (lhs
- && TREE_CODE (lhs) == CALL_EXPR
- && CALL_EXPR_OBJC_PROPERTY_GETTER (lhs))
- {
- tree selector;
- /* Get the Object. */
- tree receiver = TREE_OPERAND (lhs, 3);
- /* Get the selector reference. */
- tree selector_reference = TREE_OPERAND (lhs, 4);
- gcc_assert (receiver && selector_reference);
- /* The style of the selector reference is different for GNU & NeXT. */
- selector = get_selector_from_reference (selector_reference);
- if (selector)
- return objc_setter_func_call (receiver, selector, rhs);
- }
- return NULL_TREE;
+ return false;
}
-/* This routine checks to see if ID is a property name. If so, it
- returns property declaration. */
+/* This hook routine is called when a MODIFY_EXPR is being built. We
+ check what is being modified; if it is a PROPERTY_REF, we need to
+ generate a 'setter' function call for the property. If this is not
+ a PROPERTY_REF, we return NULL_TREE and the C/C++ frontend will go
+ on creating their MODIFY_EXPR.
-static tree
-is_property (tree klass, tree id)
-{
- tree x;
+ This is used for example if you write
- for (x = CLASS_PROPERTY_DECL (klass); x; x = TREE_CHAIN (x))
- if (PROPERTY_NAME (x) == id)
- return x;
- return NULL_TREE;
-}
-
-/* This routine returns call to property's getter when a property is
- used stand-alone (without self. notation). */
+ object.count = 1;
-static tree
-build_property_reference (tree property, tree id)
+ where 'count' is a property. The left-hand side creates a
+ PROPERTY_REF, and then the compiler tries to generate a MODIFY_EXPR
+ to assign something to it. We intercept that here, and generate a
+ call to the 'setter' method instead. */
+tree
+objc_maybe_build_modify_expr (tree lhs, tree rhs)
{
- tree getter;
- if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
+ if (lhs && TREE_CODE (lhs) == PROPERTY_REF)
{
- error ("property %qs accessed in class method",
- IDENTIFIER_POINTER (id));
- return error_mark_node;
- }
+ tree object_expr = PROPERTY_REF_OBJECT (lhs);
+ tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs);
- getter = objc_finish_message_expr (self_decl, PROPERTY_NAME (property), NULL_TREE);
- CALL_EXPR_OBJC_PROPERTY_GETTER (getter) = 1;
- return getter;
+ if (PROPERTY_READONLY (property_decl))
+ {
+ error ("readonly property can not be set");
+ return error_mark_node;
+ }
+ else
+ {
+ tree setter_argument = build_tree_list (NULL_TREE, rhs);
+ tree setter;
+ /* TODO: Decay argument in C. */
+ setter = objc_finish_message_expr (object_expr,
+ PROPERTY_SETTER_NAME (property_decl),
+ setter_argument);
+ return setter;
+ }
+ }
+ else
+ return NULL_TREE;
}
tree
@@ -7226,9 +7113,7 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params)
= lookup_method_in_hash_lists (sel_name, class_tree != NULL_TREE);
}
- if (!method_prototype && in_objc_property_setter_name_context)
- error ("readonly property can not be set");
- else if (!method_prototype)
+ if (!method_prototype)
{
static bool warn_missing_methods = false;
@@ -8164,6 +8049,16 @@ check_methods (tree chain, tree list, int mtype)
while (chain)
{
+ /* If the method is associated with a dynamic property, then it
+ is Ok not to have the method implementation, as it will be
+ generated dynamically at runtime. */
+ tree property = METHOD_PROPERTY_CONTEXT (chain);
+ if (property != NULL_TREE && PROPERTY_DYNAMIC (property))
+ {
+ chain = TREE_CHAIN (chain); /* next method... */
+ continue;
+ }
+
if (!lookup_method (list, chain))
{
if (first)
@@ -8231,6 +8126,16 @@ check_methods_accessible (tree chain, tree context, int mtype)
while (chain)
{
+ /* If the method is associated with a dynamic property, then it
+ is Ok not to have the method implementation, as it will be
+ generated dynamically at runtime. */
+ tree property = METHOD_PROPERTY_CONTEXT (chain);
+ if (property != NULL_TREE && PROPERTY_DYNAMIC (property))
+ {
+ chain = TREE_CHAIN (chain); /* next method... */
+ continue;
+ }
+
context = base_context;
while (context)
{
@@ -8600,199 +8505,67 @@ continue_class (tree klass)
}
}
-/* This routine builds a property ivar name. */
-
-static char *
-objc_build_property_ivar_name (tree property_decl)
-{
- static char string[BUFSIZE];
- sprintf (string, "_%s", IDENTIFIER_POINTER (PROPERTY_NAME (property_decl)));
- return string;
-}
-
/* This routine builds name of the setter synthesized function. */
-
static char *
-objc_build_property_setter_name (tree ident, bool delimit_colon)
+objc_build_property_setter_name (tree ident)
{
+ /* TODO: Use alloca to allocate buffer of appropriate size. */
static char string[BUFSIZE];
- if (delimit_colon)
- sprintf (string, "set%s:", IDENTIFIER_POINTER (ident));
- else
- sprintf (string, "set%s", IDENTIFIER_POINTER (ident));
+ sprintf (string, "set%s:", IDENTIFIER_POINTER (ident));
string[3] = TOUPPER (string[3]);
return string;
}
-/* This routine does all the work for generating data and code per each
- property declared in current implementation. */
-
+/* This routine synthesizes a 'getter' method. This is only called
+ for @synthesize properties. */
static void
-objc_gen_one_property_datum (tree klass, tree property, tree class_methods, bool *ivar_added)
-{
- tree mth;
-
- /* If getter, check that it is already declared in user code. */
- if (PROPERTY_GETTER_NAME (property))
- {
- mth = lookup_method (CLASS_NST_METHODS (class_methods),
- PROPERTY_GETTER_NAME (property));
- if (!mth)
- error ("property getter %qs not declared in class %qs",
- IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property)),
- IDENTIFIER_POINTER (CLASS_NAME (class_methods)));
- }
- /* If setter, check that it is already declared in user code. */
- if (PROPERTY_SETTER_NAME (property))
- {
- mth = lookup_method (CLASS_NST_METHODS (class_methods),
- PROPERTY_SETTER_NAME (property));
- if (!mth)
- error ("property setter %qs not declared in class %qs",
- IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property)),
- IDENTIFIER_POINTER (CLASS_NAME (class_methods)));
- }
- /* If ivar attribute specified, check that it is already declared. */
- if (PROPERTY_IVAR_NAME (property))
- {
- if (!is_ivar (CLASS_IVARS (klass),
- PROPERTY_IVAR_NAME (property)))
- error ("ivar %qs in property declaration must be an existing ivar",
- IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property)));
- }
- else if (!PROPERTY_GETTER_NAME (property)
- || (PROPERTY_READONLY (property) == boolean_false_node
- && !PROPERTY_SETTER_NAME (property)))
- {
- /* Setter and/or getter must be synthesize and there was no user-specified
- ivar. Must create an ivar and add to to current class's ivar list. */
- tree record = CLASS_STATIC_TEMPLATE (klass);
- tree type = TREE_TYPE (property);
- tree field_decl, field;
- field_decl = create_field_decl (type,
- objc_build_property_ivar_name (property));
- DECL_CONTEXT (field_decl) = record;
- (void) add_instance_variable (klass,
- OBJC_IVAR_VIS_PUBLIC, field_decl);
- /* Unfortunately, CLASS_IVARS is completed when interface is completed.
- Must add the new ivar by hand to its list here. */
-
- CLASS_IVARS (klass) =
- chainon (CLASS_IVARS (klass),
- copy_node (field_decl));
- gcc_assert (record);
- /* Must also add this ivar to the end of list of fields for this class. */
- field = TYPE_FIELDS (record);
- if (field && field != CLASS_IVARS (klass))
- /* class has a hidden field, attach ivar list after the hiddent field. */
- TREE_CHAIN (field) = CLASS_IVARS (klass);
- else
- TYPE_FIELDS (record) = CLASS_IVARS (klass);
- *ivar_added = true;
- }
-}
-
-/* This routine processes an existing getter or setter attribute.
- It aliases internal property getter or setter to the user implemented
- getter or setter.
-*/
-
-static void
-objc_process_getter_setter (tree klass, tree property, bool getter)
-{
- tree prop_mth_decl;
- tree prop_getter_mth_decl;
- tree name_ident;
-
- if (getter)
- /* getter name is same as property name. */
- name_ident = PROPERTY_NAME (property);
- else
- /* Must synthesize setter name from property name. */
- name_ident = get_identifier (objc_build_property_setter_name (
- PROPERTY_NAME (property), true));
-
- /* Find declaration of instance method for the property in its class. */
- prop_mth_decl = lookup_method (CLASS_NST_METHODS (klass), name_ident);
-
- if (!prop_mth_decl)
- return;
-
- prop_getter_mth_decl = lookup_method (CLASS_NST_METHODS (objc_implementation_context),
- getter ? PROPERTY_GETTER_NAME (property)
- : PROPERTY_SETTER_NAME (property));
-
- if (!prop_getter_mth_decl)
- return;
-
- if (!match_proto_with_proto (prop_getter_mth_decl, prop_mth_decl, 1))
- {
- error ("User %s %qs does not match property %qs type",
- getter ? "getter" : "setter",
- IDENTIFIER_POINTER (DECL_NAME (prop_getter_mth_decl)),
- IDENTIFIER_POINTER (PROPERTY_NAME (property)));
- return;
- }
- /* We alias internal property getter to the user implemented getter by copying relevant
- entries from user's implementation to the internal one. */
- prop_mth_decl = copy_node (prop_mth_decl);
- METHOD_ENCODING (prop_mth_decl) = METHOD_ENCODING (prop_getter_mth_decl);
- METHOD_DEFINITION (prop_mth_decl) = METHOD_DEFINITION (prop_getter_mth_decl);
- objc_add_method (objc_implementation_context, prop_mth_decl, 0, 0);
-}
-
-/* This routine synthesizes a 'getter' method. */
-
-static void
-objc_synthesize_getter (tree klass, tree class_method, tree property)
+objc_synthesize_getter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
{
tree fn, decl;
tree body;
tree ret_val;
- tree ivar_ident;
- /* If user has implemented a getter with same name then do nothing. */
+ /* If user has implemented a getter with same name then do nothing. */
if (lookup_method (CLASS_NST_METHODS (objc_implementation_context),
- PROPERTY_NAME (property)))
+ PROPERTY_GETTER_NAME (property)))
return;
- /* Find declaration of the property in the interface. There must be one. */
- decl = lookup_method (CLASS_NST_METHODS (class_method),
- PROPERTY_NAME (property));
+ /* Find declaration of the property getter in the interface. There
+ must be one. TODO: Search superclasses as well. */
+ decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_GETTER_NAME (property));
- /* If one not declared in the interface, this condition has already been reported
- as user error (because property was not declared in the interface). */
+ /* If one not declared in the interface, this condition has already
+ been reported as user error (because property was not declared in
+ the interface). */
if (!decl)
return;
- /* For now no attributes. */
- objc_start_method_definition (false /* is_class_method */, copy_node (decl), NULL_TREE);
+ /* Adapt the 'decl'. Use the source location of the @synthesize
+ statement for error messages. */
+ decl = copy_node (decl);
+ DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (property);
+ objc_start_method_definition (false /* is_class_method */, decl, NULL_TREE);
body = c_begin_compound_stmt (true);
+
+ /* TODO: Implement PROPERTY_NONATOMIC, use objc_getProperty etc as
+ appropriate. The following code just always does direct ivar
+ access. */
+
/* return self->_property_name; */
- /* If user specified an ivar, use it in generation of the getter. */
- ivar_ident = PROPERTY_IVAR_NAME (property)
- ? PROPERTY_IVAR_NAME (property)
- : get_identifier (objc_build_property_ivar_name (property));
-
- /* objc_ivar_chain might not be up to date in the case that property 'ivar'
- is added *after* user ivar is parsed and objc_continue_implementation
- has already been called. */
- objc_ivar_chain = CLASS_IVARS (klass);
- ret_val = objc_lookup_ivar (NULL_TREE, ivar_ident);
- /* If ivar attribute is not a user declared attribute, this condition has
- already been repored as error. */
- gcc_assert (ret_val || PROPERTY_IVAR_NAME (property));
-
- if (ret_val)
- {
+
+ /* PROPERTY_IVAR_NAME is always defined if we got here, and should
+ be a valid instance variable. */
+ ret_val = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
+ gcc_assert (ret_val);
+
#ifdef OBJCPLUS
- finish_return_stmt (ret_val);
+ finish_return_stmt (ret_val);
#else
- (void)c_finish_return (input_location, ret_val, NULL);
+ (void)c_finish_return (DECL_SOURCE_LOCATION (property), ret_val, NULL);
#endif
- }
- add_stmt (c_end_compound_stmt (input_location, body, true));
+
+ add_stmt (c_end_compound_stmt (DECL_SOURCE_LOCATION (property), body, true));
fn = current_function_decl;
#ifdef OBJCPLUS
finish_function ();
@@ -8803,55 +8576,69 @@ objc_synthesize_getter (tree klass, tree class_method, tree property)
/* This routine synthesizes a 'setter' method. */
static void
-objc_synthesize_setter (tree klass, tree class_method, tree property)
+objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
{
- tree fn, decl, ivar_ident, lhs, rhs;
+ tree fn, decl, lhs, rhs;
tree body;
- char *setter_name = objc_build_property_setter_name (
- PROPERTY_NAME (property), true);
- tree setter_ident = get_identifier (setter_name);
- /* If user has implemented a setter with same name then do nothing. */
+ /* If user has implemented a setter with same name then do nothing. */
if (lookup_method (CLASS_NST_METHODS (objc_implementation_context),
- setter_ident))
+ PROPERTY_SETTER_NAME (property)))
return;
- /* Find declaration of the property in the interface. There must be one. */
- decl = lookup_method (CLASS_NST_METHODS (class_method), setter_ident);
+ /* Find declaration of the property setter in the interface. There
+ must be one. TODO: Search superclasses as well. */
+ decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_SETTER_NAME (property));
- /* If one not declared in the inerface, this condition has already been reported
- as user error (because property was not declared in the interface. */
+ /* If one not declared in the interface, this condition has already
+ been reported as user error (because property was not declared in
+ the interface). */
if (!decl)
return;
- /* For now, no attributes. */
- objc_start_method_definition (false /* is_class_method */, copy_node (decl), NULL_TREE);
+ /* Adapt the 'decl'. Use the source location of the @synthesize
+ statement for error messages. */
+ decl = copy_node (decl);
+ DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (property);
+
+ objc_start_method_definition (false /* is_class_method */, decl, NULL_TREE);
body = c_begin_compound_stmt (true);
+
+ /* TODO: Implement PROPERTY_NONATOMIC, use objc_getProperty etc as
+ appropriate. The following code just always does direct ivar
+ access. */
+
/* _property_name = _value; */
- /* If user specified an ivar, use it in generation of the setter. */
- ivar_ident = PROPERTY_IVAR_NAME (property)
- ? PROPERTY_IVAR_NAME (property)
- : get_identifier (objc_build_property_ivar_name (property));
-
- /* objc_ivar_chain might not be up to date in the case that property 'ivar'
- is added *after* user ivar is parsed and objc_continue_implementation
- has already been called. */
- objc_ivar_chain = CLASS_IVARS (klass);
- lhs = objc_lookup_ivar (NULL_TREE, ivar_ident);
- /* If ivar attribute is not a user declared attribute, this condition has
- already been repored as error. */
- gcc_assert (lhs || PROPERTY_IVAR_NAME (property));
- if (lhs)
- {
- rhs = lookup_name (get_identifier ("_value"));
- gcc_assert (rhs);
- /* FIXME: NULL types to get compile. */
- add_stmt (build_modify_expr (input_location,
- lhs, NULL_TREE, NOP_EXPR,
- input_location, rhs, NULL_TREE));
- }
- add_stmt (c_end_compound_stmt (input_location, body, true));
+
+ /* PROPERTY_IVAR_NAME is always defined if we got here, and should
+ be a valid instance variable. */
+ lhs = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
+ gcc_assert (lhs);
+
+ /* TODO: Lookup the argument in a more robust way so that it works
+ even if the method prototype does not call it '_value'. */
+ rhs = lookup_name (get_identifier ("_value"));
+
+ /* This would presumably happen if the user has specified a
+ prototype for the setter that is not the correct one. */
+ if (rhs == NULL_TREE)
+ {
+ /* TODO: This should be caught much earlier than this. */
+ /* We couldn't find the '_value' identifier in the current
+ context; presumably the user didn't have a '_value'
+ argument. */
+ error_at (DECL_SOURCE_LOCATION (decl), "invalid setter, missing _value argument");
+ /* Just recover somehow. */
+ rhs = lhs;
+ }
+
+ /* FIXME: NULL types to get compile. */
+ add_stmt (build_modify_expr (DECL_SOURCE_LOCATION (decl),
+ lhs, NULL_TREE, NOP_EXPR,
+ DECL_SOURCE_LOCATION (decl), rhs, NULL_TREE));
+
+ add_stmt (c_end_compound_stmt (DECL_SOURCE_LOCATION (decl), body, true));
fn = current_function_decl;
#ifdef OBJCPLUS
finish_function ();
@@ -8859,14 +8646,104 @@ objc_synthesize_setter (tree klass, tree class_method, tree property)
objc_finish_method_definition (fn);
}
+/* This function is a sub-routine of objc_add_synthesize_declaration.
+ It is called for each property to synthesize once we have
+ determined that the context is Ok. */
+static void
+objc_add_synthesize_declaration_for_property (location_t location, tree interface,
+ tree property_name, tree ivar_name)
+{
+ /* Find the @property declaration. */
+ tree property;
+
+ /* Check that synthesize or dynamic has not already been used for
+ the same property. */
+ for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
+ if (PROPERTY_NAME (property) == property_name)
+ {
+ location_t original_location = DECL_SOURCE_LOCATION (property);
+
+ if (PROPERTY_DYNAMIC (property))
+ error_at (location, "property %qs already specified in %<@dynamic%>",
+ IDENTIFIER_POINTER (property_name));
+ else
+ error_at (location, "property %qs already specified in %<@synthesize%>",
+ IDENTIFIER_POINTER (property_name));
+
+ if (original_location != UNKNOWN_LOCATION)
+ inform (original_location, "originally specified here");
+ return;
+ }
+
+ /* Check that the property is declared in the interface. */
+ /* TODO: This only check the immediate class; we need to check the
+ superclass (and categories ?) as well. */
+ for (property = CLASS_PROPERTY_DECL (interface); property; property = TREE_CHAIN (property))
+ if (PROPERTY_NAME (property) == property_name)
+ break;
+
+ if (!property)
+ {
+ error_at (location, "no declaration of property %qs found in the interface",
+ IDENTIFIER_POINTER (property_name));
+ return;
+ }
+ else
+ {
+ /* We have to copy the property, because we want to chain it to
+ the implementation context, and we want to store the source
+ location of the @synthesize, not of the original
+ @property. */
+ property = copy_node (property);
+ DECL_SOURCE_LOCATION (property) = location;
+ }
+
+ /* Determine PROPERTY_IVAR_NAME. */
+ if (ivar_name == NULL_TREE)
+ ivar_name = property_name;
+
+ /* Check that the instance variable exists. You can only use an
+ instance variable from the same class, not one from the
+ superclass. */
+ if (!is_ivar (CLASS_IVARS (interface), ivar_name))
+ error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar",
+ IDENTIFIER_POINTER (property_name));
+
+ /* TODO: Check that the types of the instance variable and of the
+ property match. */
+
+ /* TODO: Check that no other property is using the same instance
+ variable. */
+
+ /* Note that a @synthesize (and only a @synthesize) always sets
+ PROPERTY_IVAR_NAME to a non-NULL_TREE. You can recognize a
+ @synthesize by that. */
+ PROPERTY_IVAR_NAME (property) = ivar_name;
+
+ /* PROPERTY_SETTER_NAME and PROPERTY_GETTER_NAME are copied from the
+ original declaration; they are always set (with the exception of
+ PROPERTY_SETTER_NAME not being set if PROPERTY_READONLY == 1). */
+
+ /* Add the property to the list of properties for current implementation. */
+ TREE_CHAIN (property) = IMPL_PROPERTY_DECL (objc_implementation_context);
+ IMPL_PROPERTY_DECL (objc_implementation_context) = property;
+
+ /* Note how we don't actually synthesize the getter/setter here; it
+ would be very natural, but we may miss the fact that the user has
+ implemented his own getter/setter later on in the @implementation
+ (in which case we shouldn't generate getter/setter). We wait
+ until we have parsed it all before generating the code. */
+}
+
/* This function is called by the parser after a @synthesize
- expression is parsed. 'start_locus' is the location of the
+ expression is parsed. 'location' is the location of the
@synthesize expression, and 'property_and_ivar_list' is a chained
- list of the property and ivar names.
- */
+ list of the property and ivar names. */
void
-objc_add_synthesize_declaration (location_t start_locus ATTRIBUTE_UNUSED, tree property_and_ivar_list ATTRIBUTE_UNUSED)
+objc_add_synthesize_declaration (location_t location, tree property_and_ivar_list)
{
+ tree interface, chain;
+
if (property_and_ivar_list == error_mark_node)
return;
@@ -8876,21 +8753,117 @@ objc_add_synthesize_declaration (location_t start_locus ATTRIBUTE_UNUSED, tree p
detects the problem while parsing, outputs the error
"misplaced '@synthesize' Objective-C++ construct" and skips
the declaration. */
- error ("%<@synthesize%> not in @implementation context");
+ error_at (location, "%<@synthesize%> not in @implementation context");
+ return;
+ }
+
+ if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ /* TODO: Maybe we should allow @synthesize in categories ? */
+ error_at (location, "%<@synthesize%> can not be used in categories");
+ return;
+ }
+
+ interface = lookup_interface (CLASS_NAME (objc_implementation_context));
+ if (!interface)
+ {
+ /* I can't see how this could happen, but it is good as a safety check. */
+ error_at (location,
+ "%<@synthesize%> requires the @interface of the class to be available");
+ return;
+ }
+
+ /* Now, iterate over the properties and do each of them. */
+ for (chain = property_and_ivar_list; chain; chain = TREE_CHAIN (chain))
+ {
+ objc_add_synthesize_declaration_for_property (location, interface, TREE_VALUE (chain),
+ TREE_PURPOSE (chain));
+ }
+}
+
+/* This function is a sub-routine of objc_add_dynamic_declaration. It
+ is called for each property to mark as dynamic once we have
+ determined that the context is Ok. */
+static void
+objc_add_dynamic_declaration_for_property (location_t location, tree interface,
+ tree property_name)
+{
+ /* Find the @property declaration. */
+ tree property;
+
+ /* Check that synthesize or dynamic has not already been used for
+ the same property. */
+ for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
+ if (PROPERTY_NAME (property) == property_name)
+ {
+ location_t original_location = DECL_SOURCE_LOCATION (property);
+
+ if (PROPERTY_DYNAMIC (property))
+ error_at (location, "property %qs already specified in %<@dynamic%>",
+ IDENTIFIER_POINTER (property_name));
+ else
+ error_at (location, "property %qs already specified in %<@synthesize%>",
+ IDENTIFIER_POINTER (property_name));
+
+ if (original_location != UNKNOWN_LOCATION)
+ inform (original_location, "originally specified here");
+ return;
+ }
+
+ /* Check that the property is declared in the interface. */
+ /* TODO: This only check the immediate class; we need to check the
+ superclass (and categories ?) as well. */
+ for (property = CLASS_PROPERTY_DECL (interface); property; property = TREE_CHAIN (property))
+ if (PROPERTY_NAME (property) == property_name)
+ break;
+
+ if (!property)
+ {
+ error_at (location, "no declaration of property %qs found in the interface",
+ IDENTIFIER_POINTER (property_name));
return;
}
+ else
+ {
+ /* Mark the original PROPERTY_DECL as dynamic. The reason is
+ that the setter and getter methods in the interface have a
+ METHOD_PROPERTY_CONTEXT that points to the original
+ PROPERTY_DECL; when we check that these methods have been
+ implemented, we need to easily find that they are associated
+ with a dynamic property. TODO: Clean this up; maybe the
+ @property PROPERTY_DECL should contain a reference to the
+ @dynamic PROPERTY_DECL ? */
+ PROPERTY_DYNAMIC (property) = 1;
+
+ /* We have to copy the property, because we want to chain it to
+ the implementation context, and we want to store the source
+ location of the @synthesize, not of the original
+ @property. */
+ property = copy_node (property);
+ DECL_SOURCE_LOCATION (property) = location;
+ }
+
+ /* Note that a @dynamic (and only a @dynamic) always sets
+ PROPERTY_DYNAMIC to 1. You can recognize a @dynamic by that.
+ (actually, as explained above, PROPERTY_DECL generated by
+ @property and associated with a @dynamic property are also marked
+ as PROPERTY_DYNAMIC). */
+ PROPERTY_DYNAMIC (property) = 1;
- /* TODO */
- error ("%<@synthesize%> is not supported in this version of the compiler");
+ /* Add the property to the list of properties for current implementation. */
+ TREE_CHAIN (property) = IMPL_PROPERTY_DECL (objc_implementation_context);
+ IMPL_PROPERTY_DECL (objc_implementation_context) = property;
}
/* This function is called by the parser after a @dynamic expression
- is parsed. 'start_locus' is the location of the @dynamic
- expression, and 'property_list' is a chained list of all the
- property names. */
+ is parsed. 'location' is the location of the @dynamic expression,
+ and 'property_list' is a chained list of all the property
+ names. */
void
-objc_add_dynamic_declaration (location_t start_locus ATTRIBUTE_UNUSED, tree property_list ATTRIBUTE_UNUSED)
+objc_add_dynamic_declaration (location_t location, tree property_list)
{
+ tree interface, chain;
+
if (property_list == error_mark_node)
return;
@@ -8900,12 +8873,31 @@ objc_add_dynamic_declaration (location_t start_locus ATTRIBUTE_UNUSED, tree prop
detects the problem while parsing, outputs the error
"misplaced '@dynamic' Objective-C++ construct" and skips the
declaration. */
- error ("%<@dynamic%> not in @implementation context");
+ error_at (location, "%<@dynamic%> not in @implementation context");
return;
}
- /* TODO */
- error ("%<@dynamic%> is not supported in this version of the compiler");
+ if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ /* TODO: Maybe we should allow @dynamic in categories ? */
+ error_at (location, "%<@dynamic%> can not be used in categories");
+ return;
+ }
+
+ interface = lookup_interface (CLASS_NAME (objc_implementation_context));
+ if (!interface)
+ {
+ /* I can't see how this could happen, but it is good as a safety check. */
+ error_at (location,
+ "%<@dynamic%> requires the @interface of the class to be available");
+ return;
+ }
+
+ /* Now, iterate over the properties and do each of them. */
+ for (chain = property_list; chain; chain = TREE_CHAIN (chain))
+ {
+ objc_add_dynamic_declaration_for_property (location, interface, TREE_VALUE (chain));
+ }
}
/* Main routine to generate code/data for all the property information for
@@ -8918,35 +8910,25 @@ static void
objc_gen_property_data (tree klass, tree class_methods)
{
tree x;
- bool ivar_added = false;
- for (x = IMPL_PROPERTY_DECL (objc_implementation_context); x; x = TREE_CHAIN (x))
- objc_gen_one_property_datum (klass, x, class_methods, &ivar_added);
- if (ivar_added)
- {
- tree record = CLASS_STATIC_TEMPLATE (klass);
- /* Ugh, must recalculate struct layout since at least one ivar was added. */
- TYPE_SIZE (record) = 0;
- layout_type (record);
- }
-
- /* Synthesize all getters for properties. */
for (x = IMPL_PROPERTY_DECL (objc_implementation_context); x; x = TREE_CHAIN (x))
{
- /* Property has a getter attribute, no need to synthesize one. */
- if (PROPERTY_GETTER_NAME (x) == NULL_TREE)
- objc_synthesize_getter (klass, class_methods, x);
- else
- objc_process_getter_setter (class_methods, x, true);
-
- if (PROPERTY_READONLY (x) == boolean_false_node)
- {
- /* not a readonly property. */
- if (PROPERTY_SETTER_NAME (x) == NULL_TREE)
- objc_synthesize_setter (klass, class_methods, x);
- else
- objc_process_getter_setter (class_methods, x, false);
- }
+ /* @dynamic property - nothing to check or synthesize. */
+ if (PROPERTY_DYNAMIC (x))
+ continue;
+
+ /* @synthesize property - need to synthesize the accessors. */
+ if (PROPERTY_IVAR_NAME (x))
+ {
+ objc_synthesize_getter (klass, class_methods, x);
+
+ if (PROPERTY_READONLY (x) == 0)
+ objc_synthesize_setter (klass, class_methods, x);
+
+ continue;
+ }
+
+ gcc_unreachable ();
}
}
@@ -9001,60 +8983,119 @@ finish_class (tree klass)
}
break;
}
- default:
+ case CLASS_INTERFACE_TYPE:
+ case CATEGORY_INTERFACE_TYPE:
+ case PROTOCOL_INTERFACE_TYPE:
{
/* Process properties of the class. */
tree x;
for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
{
- tree type = TREE_TYPE (x);
- tree prop_name = PROPERTY_NAME (x);
- /* Build an instance method declaration: - (type) prop_name; */
+ /* Store the getter name that we used into the property.
+ It is used to generate the right getter calls;
+ moreover, when a @synthesize is processed, it copies
+ everything from the property, including the
+ PROPERTY_GETTER_NAME. We want to be sure that
+ @synthesize will get exactly the right
+ PROPERTY_GETTER_NAME. */
if (PROPERTY_GETTER_NAME (x) == NULL_TREE)
+ PROPERTY_GETTER_NAME (x) = PROPERTY_NAME (x);
+
+ /* Now we check that the appropriate getter is declared,
+ and if not, we declare one ourselves. */
+ {
+ tree getter_decl = lookup_method (CLASS_NST_METHODS (klass),
+ PROPERTY_GETTER_NAME (x));
+
+ if (getter_decl)
+ {
+ /* TODO: Check that the declaration is consistent with the property. */
+ ;
+ }
+ else
+ {
+ /* Generate an instance method declaration for the
+ getter; for example "- (id) name;". In general
+ it will be of the form
+ -(type)property_getter_name; */
+ tree rettype = build_tree_list (NULL_TREE, TREE_TYPE (x));
+ getter_decl = build_method_decl (INSTANCE_METHOD_DECL,
+ rettype, PROPERTY_GETTER_NAME (x),
+ NULL_TREE, false);
+ objc_add_method (objc_interface_context, getter_decl, false, false);
+ METHOD_PROPERTY_CONTEXT (getter_decl) = x;
+ }
+ }
+
+ if (PROPERTY_READONLY (x) == 0)
{
- /* No getter attribute specified. Generate an instance method for the
- getter. */
- tree rettype = build_tree_list (NULL_TREE, type);
- tree getter_decl = build_method_decl (INSTANCE_METHOD_DECL,
- rettype, prop_name,
- NULL_TREE, false);
- objc_add_method (objc_interface_context, getter_decl, false, false);
- METHOD_PROPERTY_CONTEXT (getter_decl) = x;
- }
- else
- warning (0, "getter = %qs may not be specified in an interface",
- IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (x)));
-
- /* Build an instance method declaration: - (void) setName: (type)value; */
- if (PROPERTY_SETTER_NAME (x) == NULL_TREE
- && PROPERTY_READONLY (x) == boolean_false_node)
- {
- /* Declare a setter instance method in the interface. */
- tree key_name, arg_type, arg_name;
- tree setter_decl, selector;
- tree ret_type = build_tree_list (NULL_TREE, void_type_node);
- /* setter name. */
- key_name = get_identifier (objc_build_property_setter_name
- (PROPERTY_NAME (x), false));
- arg_type = build_tree_list (NULL_TREE, type);
- arg_name = get_identifier ("_value");
- /* For now, no attributes. */
- selector = objc_build_keyword_decl (key_name, arg_type, arg_name, NULL);
- setter_decl = build_method_decl (INSTANCE_METHOD_DECL,
- ret_type, selector,
- build_tree_list (NULL_TREE, NULL_TREE),
- false);
- objc_add_method (objc_interface_context, setter_decl, false, false);
- METHOD_PROPERTY_CONTEXT (setter_decl) = x;
+ /* Store the setter name that we used into the
+ property. It is used when generating setter calls;
+ moreover, when a @synthesize is processed, it
+ copies everything from the property, including the
+ PROPERTY_SETTER_NAME. We want to be sure that
+ @synthesize will get exactly the right
+ PROPERTY_SETTER_NAME. */
+ if (PROPERTY_SETTER_NAME (x) == NULL_TREE)
+ PROPERTY_SETTER_NAME (x) = get_identifier (objc_build_property_setter_name
+ (PROPERTY_NAME (x)));
+
+ /* Now we check that the appropriate setter is declared,
+ and if not, we declare on ourselves. */
+ {
+ tree setter_decl = lookup_method (CLASS_NST_METHODS (klass),
+ PROPERTY_SETTER_NAME (x));
+
+ if (setter_decl)
+ {
+ /* TODO: Check that the declaration is consistent with the property. */
+ ;
+ }
+ else
+ {
+ /* The setter name is something like 'setName:'.
+ We need the substring 'setName' to build the
+ method declaration due to how the declaration
+ works. TODO: build_method_decl() will then
+ generate back 'setName:' from 'setName'; it
+ would be more efficient to hook into
+ there. */
+ const char *full_setter_name = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (x));
+ size_t length = strlen (full_setter_name);
+ char *setter_name = (char *) alloca (length);
+ tree ret_type, selector, arg_type, arg_name;
+
+ strcpy (setter_name, full_setter_name);
+ setter_name[length - 1] = '\0';
+ ret_type = build_tree_list (NULL_TREE, void_type_node);
+ arg_type = build_tree_list (NULL_TREE, TREE_TYPE (x));
+ arg_name = get_identifier ("_value");
+ selector = objc_build_keyword_decl (get_identifier (setter_name),
+ arg_type, arg_name, NULL);
+ setter_decl = build_method_decl (INSTANCE_METHOD_DECL,
+ ret_type, selector,
+ build_tree_list (NULL_TREE, NULL_TREE),
+ false);
+ objc_add_method (objc_interface_context, setter_decl, false, false);
+ METHOD_PROPERTY_CONTEXT (setter_decl) = x;
+ }
+ }
+
+ /* Note how at this point (once an @interface or @protocol
+ have been processed), PROPERTY_GETTER_NAME is always
+ set for all PROPERTY_DECLs, and PROPERTY_SETTER_NAME is
+ always set for all PROPERTY_DECLs where
+ PROPERTY_READONLY == 0. Any time we deal with a getter
+ or setter, we should get the PROPERTY_DECL and use
+ PROPERTY_GETTER_NAME and PROPERTY_SETTER_NAME to know
+ the correct names. */
}
- else if (PROPERTY_SETTER_NAME (x))
- warning (0, "setter = %qs may not be specified in an interface",
- IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (x)));
- if (PROPERTY_IVAR_NAME (x))
- warning (0, "ivar = %qs attribute may not be specified in an interface",
- IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (x)));
}
+ break;
}
+ default:
+ gcc_unreachable ();
+ break;
}
}
@@ -11184,11 +11225,11 @@ objc_diagnose_private_ivar (tree id)
/* Look up ID as an instance variable. OTHER contains the result of
the C or C++ lookup, which we may want to use instead. */
-/* Also handle use of property as setter/getter. */
+/* To use properties inside an instance method, use self.property. */
tree
objc_lookup_ivar (tree other, tree id)
{
- tree ivar, property;
+ tree ivar;
/* If we are not inside of an ObjC method, ivar lookup makes no sense. */
if (!objc_method_context)
@@ -11204,18 +11245,11 @@ objc_lookup_ivar (tree other, tree id)
&& other && other != error_mark_node)
return other;
- property = NULL_TREE;
- if (objc_implementation_context)
- property = is_property (objc_implementation_context, id);
-
- if (!property)
- {
- /* Look up the ivar, but do not use it if it is not accessible. */
- ivar = is_ivar (objc_ivar_chain, id);
-
- if (!ivar || is_private (ivar))
- return other;
- }
+ /* Look up the ivar, but do not use it if it is not accessible. */
+ ivar = is_ivar (objc_ivar_chain, id);
+
+ if (!ivar || is_private (ivar))
+ return other;
/* In an instance method, a local variable (or parameter) may hide the
instance variable. */
@@ -11227,17 +11261,11 @@ objc_lookup_ivar (tree other, tree id)
&& !DECL_FILE_SCOPE_P (other))
#endif
{
- if (property)
- warning (0, "local declaration of %qE hides property", id);
- else
- warning (0, "local declaration of %qE hides instance variable", id);
+ warning (0, "local declaration of %qE hides instance variable", id);
return other;
}
- if (property)
- return build_property_reference (property, id);
-
/* At this point, we are either in an instance method with no obscuring
local definitions, or in a class method with no alternate definitions
at all. */
@@ -11263,31 +11291,77 @@ objc_rewrite_function_call (tree function, tree first_param)
return function;
}
-/* Look for the special case of OBJC_TYPE_REF with the address of
- a function in OBJ_TYPE_REF_EXPR (presumably objc_msgSend or one
- of its cousins). */
+/* This is called to "gimplify" a PROPERTY_REF node. It builds the
+ corresponding 'getter' function call. Note that we assume the
+ PROPERTY_REF to be valid since we generated it while parsing. */
+static void
+objc_gimplify_property_ref (tree *expr_p)
+{
+ tree object_expression = PROPERTY_REF_OBJECT (*expr_p);
+ tree property_decl = PROPERTY_REF_PROPERTY_DECL (*expr_p);
+ tree call_exp, getter;
+
+ /* TODO: Implement super.property. */
+
+ getter = objc_finish_message_expr (object_expression,
+ PROPERTY_GETTER_NAME (property_decl),
+ NULL_TREE);
+ call_exp = getter;
+#ifdef OBJCPLUS
+ /* In C++, a getter which returns an aggregate value results in a
+ target_expr which initializes a temporary to the call
+ expression. */
+ if (TREE_CODE (getter) == TARGET_EXPR)
+ {
+ gcc_assert (MAYBE_CLASS_TYPE_P (TREE_TYPE (getter)));
+ gcc_assert (TREE_CODE (TREE_OPERAND (getter, 0)) == VAR_DECL);
+ call_exp = TREE_OPERAND (getter, 1);
+ }
+#endif
+ gcc_assert (TREE_CODE (call_exp) == CALL_EXPR);
+
+ *expr_p = call_exp;
+}
+/* This is called when "gimplifying" the trees. We need to gimplify
+ the Objective-C/Objective-C++ specific trees, then hand over the
+ process to C/C++. */
int
objc_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
{
- enum gimplify_status r0, r1;
- if (TREE_CODE (*expr_p) == OBJ_TYPE_REF
- && TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0))
- == FUNCTION_DECL)
+ enum tree_code code = TREE_CODE (*expr_p);
+ switch (code)
{
- /* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the
- value of the OBJ_TYPE_REF, so force them to be emitted
- during subexpression evaluation rather than after the
- OBJ_TYPE_REF. This permits objc_msgSend calls in Objective
- C to use direct rather than indirect calls when the
- object expression has a postincrement. */
- r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL,
- is_gimple_val, fb_rvalue);
- r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
- is_gimple_val, fb_rvalue);
-
- return MIN (r0, r1);
+ /* Look for the special case of OBJC_TYPE_REF with the address
+ of a function in OBJ_TYPE_REF_EXPR (presumably objc_msgSend
+ or one of its cousins). */
+ case OBJ_TYPE_REF:
+ if (TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0))
+ == FUNCTION_DECL)
+ {
+ enum gimplify_status r0, r1;
+
+ /* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the
+ value of the OBJ_TYPE_REF, so force them to be emitted
+ during subexpression evaluation rather than after the
+ OBJ_TYPE_REF. This permits objc_msgSend calls in
+ Objective C to use direct rather than indirect calls when
+ the object expression has a postincrement. */
+ r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL,
+ is_gimple_val, fb_rvalue);
+ r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+
+ return MIN (r0, r1);
+ }
+ break;
+ case PROPERTY_REF:
+ objc_gimplify_property_ref (expr_p);
+ /* Do not return yet; let C/C++ gimplify the resulting expression. */
+ break;
+ default:
+ break;
}
#ifdef OBJCPLUS
diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h
index 2456c10..95e9070 100644
--- a/gcc/objc/objc-act.h
+++ b/gcc/objc/objc-act.h
@@ -54,18 +54,64 @@ tree objc_eh_personality (void);
#define METHOD_TYPE_ATTRIBUTES(DECL) ((DECL)->decl_common.abstract_origin)
#define METHOD_PROPERTY_CONTEXT(DECL) ((DECL)->decl_common.size_unit)
-#define PROPERTY_NAME(DECL) ((DECL)->decl_minimal.name)
+
+/* PROPERTY_DECL. A PROPERTY_DECL repesents a @property declaration
+ (when attached to the list of properties of an interface) or a
+ @synthesize or @dynamic declaration (when attached to the list of
+ properties of an implementation). */
+
+/* TREE_TYPE is the type (int, float, etc) of the property. */
+
+/* PROPERTY_NAME is the name of the property. */
+#define PROPERTY_NAME(DECL) DECL_NAME(DECL)
+
+/* PROPERTY_GETTER_NAME is the identifier of the getter method. */
#define PROPERTY_GETTER_NAME(DECL) ((DECL)->decl_non_common.arguments)
+
+/* PROPERTY_SETTER_NAME is the identifier of the setter method. */
#define PROPERTY_SETTER_NAME(DECL) ((DECL)->decl_non_common.result)
-#define PROPERTY_IVAR_NAME(DECL) ((DECL)->decl_common.initial)
-#define PROPERTY_READONLY(DECL) ((DECL)->decl_minimal.context)
-#define PROPERTY_COPIES(DECL) ((DECL)->decl_common.size_unit)
-enum objc_property_assign_semantics {
+/* PROPERTY_READONLY can be 0 or 1. */
+#define PROPERTY_READONLY(DECL) DECL_LANG_FLAG_0 (DECL)
+
+/* PROPERTY_NONATOMIC can be 0 or 1. */
+#define PROPERTY_NONATOMIC(DECL) DECL_LANG_FLAG_1 (DECL)
+
+typedef enum objc_property_assign_semantics {
OBJC_PROPERTY_ASSIGN = 1,
OBJC_PROPERTY_RETAIN = 2,
OBJC_PROPERTY_COPY = 3
-};
+} objc_property_assign_semantics;
+
+/* PROPERTY_ASSIGN_SEMANTICS can be OBJC_PROPERTY_ASSIGN,
+ OBJC_PROPERTY_RETAIN or OBJC_PROPERTY_COPY. We need an integer to
+ store it, so we hijack the alignment, that properties don't
+ have. */
+#define PROPERTY_ASSIGN_SEMANTICS(DECL) ((DECL)->decl_common.align)
+
+/* PROPERTY_IVAR_NAME is the identifier of the instance variable.
+ This is set only if the PROPERTY_DECL represents a @synthesize;
+ otherwise, it is set to TREE_NULL. */
+#define PROPERTY_IVAR_NAME(DECL) ((DECL)->decl_common.initial)
+
+/* PROPERTY_DYNAMIC can be 0 or 1. This is 1 if the PROPERTY_DECL
+ represents a @dynamic (or if it is a @property for which a @dynamic
+ declaration has been parsed); otherwise, it is set to 0. */
+#define PROPERTY_DYNAMIC(DECL) DECL_LANG_FLAG_2 (DECL)
+
+
+/* PROPERTY_REF. A PROPERTY_REF represents an 'object.property'
+ expression. */
+
+/* PROPERTY_REF_OBJECT is the object whose property we are
+ accessing. */
+#define PROPERTY_REF_OBJECT(NODE) TREE_OPERAND (PROPERTY_REF_CHECK (NODE), 0)
+
+/* PROPERTY_REF_PROPERTY_DECL is the PROPERTY_DECL for the property
+ used in the expression. From it, you can get the property type,
+ and the getter/setter names. */
+#define PROPERTY_REF_PROPERTY_DECL(NODE) TREE_OPERAND (PROPERTY_REF_CHECK (NODE), 1)
+
/* CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
CATEGORY_INTERFACE_TYPE, CATEGORY_IMPLEMENTATION_TYPE,
diff --git a/gcc/objc/objc-tree.def b/gcc/objc/objc-tree.def
index b567347..5da2671 100644
--- a/gcc/objc/objc-tree.def
+++ b/gcc/objc/objc-tree.def
@@ -40,6 +40,24 @@ DEFTREECODE (PROPERTY_DECL, "property_decl", tcc_declaration, 0)
DEFTREECODE (MESSAGE_SEND_EXPR, "message_send_expr", tcc_expression, 3)
DEFTREECODE (CLASS_REFERENCE_EXPR, "class_reference_expr", tcc_expression, 1)
+/* This tree is used to represent the expression 'object.property',
+ where 'object' is an Objective-C object and 'property' is an
+ Objective-C property. Operand 0 is the object (the tree
+ representing the expression), and Operand 1 is the property (the
+ PROPERTY_DECL). A PROPERTY_REF tree needs to be transformed into
+ 'setter' and 'getter' calls at some point; at the moment this
+ happens in two places:
+
+ * if we detect that a modify expression is being applied to a
+ PROPERTY_REF, then we transform that into a 'getter' call (this
+ happens in build_modify_expr() or cp_build_modify_expr()).
+
+ * else, it will remain as a PROPERTY_REF until we get to
+ gimplification; at that point, we convert each PROPERTY_REF into
+ a 'getter' call during ObjC/ObjC++ gimplify.
+*/
+DEFTREECODE (PROPERTY_REF, "property_ref", tcc_expression, 2)
+
/*
Local variables:
mode:c
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7000b10..00e05ef 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,64 @@
+2010-10-30 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ Implemented Objective-C 2.0 @property, @synthesize and @dynamic.
+ * objc.dg/property/property-neg-1.m: Updated for changes in the
+ syntax of @property and the implementation of
+ @synthesize/@dynamic.
+ * objc.dg/property/property-neg-2.m: Same change.
+ * objc.dg/property/property-neg-3.m: Same change.
+ * objc.dg/property/property-neg-4.m: Same change.
+ * objc.dg/property/property-neg-5.m: Same change.
+ * objc.dg/property/property-neg-7.m: Same change.
+ * objc.dg/property/property-1.m: Same change.
+ * objc.dg/property/synthesize-1.m: Same change.
+ * objc.dg/property/at-property-2.m: Same change.
+ * objc.dg/property/at-property-4.m: Same change.
+
+ * objc.dg/property/fsf-property-method-acces.m: Updated for
+ changes in the syntax of @property and the implementation of
+ @synthesize/@dynamic. Use the same code for GNU and NeXT runtime.
+ * objc.dg/property/fsf-property-basic.m: Same change.
+ * objc.dg/property/fsf-property-named-ivar.m: Same change.
+
+ * objc.dg/property/at-property-5.m: New.
+ * objc.dg/property/at-property-6.m: New.
+ * objc.dg/property/at-property-7.m: New.
+ * objc.dg/property/at-property-8.m: New.
+ * objc.dg/property/at-property-9.m: New.
+ * objc.dg/property/at-property-10.m: New.
+ * objc.dg/property/at-property-11.m: New.
+ * objc.dg/property/synthesize-2.m: New.
+ * objc.dg/property/dynamic-2.m: New.
+
+ * obj-c++.dg/property/property-neg-1.mm: Updated for changes in the
+ syntax of @property and the implementation of
+ @synthesize/@dynamic.
+ * obj-c++.dg/property/property-neg-2.mm: Same change.
+ * obj-c++.dg/property/property-neg-3.mm: Same change.
+ * obj-c++.dg/property/property-neg-4.mm: Same change.
+ * obj-c++.dg/property/property-neg-5.mm: Same change.
+ * obj-c++.dg/property/property-neg-7.mm: Same change.
+ * obj-c++.dg/property/property-1.mm: Same change.
+ * obj-c++.dg/property/synthesize-1.mm: Same change.
+ * obj-c++.dg/property/at-property-2.mm: Same change.
+ * obj-c++.dg/property/at-property-4.mm: Same change.
+
+ * obj-c++.dg/property/fsf-property-method-acces.mm: Updated for
+ changes in the syntax of @property and the implementation of
+ @synthesize/@dynamic. Use the same code for GNU and NeXT runtime.
+ * obj-c++.dg/property/fsf-property-basic.mm: Same change.
+ * obj-c++.dg/property/fsf-property-named-ivar.mm: Same change.
+
+ * obj-c++.dg/property/at-property-5.mm: New.
+ * obj-c++.dg/property/at-property-6.mm: New.
+ * obj-c++.dg/property/at-property-7.mm: New.
+ * obj-c++.dg/property/at-property-8.mm: New.
+ * obj-c++.dg/property/at-property-9.mm: New.
+ * obj-c++.dg/property/at-property-10.mm: New.
+ * obj-c++.dg/property/at-property-11.mm: New.
+ * obj-c++.dg/property/synthesize-2.mm: New.
+ * obj-c++.dg/property/dynamic-2.mm: New.
+
2010-10-29 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
Andrew Pinski <pinskia@gmail.com>
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-10.mm b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm
new file mode 100644
index 0000000..f130292
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm
@@ -0,0 +1,100 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax in a number of expressions. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+int
+test (int g)
+{
+ return g;
+}
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+ MyRootClass *object2 = [[MyRootClass alloc] init];
+
+ object.a = 14;
+ object.a = object.a + object.a;
+
+ if (object.a != 28)
+ abort ();
+
+ object.a = 99;
+ /* TODO: The following one does not work yet. */
+ /* object.a++; */
+ object.a = object.a + 1;
+
+ if (object.a != 100)
+ abort ();
+
+ object.a = 99;
+ object.a *= 2;
+
+ if (object.a != 198)
+ abort ();
+
+ {
+ int f = object.a;
+
+ if (f != 198)
+ abort ();
+
+ if (f != object.a)
+ abort ();
+
+ if (object.a != f)
+ abort ();
+
+ object.a = object.a;
+
+ if (object.a != 198)
+ abort ();
+ }
+
+ if (test (object.a) != 198)
+ abort ();
+
+ object.a = -object.a;
+
+ if (object.a != -198)
+ abort ();
+
+ /* TODO: The following one does not work yet. */
+ /* for (object.a = 0; object.a < 99; object.a++) */
+ for (object.a = 0; object.a < 99; object.a = object.a + 1)
+ object2.a = object.a;
+
+ if (object2.a != object.a - 1)
+ abort ();
+
+ if (object2.a != 98)
+ abort ();
+
+ if (object.a != 99)
+ abort ();
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-11.mm b/gcc/testsuite/obj-c++.dg/property/at-property-11.mm
new file mode 100644
index 0000000..36da7bf
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-11.mm
@@ -0,0 +1,43 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test that properties are found even if implemented in superclasses. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+@interface MySubClass : MyRootClass
+@end
+
+@implementation MySubClass
+@end
+
+int main (void)
+{
+ MySubClass *object = [[MySubClass alloc] init];
+
+ object.a = 40;
+ if (object.a != 40)
+ abort ();
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-2.mm b/gcc/testsuite/obj-c++.dg/property/at-property-2.mm
index 7442251..a97c33e 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-2.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-2.mm
@@ -6,8 +6,8 @@
{
Class isa;
}
-@property id name __attribute__((deprecated));
-@property id table __attribute__((xxx)); /* { dg-warning ".xxx. attribute directive ignored" } */
+@property int name __attribute__((deprecated));
+@property int table __attribute__((xxx)); /* { dg-warning ".xxx. attribute directive ignored" } */
@property void function (void); /* { dg-error "can.t make .function. into a method" } */
@property typedef int j; /* { dg-error "invalid type for property" } */
@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 05223a3..e327930 100644
--- a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm
@@ -6,36 +6,35 @@
{
Class isa;
}
-- (id) myGetter;
-- (id) myGetterB;
-- (void) mySetter: (id)property;
-- (void) mySetterB: (id)property;
+- (int) myGetter;
+- (int) myGetterB;
+- (int) myGetter2;
+- (void) mySetter: (int)property;
+- (void) mySetterB: (int)property;
+- (void) mySetter2: (int)property;
/* Test that all the new property attributes can be parsed. */
@property (assign) id property_a;
@property (copy) id property_b;
-@property (nonatomic) id property_c;
-@property (readonly) id property_d;
-@property (readwrite) id property_e;
+@property (nonatomic) int property_c;
+@property (readonly) int property_d;
+@property (readwrite) int property_e;
@property (retain) id property_f;
-@property (release) id property_g; /* { dg-error "unknown property attribute" } */
+@property (release) int property_g; /* { dg-error "unknown property attribute" } */
-/* The following will be enabled when @synthesized is implemented. */
-/* @property (getter=myGetter) id property_h; */
-/* @property (setter=mySetter:) id property_i; */
+@property (getter=myGetter) int property_h;
+@property (setter=mySetter:) int property_i;
/* Now test various problems. */
@property (readonly, readwrite) int a; /* { dg-error ".readonly. attribute conflicts with .readwrite. attribute" } */
-/* The following will be enabled when @synthesized is implemented. */
-/* @property (readonly, setter=setA:) int b; */ /* dg-warning ".readonly. attribute conflicts with .setter. attribute" */
+@property (readonly, setter=mySetterB:) int b; /* { dg-warning ".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 (copy, retain) id e; /* { dg-error ".retain. attribute conflicts with .copy. attribute" } */
-/* The following will be enabled when @synthesized is implemented. */
-/* @property (setter=mySetter:,setter=mySetterB:) id f; */ /* dg-error ".setter. attribute may only be specified once" */
-/* @property (getter=myGetter:,getter=myGetterB:) id f; */ /* dg-error ".getter. attribute may only be specified once" */
+@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" } */
@end
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-5.mm b/gcc/testsuite/obj-c++.dg/property/at-property-5.mm
new file mode 100644
index 0000000..1e604e9
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-5.mm
@@ -0,0 +1,38 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ id property_a;
+ int property_b;
+ int property_c;
+ int property_d;
+ id property_e;
+ id property_f;
+ id property_g;
+ id property_h;
+}
+
+/* Test various error messages. */
+/* FIXME - there is a problem with the testuite in running the following test. The compiler
+ generates the messages, but the testsuite still complains. */
+/*@property id property_a;*/ /* dg-warning "object property .property.a. has no .assign., .retain. or .copy. attribute" */
+ /* dg-message ".assign. can be unsafe for Objective-C objects" "" { target *-*-* } 20 */
+@property int property_b = 4; /* { dg-error "expected" } */
+@property (retain) int property_c; /* { dg-error ".retain. attribute is only valid for Objective-C objects" } */
+@property (copy) int property_d; /* { dg-error ".copy. attribute is only valid for Objective-C objects" } */
+
+@property (retain) id property_e;
+@property (retain) id property_f;
+@property (retain) id property_g;
+@property (retain) id property_h;
+/* FIXME - there is a problem with the testuite in running the following test. The compiler
+ generates the messages, but the testsuite still complains. */
+/*@property (retain) id property_e;*/ /* dg-error "redeclaration of property .property_e." */
+ /* dg-message "originally declared here" "" { target *-*-* } 26 */
+@end
+
+@property id test; /* { dg-error "misplaced .@property. Objective-C.. construct" } */
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-6.mm b/gcc/testsuite/obj-c++.dg/property/at-property-6.mm
new file mode 100644
index 0000000..3f1f0d3
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-6.mm
@@ -0,0 +1,60 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with non-synthesized setter/getter
+ and with standard names. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+
+- (int) a
+{
+ return a;
+}
+- (void) setA: (int)value
+{
+ a = value;
+}
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ if (object.a != 0)
+ abort ();
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-7.mm b/gcc/testsuite/obj-c++.dg/property/at-property-7.mm
new file mode 100644
index 0000000..cae04de
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-7.mm
@@ -0,0 +1,57 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with non-synthesized setter/getter
+ and with a non-standard name for the getter. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property (getter = getA) int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+
+- (int) getA
+{
+ return a;
+}
+- (void) setA: (int)value
+{
+ a = value;
+}
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-8.mm b/gcc/testsuite/obj-c++.dg/property/at-property-8.mm
new file mode 100644
index 0000000..ec37052
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-8.mm
@@ -0,0 +1,57 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with non-synthesized setter/getter
+ and with a non-standard name for the setter. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property (setter = writeA:) int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+
+- (int) a
+{
+ return a;
+}
+- (void) writeA: (int)value
+{
+ a = value;
+}
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-9.mm b/gcc/testsuite/obj-c++.dg/property/at-property-9.mm
new file mode 100644
index 0000000..12e9ffd
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/at-property-9.mm
@@ -0,0 +1,49 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with synthesized setter/getter
+ and with a non-standard name for the getter and setter. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property (getter = giveMeA, setter = writeA:) int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/dynamic-1.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-1.mm
index d66ef28..4e84843 100644
--- a/gcc/testsuite/obj-c++.dg/property/dynamic-1.mm
+++ b/gcc/testsuite/obj-c++.dg/property/dynamic-1.mm
@@ -20,11 +20,15 @@
int v3;
int v4;
}
+@property int v1;
+@property int v2;
+@property int v3;
+@property int v4;
@end
@implementation Test
@dynamic; /* { dg-error "expected identifier" } */
@dynamic v1, ; /* { dg-error "expected identifier" } */
-@dynamic v1, v2, v3; /* { dg-error ".@dynamic. is not supported in this version of the compiler" } */
-@dynamic v4; /* { dg-error ".@dynamic. is not supported in this version of the compiler" } */
+@dynamic v1, v2, v3;
+@dynamic v4;
@end
diff --git a/gcc/testsuite/obj-c++.dg/property/dynamic-2.mm b/gcc/testsuite/obj-c++.dg/property/dynamic-2.mm
new file mode 100644
index 0000000..acc9374
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/dynamic-2.mm
@@ -0,0 +1,46 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+ Class isa;
+}
+@end
+
+@implementation MyRootClass
+@end
+
+@dynamic isa; /* { dg-error "misplaced .@dynamic. Objective-C.. construct" } */
+
+@interface Test : MyRootClass
+{
+ int v1;
+}
+@end
+@implementation Test
+@end
+
+
+@interface Test (Category)
+@end
+@implementation Test (Category)
+@dynamic v1; /* { dg-error ".@dynamic. can not be used in categories" } */
+@end
+
+
+@interface AnotherTest : MyRootClass
+{
+}
+@property int one;
+@end
+
+@implementation AnotherTest
+@dynamic one;
+/* FIXME - there is a problem with the testuite in running the following test. The compiler
+ generates the messages, but the testsuite still complains. */
+/*@dynamic one;*/ /* dg-error "property .one. already specified in .@dynamic." */
+ /* dg-message "originally specified here" "" { target *-*-* } 40 */
+@dynamic three; /* { dg-error "no declaration of property .three. found in the interface" } */
+@end
diff --git a/gcc/testsuite/obj-c++.dg/property/fsf-property-basic.mm b/gcc/testsuite/obj-c++.dg/property/fsf-property-basic.mm
index 502ac0d..e7f8cbb 100644
--- a/gcc/testsuite/obj-c++.dg/property/fsf-property-basic.mm
+++ b/gcc/testsuite/obj-c++.dg/property/fsf-property-basic.mm
@@ -1,26 +1,16 @@
/* Basic test, auto-generated getter/setter based on property name. */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
#ifdef __cplusplus
extern "C" {
#endif
-extern int printf (const char *fmt,...) ;
+extern int printf (const char *fmt,...);
extern void abort (void);
-typedef struct objc_class *Class;
+#include <objc/objc.h>
+#include <objc/runtime.h>
-#ifdef __NEXT_RUNTIME__
-
-extern id class_createInstance(Class, long);
-#define class_create_instance(C) class_createInstance(C, 0)
-
-#else
-
-extern id class_create_instance(Class);
-
-#endif
#ifdef __cplusplus
}
#endif
@@ -28,28 +18,25 @@ extern id class_create_instance(Class);
@interface Bar
{
@public
-#ifdef __NEXT_RUNTIME__
Class isa;
-#else
- Class class_pointer;
-#endif
- int var;
+ int FooBar;
}
+ (id) initialize;
+ (id) alloc ;
- - (id) init;
-
+- (id) init;
+- (int) whatIsFooBar;
@property int FooBar;
@end
@implementation Bar
+initialize { return self;}
-+ (id) alloc { return class_create_instance(self);}
++ (id) alloc { return class_createInstance (self, 0); }
- (id) init {return self;}
-@property int FooBar ;
+- (int) whatIsFooBar { return self->FooBar; }
+@synthesize FooBar;
@end
int main(int argc, char *argv[]) {
@@ -60,21 +47,23 @@ int main(int argc, char *argv[]) {
and operate correctly. */
[f setFooBar:1];
- if (f->_FooBar != 1)
- { printf ("setFooBar did not set _FooBar\n"); abort ();}
+ if ([f whatIsFooBar] != 1)
+ { printf ("setFooBar did not set FooBar\n"); abort ();}
res = [f FooBar];
if (res != 1 )
{ printf ("[f FooBar] = %d\n", res); abort ();}
- /* Now check the short-cut CLASS.property syntax. */
+ /* Now check the short-cut object.property syntax. */
+ /* Read... */
res = f.FooBar;
if (res != 1 )
- { printf ("f,FooBar = %d\n", res); abort ();}
-
+ { printf ("f.FooBar = %d\n", res); abort ();}
+
+ /* .... write. */
f.FooBar = 0;
- printf ("seems OK\n", res);
+ /* printf ("seems OK\n", res); */
return f.FooBar;
}
diff --git a/gcc/testsuite/obj-c++.dg/property/fsf-property-method-access.mm b/gcc/testsuite/obj-c++.dg/property/fsf-property-method-access.mm
index 4052d16..8053c84 100644
--- a/gcc/testsuite/obj-c++.dg/property/fsf-property-method-access.mm
+++ b/gcc/testsuite/obj-c++.dg/property/fsf-property-method-access.mm
@@ -1,25 +1,16 @@
/* test access in methods, auto-generated getter/setter based on property name. */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
#ifdef __cplusplus
extern "C" {
#endif
-extern int printf (const char *fmt,...) ;
-extern void abort (void);
-
-typedef struct objc_class *Class;
-
-#ifdef __NEXT_RUNTIME__
-
-extern id class_createInstance(Class, long);
-#define class_create_instance(C) class_createInstance(C, 0)
-#else
+extern int printf (const char *fmt,...);
+extern void abort (void);
-extern id class_create_instance(Class);
+#include <objc/objc.h>
+#include <objc/runtime.h>
-#endif
#ifdef __cplusplus
}
#endif
@@ -27,11 +18,8 @@ extern id class_create_instance(Class);
@interface Bar
{
@public
-#ifdef __NEXT_RUNTIME__
Class isa;
-#else
- Class class_pointer;
-#endif
+ int FooBar;
}
+ (id) initialize;
+ (id) alloc ;
@@ -46,11 +34,11 @@ extern id class_create_instance(Class);
@implementation Bar
+initialize { return self;}
-+ (id) alloc { return class_create_instance(self);}
++ (id) alloc { return class_createInstance(self, 0);}
- (id) init {return self;}
-@property int FooBar;
+@synthesize FooBar;
- (int) lookAtProperty { return FooBar; }
- (void) setProperty: (int) v { FooBar = v; }
@@ -65,8 +53,8 @@ int main(int argc, char *argv[]) {
and operate correctly. */
[f setProperty:11];
- if (f->_FooBar != 11)
- { printf ("setProperty did not set _FooBar\n"); abort ();}
+ if (f.FooBar != 11)
+ { printf ("setProperty did not set FooBar\n"); abort ();}
res = [f lookAtProperty];
if (res != 11 )
diff --git a/gcc/testsuite/obj-c++.dg/property/fsf-property-named-ivar.mm b/gcc/testsuite/obj-c++.dg/property/fsf-property-named-ivar.mm
index 4b29c92..8538a1f 100644
--- a/gcc/testsuite/obj-c++.dg/property/fsf-property-named-ivar.mm
+++ b/gcc/testsuite/obj-c++.dg/property/fsf-property-named-ivar.mm
@@ -1,25 +1,16 @@
/* Basic test, auto-generated getter/setter based on named ivar */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
#ifdef __cplusplus
extern "C" {
#endif
-extern int printf (const char *fmt,...) ;
-extern void abort (void);
-
-typedef struct objc_class *Class;
-
-#ifdef __NEXT_RUNTIME__
-
-extern id class_createInstance(Class, long);
-#define class_create_instance(C) class_createInstance(C, 0)
-#else
+extern int printf (const char *fmt,...);
+extern void abort (void);
-extern id class_create_instance(Class);
+#include <objc/objc.h>
+#include <objc/runtime.h>
-#endif
#ifdef __cplusplus
}
#endif
@@ -27,11 +18,7 @@ extern id class_create_instance(Class);
@interface Bar
{
@public
-#ifdef __NEXT_RUNTIME__
Class isa;
-#else
- Class class_pointer;
-#endif
int var;
}
+ (id) initialize;
@@ -44,11 +31,11 @@ extern id class_create_instance(Class);
@implementation Bar
+initialize { return self;}
-+ (id) alloc { return class_create_instance(self);}
++ (id) alloc { return class_createInstance (self, 0); }
- (id) init {return self;}
-@property (ivar = var) int FooBar ;
+@synthesize FooBar = var;
@end
int main(int argc, char *argv[]) {
@@ -67,7 +54,7 @@ int main(int argc, char *argv[]) {
if (res != 1234 )
{ printf ("[f FooBar] = %d\n", res); abort ();}
- /* Now check the short-cut CLASS.property syntax. */
+ /* Now check the short-cut object.property syntax. */
/* Read .... */
res = f.FooBar;
if (res != 1234 )
diff --git a/gcc/testsuite/obj-c++.dg/property/property-1.mm b/gcc/testsuite/obj-c++.dg/property/property-1.mm
index c9b9c46..b89d34b 100644
--- a/gcc/testsuite/obj-c++.dg/property/property-1.mm
+++ b/gcc/testsuite/obj-c++.dg/property/property-1.mm
@@ -1,6 +1,5 @@
/* This program tests use of property provided setter/getter functions. */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
/* { dg-additional-sources "../../objc-obj-c++-shared/Object1.mm" } */
#import "../../objc-obj-c++-shared/Object1.h"
@@ -9,11 +8,11 @@
{
int iVar;
}
-@property int FooBar;
+@property (setter=MySetter:) int FooBar;
@end
@implementation Bar
-@property (ivar = iVar, setter = MySetter:) int FooBar;
+@synthesize FooBar=iVar;
- (void) MySetter : (int) value { iVar = value; }
diff --git a/gcc/testsuite/obj-c++.dg/property/property-neg-1.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-1.mm
index 2989c3b..cae1a56 100644
--- a/gcc/testsuite/obj-c++.dg/property/property-neg-1.mm
+++ b/gcc/testsuite/obj-c++.dg/property/property-neg-1.mm
@@ -1,14 +1,13 @@
-/* This program checks for proper use of 'readonly' attribute. */
/* { dg-do compile } */
@interface Bar
{
int iVar;
}
-@property (readonly) int FooBar;
+@property int fooBar;
@end
@implementation Bar
-@property int FooBar; /* { dg-error " property 'FooBar' 'readonly' attribute conflicts with its interface version" } */
-
-@end
+@end /* { dg-warning "incomplete implementation of class .Bar." } */
+ /* { dg-warning "method definition for .-setFooBar:. not found" "" { target *-*-* } 11 } */
+ /* { dg-warning "method definition for .-fooBar. not found" "" { target *-*-* } 11 } */
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 7046da8..f730fe8 100644
--- a/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm
+++ b/gcc/testsuite/obj-c++.dg/property/property-neg-2.mm
@@ -1,9 +1,8 @@
-/* This program checks for proper declaration of property. */
/* { dg-do compile } */
@interface Bar
@end
@implementation Bar
-@property int foo; /* { dg-error "no declaration of property 'foo' found in the interface" } */
+@property int FooBar; /* { dg-error "property declaration not in @interface or @protocol context" } */
@end
diff --git a/gcc/testsuite/obj-c++.dg/property/property-neg-3.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-3.mm
index 07438a6..a749c28 100644
--- a/gcc/testsuite/obj-c++.dg/property/property-neg-3.mm
+++ b/gcc/testsuite/obj-c++.dg/property/property-neg-3.mm
@@ -1,14 +1,16 @@
-/* Property name cannot match the ivar name. */
/* { dg-do compile } */
-/* Suppress warnings for incomplete class definition etc. */
-/* { dg-options "-w" } */
@interface Person
{
char *firstName;
}
-@property char *firstName; /* { dg-error "property 'firstName' may not have the same name as an ivar in the class" } */
+@property char *firstName;
@end
@implementation Person
-@end
+@dynamic firstName;
+/* FIXME - there is a problem with the testuite in running the following test. The compiler
+ generates the messages, but the testsuite still complains. */
+/*@synthesize firstName;*/ /* dg-error "property .firstName. already specified in .@dynamic." */
+ /* dg-message "originally specified here" "" { target *-*-* } 11 */
+@end
diff --git a/gcc/testsuite/obj-c++.dg/property/property-neg-4.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-4.mm
index b3dbb60..cc25d84 100644
--- a/gcc/testsuite/obj-c++.dg/property/property-neg-4.mm
+++ b/gcc/testsuite/obj-c++.dg/property/property-neg-4.mm
@@ -1,18 +1,17 @@
-/* Property cannot be accessed in class method. */
/* { dg-do compile } */
@interface Person
{
+ char *fullName;
}
@property char *fullName;
+ (void) testClass;
@end
+
@implementation Person
-@property char *fullName;
+@synthesize fullName;
+ (void) testClass {
- fullName = "MyName"; /* { dg-error "property 'fullName' accessed in class method" } */
- /* { dg-error "'fullName' was not declared in this scope" "" { target *-*-* } 14 } */
+ self.fullName = "MyName"; /* { dg-error "request for member .fullName." } */
}
@end
-
diff --git a/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm
index 7a9090a..403f684 100644
--- a/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm
+++ b/gcc/testsuite/obj-c++.dg/property/property-neg-5.mm
@@ -1,7 +1,5 @@
-/* getter/setter cannot be specified in an interface. */
/* { dg-do compile } */
@interface Foo
@property ( readonly, getter = HELLO, setter = THERE : ) int value; /* { dg-warning ".readonly. attribute conflicts with .setter. attribute" } */
-@end /* { dg-warning "getter = \\'HELLO\\' may not be specified in an interface" } */
- /* { dg-warning "setter = \\'THERE\\:\\' may not be specified in an interface" "" { target *-*-* } 6 } */
+@end
diff --git a/gcc/testsuite/obj-c++.dg/property/property-neg-7.mm b/gcc/testsuite/obj-c++.dg/property/property-neg-7.mm
index 506f097..4c3d5d7 100644
--- a/gcc/testsuite/obj-c++.dg/property/property-neg-7.mm
+++ b/gcc/testsuite/obj-c++.dg/property/property-neg-7.mm
@@ -1,13 +1,14 @@
-/* Cannot write into a read-only property. */
/* { dg-do compile } */
-/* Suppress warnings for incomplete class definition etc. */
-/* { dg-options "-w" } */
@interface NSArray
+{
+ int count;
+}
@property(readonly) int count;
@end
@implementation NSArray
+@synthesize count;
@end
void foo (NSArray *ans[], id pid, id apid[], int i) {
diff --git a/gcc/testsuite/obj-c++.dg/property/synthesize-1.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-1.mm
index fb9b38e..3513c01 100644
--- a/gcc/testsuite/obj-c++.dg/property/synthesize-1.mm
+++ b/gcc/testsuite/obj-c++.dg/property/synthesize-1.mm
@@ -19,13 +19,35 @@
int v2;
int v3;
int v4;
+ int v5;
+ int v6;
+ int v7;
+ int v8;
}
+@property int v1;
+@property int v2;
+@property int v3;
+@property int v4;
+@property int v5;
+@property int v6;
+@property int v7;
+@property int v8;
@end
@implementation Test
@synthesize; /* { dg-error "expected identifier" } */
@synthesize v1, ; /* { dg-error "expected identifier" } */
-@synthesize v1, v2 = ; /* { dg-error "expected identifier" } */
-@synthesize v1, v2=v2, v3 = v3,v4; /* { dg-error ".@synthesize. is not supported in this version of the compiler" } */
-@synthesize v4; /* { dg-error ".@synthesize. is not supported in this version of the compiler" } */
+@synthesize v2, v3 = ; /* { dg-error "expected identifier" } */
+@synthesize v4, v5=v6, v6 = v5,v7;
+@synthesize v8;
+/* Some of the @synthesize above will fail due to syntax errors. The
+ compiler will then complain that the methods implementing the
+ properties are missing. That is correct, but we are not
+ interested. The following ones shut up the compiler. */
+- (int) v1 { return v1; }
+- (void) setV1: (int)a { v1 = a; }
+- (int) v2 { return v2; }
+- (void) setV2: (int)a { v2 = a; }
+- (int) v3 { return v3; }
+- (void) setV3: (int)a { v3 = a; }
@end
diff --git a/gcc/testsuite/obj-c++.dg/property/synthesize-2.mm b/gcc/testsuite/obj-c++.dg/property/synthesize-2.mm
new file mode 100644
index 0000000..dfa3fd5
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/property/synthesize-2.mm
@@ -0,0 +1,51 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+#include <objc/objc.h>
+#include <objc/runtime.h>
+#include <stdlib.h>
+
+@interface MyRootClass
+{
+ Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@interface Test : MyRootClass
+{
+ int v1;
+}
+@property int v1;
+/* TODO: Test more types of properties with different semantics
+ (retain, copy, atomic, nonatomic, and test various C and
+ Objective-C types). */
+@end
+
+@implementation Test
+@synthesize v1;
+@end
+
+int main ()
+{
+ Test *object = [[Test alloc] init];
+
+ /* Check that the synthesized methods exist and work. Do not invoke
+ them via property syntax - that is another test. Here we just
+ want to test the synthesis of the methods. */
+ [object setV1: 400];
+
+ if ([object v1] != 400)
+ abort ();
+
+ return (0);
+}
+
diff --git a/gcc/testsuite/objc.dg/property/at-property-10.m b/gcc/testsuite/objc.dg/property/at-property-10.m
new file mode 100644
index 0000000..bc6380c
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-10.m
@@ -0,0 +1,100 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax in a number of expressions. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+int
+test (int g)
+{
+ return g;
+}
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+ MyRootClass *object2 = [[MyRootClass alloc] init];
+
+ object.a = 14;
+ object.a = object.a + object.a;
+
+ if (object.a != 28)
+ abort ();
+
+ object.a = 99;
+ /* TODO: The following one does not work yet. */
+ /* object.a++; */
+ object.a = object.a + 1;
+
+ if (object.a != 100)
+ abort ();
+
+ object.a = 99;
+ object.a *= 2;
+
+ if (object.a != 198)
+ abort ();
+
+ {
+ int f = object.a;
+
+ if (f != 198)
+ abort ();
+
+ if (f != object.a)
+ abort ();
+
+ if (object.a != f)
+ abort ();
+
+ object.a = object.a;
+
+ if (object.a != 198)
+ abort ();
+ }
+
+ if (test (object.a) != 198)
+ abort ();
+
+ object.a = -object.a;
+
+ if (object.a != -198)
+ abort ();
+
+ /* TODO: The following one does not work yet. */
+ /* for (object.a = 0; object.a < 99; object.a++) */
+ for (object.a = 0; object.a < 99; object.a = object.a + 1)
+ object2.a = object.a;
+
+ if (object2.a != object.a - 1)
+ abort ();
+
+ if (object2.a != 98)
+ abort ();
+
+ if (object.a != 99)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-11.m b/gcc/testsuite/objc.dg/property/at-property-11.m
new file mode 100644
index 0000000..84857e0
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-11.m
@@ -0,0 +1,43 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test that properties are found even if implemented in superclasses. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+@interface MySubClass : MyRootClass
+@end
+
+@implementation MySubClass
+@end
+
+int main (void)
+{
+ MySubClass *object = [[MySubClass alloc] init];
+
+ object.a = 40;
+ if (object.a != 40)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-2.m b/gcc/testsuite/objc.dg/property/at-property-2.m
index 23bd485..19d59fd 100644
--- a/gcc/testsuite/objc.dg/property/at-property-2.m
+++ b/gcc/testsuite/objc.dg/property/at-property-2.m
@@ -6,8 +6,8 @@
{
Class isa;
}
-@property id name __attribute__((deprecated));
-@property id table __attribute__((xxx)); /* { dg-warning ".xxx. attribute directive ignored" } */
+@property int name __attribute__((deprecated));
+@property int table __attribute__((xxx)); /* { dg-warning ".xxx. attribute directive ignored" } */
@property void function (void); /* { dg-error "declared as a function" } */
@property typedef int j; /* { dg-error "expected" } */
@end
diff --git a/gcc/testsuite/objc.dg/property/at-property-4.m b/gcc/testsuite/objc.dg/property/at-property-4.m
index 05223a3..e327930 100644
--- a/gcc/testsuite/objc.dg/property/at-property-4.m
+++ b/gcc/testsuite/objc.dg/property/at-property-4.m
@@ -6,36 +6,35 @@
{
Class isa;
}
-- (id) myGetter;
-- (id) myGetterB;
-- (void) mySetter: (id)property;
-- (void) mySetterB: (id)property;
+- (int) myGetter;
+- (int) myGetterB;
+- (int) myGetter2;
+- (void) mySetter: (int)property;
+- (void) mySetterB: (int)property;
+- (void) mySetter2: (int)property;
/* Test that all the new property attributes can be parsed. */
@property (assign) id property_a;
@property (copy) id property_b;
-@property (nonatomic) id property_c;
-@property (readonly) id property_d;
-@property (readwrite) id property_e;
+@property (nonatomic) int property_c;
+@property (readonly) int property_d;
+@property (readwrite) int property_e;
@property (retain) id property_f;
-@property (release) id property_g; /* { dg-error "unknown property attribute" } */
+@property (release) int property_g; /* { dg-error "unknown property attribute" } */
-/* The following will be enabled when @synthesized is implemented. */
-/* @property (getter=myGetter) id property_h; */
-/* @property (setter=mySetter:) id property_i; */
+@property (getter=myGetter) int property_h;
+@property (setter=mySetter:) int property_i;
/* Now test various problems. */
@property (readonly, readwrite) int a; /* { dg-error ".readonly. attribute conflicts with .readwrite. attribute" } */
-/* The following will be enabled when @synthesized is implemented. */
-/* @property (readonly, setter=setA:) int b; */ /* dg-warning ".readonly. attribute conflicts with .setter. attribute" */
+@property (readonly, setter=mySetterB:) int b; /* { dg-warning ".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 (copy, retain) id e; /* { dg-error ".retain. attribute conflicts with .copy. attribute" } */
-/* The following will be enabled when @synthesized is implemented. */
-/* @property (setter=mySetter:,setter=mySetterB:) id f; */ /* dg-error ".setter. attribute may only be specified once" */
-/* @property (getter=myGetter:,getter=myGetterB:) id f; */ /* dg-error ".getter. attribute may only be specified once" */
+@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" } */
@end
diff --git a/gcc/testsuite/objc.dg/property/at-property-5.m b/gcc/testsuite/objc.dg/property/at-property-5.m
new file mode 100644
index 0000000..e4abd27
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-5.m
@@ -0,0 +1,34 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ id property_a;
+ int property_b;
+ int property_c;
+ int property_d;
+ id property_e;
+ id property_f;
+ id property_g;
+ id property_h;
+}
+
+/* Test various error messages. */
+@property id property_a; /* { dg-warning "object property .property.a. has no .assign., .retain. or .copy. attribute" } */
+ /* { dg-message ".assign. can be unsafe for Objective-C objects" "" { target *-*-* } 20 } */
+@property int property_b = 4; /* { dg-error "expected" } */
+@property (retain) int property_c; /* { dg-error ".retain. attribute is only valid for Objective-C objects" } */
+@property (copy) int property_d; /* { dg-error ".copy. attribute is only valid for Objective-C objects" } */
+
+@property (retain) id property_e;
+@property (retain) id property_f;
+@property (retain) id property_g;
+@property (retain) id property_h;
+@property (retain) id property_e; /* { dg-error "redeclaration of property .property_e." } */
+ /* { dg-message "originally declared here" "" { target *-*-* } 26 } */
+@end
+
+@property id test; /* { dg-error "property declaration not in .interface or .protocol context" } */
diff --git a/gcc/testsuite/objc.dg/property/at-property-6.m b/gcc/testsuite/objc.dg/property/at-property-6.m
new file mode 100644
index 0000000..a97c0b0
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-6.m
@@ -0,0 +1,60 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with non-synthesized setter/getter
+ and with standard names. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+
+- (int) a
+{
+ return a;
+}
+- (void) setA: (int)value
+{
+ a = value;
+}
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ if (object.a != 0)
+ abort ();
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-7.m b/gcc/testsuite/objc.dg/property/at-property-7.m
new file mode 100644
index 0000000..dce2764
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-7.m
@@ -0,0 +1,57 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with non-synthesized setter/getter
+ and with a non-standard name for the getter. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property (getter = getA) int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+
+- (int) getA
+{
+ return a;
+}
+- (void) setA: (int)value
+{
+ a = value;
+}
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-8.m b/gcc/testsuite/objc.dg/property/at-property-8.m
new file mode 100644
index 0000000..eb15889
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-8.m
@@ -0,0 +1,57 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with non-synthesized setter/getter
+ and with a non-standard name for the setter. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property (setter = writeA:) int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+
+- (int) a
+{
+ return a;
+}
+- (void) writeA: (int)value
+{
+ a = value;
+}
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-9.m b/gcc/testsuite/objc.dg/property/at-property-9.m
new file mode 100644
index 0000000..203eb30
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/at-property-9.m
@@ -0,0 +1,49 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+/* Test the property syntax with synthesized setter/getter
+ and with a non-standard name for the getter and setter. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+ Class isa;
+ int a;
+}
+@property (getter = giveMeA, setter = writeA:) int a;
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@synthesize a;
+@end
+
+int main (void)
+{
+ MyRootClass *object = [[MyRootClass alloc] init];
+
+ object.a = 14;
+
+ if (object.a != 14)
+ abort ();
+
+ object.a = 23;
+
+ if (object.a != 23)
+ abort ();
+
+ object.a = 78;
+
+ if (object.a != 78)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/dynamic-1.m b/gcc/testsuite/objc.dg/property/dynamic-1.m
index b91a030..8f97371 100644
--- a/gcc/testsuite/objc.dg/property/dynamic-1.m
+++ b/gcc/testsuite/objc.dg/property/dynamic-1.m
@@ -20,11 +20,15 @@
int v3;
int v4;
}
+@property int v1;
+@property int v2;
+@property int v3;
+@property int v4;
@end
@implementation Test
@dynamic; /* { dg-error "expected identifier" } */
@dynamic v1, ; /* { dg-error "expected identifier" } */
-@dynamic v1, v2, v3; /* { dg-error ".@dynamic. is not supported in this version of the compiler" } */
-@dynamic v4; /* { dg-error ".@dynamic. is not supported in this version of the compiler" } */
+@dynamic v1, v2, v3;
+@dynamic v4;
@end
diff --git a/gcc/testsuite/objc.dg/property/dynamic-2.m b/gcc/testsuite/objc.dg/property/dynamic-2.m
new file mode 100644
index 0000000..313d8dc
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/dynamic-2.m
@@ -0,0 +1,44 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+@interface MyRootClass
+{
+ Class isa;
+}
+@end
+
+@implementation MyRootClass
+@end
+
+@dynamic isa; /* { dg-error ".@dynamic. not in @implementation context" } */
+
+@interface Test : MyRootClass
+{
+ int v1;
+}
+@end
+@implementation Test
+@end
+
+
+@interface Test (Category)
+@end
+@implementation Test (Category)
+@dynamic v1; /* { dg-error ".@dynamic. can not be used in categories" } */
+@end
+
+
+@interface AnotherTest : MyRootClass
+{
+}
+@property int one;
+@end
+
+@implementation AnotherTest
+@dynamic one;
+@dynamic one; /* { dg-error "property .one. already specified in .@dynamic." } */
+ /* { dg-message "originally specified here" "" { target *-*-* } 40 } */
+@dynamic three; /* { dg-error "no declaration of property .three. found in the interface" } */
+@end
diff --git a/gcc/testsuite/objc.dg/property/fsf-property-basic.m b/gcc/testsuite/objc.dg/property/fsf-property-basic.m
index 13a00a2..20fd978 100644
--- a/gcc/testsuite/objc.dg/property/fsf-property-basic.m
+++ b/gcc/testsuite/objc.dg/property/fsf-property-basic.m
@@ -1,47 +1,34 @@
/* Basic test, auto-generated getter/setter based on property name. */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
extern int printf (char *fmt,...) ;
extern void abort (void);
-typedef struct objc_class *Class;
-
-#ifdef __NEXT_RUNTIME__
-
-extern id class_createInstance(Class, long);
-#define class_create_instance(C) class_createInstance(C, 0)
-
-#else
-
-extern id class_create_instance(Class);
-
-#endif
+#include <objc/objc.h>
+#include <objc/runtime.h>
@interface Bar
{
@public
-#ifdef __NEXT_RUNTIME__
Class isa;
-#else
- Class class_pointer;
-#endif
+ int FooBar;
}
+ (id) initialize;
+ (id) alloc ;
- (id) init;
-
+- (int) whatIsFooBar;
@property int FooBar;
@end
@implementation Bar
+initialize { return self;}
-+ (id) alloc { return class_create_instance(self);}
++ (id) alloc { return class_createInstance (self, 0); }
- (id) init {return self;}
-@property int FooBar ;
+- (int) whatIsFooBar { return self->FooBar; }
+@synthesize FooBar;
@end
int main(int argc, char *argv[]) {
@@ -52,15 +39,15 @@ int main(int argc, char *argv[]) {
and operate correctly. */
[f setFooBar:1];
- if (f->_FooBar != 1)
- { printf ("setFooBar did not set _FooBar\n"); abort ();}
+ if ([f whatIsFooBar] != 1)
+ { printf ("setFooBar did not set FooBar\n"); abort ();}
res = [f FooBar];
if (res != 1 )
{ printf ("[f FooBar] = %d\n", res); abort ();}
- /* Now check the short-cut CLASS.property syntax. */
+ /* Now check the short-cut object.property syntax. */
/* Read... */
res = f.FooBar;
if (res != 1 )
diff --git a/gcc/testsuite/objc.dg/property/fsf-property-method-access.m b/gcc/testsuite/objc.dg/property/fsf-property-method-access.m
index fae4969..866f522 100644
--- a/gcc/testsuite/objc.dg/property/fsf-property-method-access.m
+++ b/gcc/testsuite/objc.dg/property/fsf-property-method-access.m
@@ -1,31 +1,17 @@
/* test access in methods, auto-generated getter/setter based on property name. */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
extern int printf (char *fmt,...) ;
extern void abort (void);
-typedef struct objc_class *Class;
-
-#ifdef __NEXT_RUNTIME__
-
-extern id class_createInstance(Class, long);
-#define class_create_instance(C) class_createInstance(C, 0)
-
-#else
-
-extern id class_create_instance(Class);
-
-#endif
+#include <objc/objc.h>
+#include <objc/runtime.h>
@interface Bar
{
@public
-#ifdef __NEXT_RUNTIME__
Class isa;
-#else
- Class class_pointer;
-#endif
+ int FooBar;
}
+ (id) initialize;
+ (id) alloc ;
@@ -40,11 +26,11 @@ extern id class_create_instance(Class);
@implementation Bar
+initialize { return self;}
-+ (id) alloc { return class_create_instance(self);}
++ (id) alloc { return class_createInstance(self, 0);}
- (id) init {return self;}
-@property int FooBar;
+@synthesize FooBar;
- (int) lookAtProperty { return FooBar; }
- (void) setProperty: (int) v { FooBar = v; }
@@ -59,8 +45,8 @@ int main(int argc, char *argv[]) {
and operate correctly. */
[f setProperty:11];
- if (f->_FooBar != 11)
- { printf ("setProperty did not set _FooBar\n"); abort ();}
+ if (f.FooBar != 11)
+ { printf ("setProperty did not set FooBar\n"); abort ();}
res = [f lookAtProperty];
if (res != 11 )
diff --git a/gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m b/gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m
index 837d303..3e0b529 100644
--- a/gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m
+++ b/gcc/testsuite/objc.dg/property/fsf-property-named-ivar.m
@@ -1,31 +1,16 @@
/* Basic test, auto-generated getter/setter based on named ivar */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
extern int printf (char *fmt,...) ;
extern void abort (void);
-typedef struct objc_class *Class;
-
-#ifdef __NEXT_RUNTIME__
-
-extern id class_createInstance(Class, long);
-#define class_create_instance(C) class_createInstance(C, 0)
-
-#else
-
-extern id class_create_instance(Class);
-
-#endif
+#include <objc/objc.h>
+#include <objc/runtime.h>
@interface Bar
{
@public
-#ifdef __NEXT_RUNTIME__
Class isa;
-#else
- Class class_pointer;
-#endif
int var;
}
+ (id) initialize;
@@ -38,11 +23,11 @@ extern id class_create_instance(Class);
@implementation Bar
+initialize { return self;}
-+ (id) alloc { return class_create_instance(self);}
++ (id) alloc { return class_createInstance (self, 0); }
- (id) init {return self;}
-@property (ivar = var) int FooBar ;
+@synthesize FooBar = var;
@end
int main(int argc, char *argv[]) {
@@ -61,7 +46,7 @@ int main(int argc, char *argv[]) {
if (res != 1234 )
{ printf ("[f FooBar] = %d\n", res); abort ();}
- /* Now check the short-cut CLASS.property syntax. */
+ /* Now check the short-cut object.property syntax. */
/* Read .... */
res = f.FooBar;
if (res != 1234 )
diff --git a/gcc/testsuite/objc.dg/property/property-1.m b/gcc/testsuite/objc.dg/property/property-1.m
index 89537ca..fbc181eb 100644
--- a/gcc/testsuite/objc.dg/property/property-1.m
+++ b/gcc/testsuite/objc.dg/property/property-1.m
@@ -1,7 +1,6 @@
/* This program tests use of property provided setter/getter functions. */
/* { dg-options "-std=c99" } */
/* { dg-do run } */
-/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
/* { dg-additional-sources "../../objc-obj-c++-shared/Object1.m" } */
#import "../../objc-obj-c++-shared/Object1.h"
@@ -10,11 +9,11 @@
{
int iVar;
}
-@property int FooBar;
+@property (setter=MySetter:) int FooBar;
@end
@implementation Bar
-@property (ivar = iVar, setter = MySetter:) int FooBar;
+@synthesize FooBar=iVar;
- (void) MySetter : (int) value { iVar = value; }
diff --git a/gcc/testsuite/objc.dg/property/property-2.m b/gcc/testsuite/objc.dg/property/property-2.m
index 2a923e0..c14d759 100644
--- a/gcc/testsuite/objc.dg/property/property-2.m
+++ b/gcc/testsuite/objc.dg/property/property-2.m
@@ -7,6 +7,8 @@
/* Force ABI = 0 in the NeXT headers, also suppress deprecation warnings. */
/* { dg-options "-framework Foundation -fobjc-exceptions -mmacosx-version-min=10.4 -Wno-deprecated-declarations" } */
+/* FIXME: There is no reason to use NSString in this file. */
+
#include <objc/objc-api.h>
#include <Foundation/Foundation.h>
diff --git a/gcc/testsuite/objc.dg/property/property-neg-1.m b/gcc/testsuite/objc.dg/property/property-neg-1.m
index ffb8253..cae1a56 100644
--- a/gcc/testsuite/objc.dg/property/property-neg-1.m
+++ b/gcc/testsuite/objc.dg/property/property-neg-1.m
@@ -1,14 +1,13 @@
-/* This program checks for proper use of 'readonly' attribute. */
/* { dg-do compile } */
@interface Bar
{
int iVar;
}
-@property (readonly) int FooBar;
+@property int fooBar;
@end
@implementation Bar
-@property int FooBar; /* { dg-error "property 'FooBar' 'readonly' attribute conflicts with its interface version" } */
-
-@end
+@end /* { dg-warning "incomplete implementation of class .Bar." } */
+ /* { dg-warning "method definition for .-setFooBar:. not found" "" { target *-*-* } 11 } */
+ /* { dg-warning "method definition for .-fooBar. not found" "" { target *-*-* } 11 } */
diff --git a/gcc/testsuite/objc.dg/property/property-neg-2.m b/gcc/testsuite/objc.dg/property/property-neg-2.m
index 7046da8..f730fe8 100644
--- a/gcc/testsuite/objc.dg/property/property-neg-2.m
+++ b/gcc/testsuite/objc.dg/property/property-neg-2.m
@@ -1,9 +1,8 @@
-/* This program checks for proper declaration of property. */
/* { dg-do compile } */
@interface Bar
@end
@implementation Bar
-@property int foo; /* { dg-error "no declaration of property 'foo' found in the interface" } */
+@property int FooBar; /* { dg-error "property declaration not in @interface or @protocol context" } */
@end
diff --git a/gcc/testsuite/objc.dg/property/property-neg-3.m b/gcc/testsuite/objc.dg/property/property-neg-3.m
index 5b48044..0b30931 100644
--- a/gcc/testsuite/objc.dg/property/property-neg-3.m
+++ b/gcc/testsuite/objc.dg/property/property-neg-3.m
@@ -1,14 +1,14 @@
-/* Property name cannot match the ivar name. */
/* { dg-do compile } */
-/* Suppress warnings for incomplete class definition etc. */
-/* { dg-options "-w" } */
@interface Person
{
char *firstName;
}
-@property char *firstName; /* { dg-error "property 'firstName' may not have the same name as an ivar in the class" } */
+@property char *firstName;
@end
@implementation Person
+@dynamic firstName;
+@synthesize firstName; /* { dg-error "property .firstName. already specified in .@dynamic." } */
+ /* { dg-message "originally specified here" "" { target *-*-* } 11 } */
@end
diff --git a/gcc/testsuite/objc.dg/property/property-neg-4.m b/gcc/testsuite/objc.dg/property/property-neg-4.m
index 960c6d6..cc25d84 100644
--- a/gcc/testsuite/objc.dg/property/property-neg-4.m
+++ b/gcc/testsuite/objc.dg/property/property-neg-4.m
@@ -1,17 +1,17 @@
-/* Property cannot be accessed in class method. */
/* { dg-do compile } */
@interface Person
{
+ char *fullName;
}
@property char *fullName;
+ (void) testClass;
@end
+
@implementation Person
-@property char *fullName;
+@synthesize fullName;
+ (void) testClass {
- fullName = "MyName"; /* { dg-error "property 'fullName' accessed in class method" } */
+ self.fullName = "MyName"; /* { dg-error "request for member .fullName." } */
}
@end
-
diff --git a/gcc/testsuite/objc.dg/property/property-neg-5.m b/gcc/testsuite/objc.dg/property/property-neg-5.m
index 7a9090a..403f684 100644
--- a/gcc/testsuite/objc.dg/property/property-neg-5.m
+++ b/gcc/testsuite/objc.dg/property/property-neg-5.m
@@ -1,7 +1,5 @@
-/* getter/setter cannot be specified in an interface. */
/* { dg-do compile } */
@interface Foo
@property ( readonly, getter = HELLO, setter = THERE : ) int value; /* { dg-warning ".readonly. attribute conflicts with .setter. attribute" } */
-@end /* { dg-warning "getter = \\'HELLO\\' may not be specified in an interface" } */
- /* { dg-warning "setter = \\'THERE\\:\\' may not be specified in an interface" "" { target *-*-* } 6 } */
+@end
diff --git a/gcc/testsuite/objc.dg/property/property-neg-7.m b/gcc/testsuite/objc.dg/property/property-neg-7.m
index 506f097..4c3d5d7 100644
--- a/gcc/testsuite/objc.dg/property/property-neg-7.m
+++ b/gcc/testsuite/objc.dg/property/property-neg-7.m
@@ -1,13 +1,14 @@
-/* Cannot write into a read-only property. */
/* { dg-do compile } */
-/* Suppress warnings for incomplete class definition etc. */
-/* { dg-options "-w" } */
@interface NSArray
+{
+ int count;
+}
@property(readonly) int count;
@end
@implementation NSArray
+@synthesize count;
@end
void foo (NSArray *ans[], id pid, id apid[], int i) {
diff --git a/gcc/testsuite/objc.dg/property/synthesize-1.m b/gcc/testsuite/objc.dg/property/synthesize-1.m
index 09085d8..fbc8e03 100644
--- a/gcc/testsuite/objc.dg/property/synthesize-1.m
+++ b/gcc/testsuite/objc.dg/property/synthesize-1.m
@@ -19,13 +19,35 @@
int v2;
int v3;
int v4;
+ int v5;
+ int v6;
+ int v7;
+ int v8;
}
+@property int v1;
+@property int v2;
+@property int v3;
+@property int v4;
+@property int v5;
+@property int v6;
+@property int v7;
+@property int v8;
@end
@implementation Test
@synthesize; /* { dg-error "expected identifier" } */
@synthesize v1, ; /* { dg-error "expected identifier" } */
-@synthesize v1, v2 = ; /* { dg-error "expected identifier" } */
-@synthesize v1, v2=v2, v3 = v3,v4; /* { dg-error ".@synthesize. is not supported in this version of the compiler" } */
-@synthesize v4; /* { dg-error ".@synthesize. is not supported in this version of the compiler" } */
+@synthesize v2, v3 = ; /* { dg-error "expected identifier" } */
+@synthesize v4, v5=v6, v6 = v5,v7;
+@synthesize v8;
+/* Some of the @synthesize above will fail due to syntax errors. The
+ compiler will then complain that the methods implementing the
+ properties are missing. That is correct, but we are not
+ interested. The following ones shut up the compiler. */
+- (int) v1 { return v1; }
+- (void) setV1: (int)a { v1 = a; }
+- (int) v2 { return v2; }
+- (void) setV2: (int)a { v2 = a; }
+- (int) v3 { return v3; }
+- (void) setV3: (int)a { v3 = a; }
@end
diff --git a/gcc/testsuite/objc.dg/property/synthesize-2.m b/gcc/testsuite/objc.dg/property/synthesize-2.m
new file mode 100644
index 0000000..4bc3e3c
--- /dev/null
+++ b/gcc/testsuite/objc.dg/property/synthesize-2.m
@@ -0,0 +1,50 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, October 2010. */
+/* { dg-do run } */
+
+#include <objc/objc.h>
+#include <objc/runtime.h>
+#include <stdlib.h>
+
+@interface MyRootClass
+{
+ Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@interface Test : MyRootClass
+{
+ int v1;
+}
+@property int v1;
+/* TODO: Test more types of properties with different semantics
+ (retain, copy, atomic, nonatomic, and test various C and
+ Objective-C types). */
+@end
+
+@implementation Test
+@synthesize v1;
+@end
+
+int main (void)
+{
+ Test *object = [[Test alloc] init];
+
+ /* Check that the synthesized methods exist and work. Do not invoke
+ them via property syntax - that is another test. Here we just
+ want to test the synthesis of the methods. */
+ [object setV1: 400];
+
+ if ([object v1] != 400)
+ abort ();
+
+ return 0;
+}