From 925e8657ce3e2d02766697a98fe2b51412979b30 Mon Sep 17 00:00:00 2001 From: Nicola Pero Date: Mon, 15 Nov 2010 18:46:42 +0000 Subject: [PATCH] In gcc/: 2010-11-15 Nicola Pero In gcc/: 2010-11-15 Nicola Pero * c-typeck.c (build_unary_op): Use objc_build_incr_expr_for_property_ref to build the pre/post increment/decrement of an Objective-C property ref, and skip the lvalue_or_else check in that case. In gcc/c-family/: 2010-11-15 Nicola Pero * c-common.h (objc_build_incr_expr_for_property_ref): New. * stub-objc.c (objc_build_incr_expr_for_property_ref): New. In gcc/cp/: 2010-11-15 Nicola Pero * typeck.c (cp_build_unary_op): Use objc_build_incr_expr_for_property_ref to build the pre/post increment/decrement of an Objective-C property ref. In gcc/objc/: 2010-11-15 Nicola Pero * objc-act.c (objc_build_incr_expr_for_property_ref): New. (objc_create_temporary_var): Moved it towards the beginning of the file so that objc_build_incr_expr_for_property_ref can use it. In gcc/testsuite/: 2010-11-15 Nicola Pero * objc.dg/property/dotsyntax-16.m: New. * objc.dg/property/dotsyntax-17.m: New. * obj-c++.dg/property/dotsyntax-16.mm: New. * obj-c++.dg/property/dotsyntax-17.mm: New. * objc.dg/property/at-property-10.m: Uncommented using 'x++' syntax with properties, which now works. * obj-c++.dg/property/at-property-10.mm: Same change. From-SVN: r166763 --- gcc/ChangeLog | 7 + gcc/c-family/ChangeLog | 5 + gcc/c-family/c-common.h | 2 + gcc/c-family/stub-objc.c | 9 + gcc/c-typeck.c | 19 +- gcc/cp/ChangeLog | 6 + gcc/cp/typeck.c | 7 + gcc/objc/ChangeLog | 6 + gcc/objc/objc-act.c | 163 +++++++++++++++--- gcc/testsuite/ChangeLog | 10 ++ .../obj-c++.dg/property/at-property-10.mm | 8 +- .../obj-c++.dg/property/dotsyntax-16.mm | 92 ++++++++++ .../obj-c++.dg/property/dotsyntax-17.mm | 68 ++++++++ .../objc.dg/property/at-property-10.m | 8 +- gcc/testsuite/objc.dg/property/dotsyntax-16.m | 92 ++++++++++ gcc/testsuite/objc.dg/property/dotsyntax-17.m | 68 ++++++++ 16 files changed, 527 insertions(+), 43 deletions(-) create mode 100644 gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm create mode 100644 gcc/testsuite/objc.dg/property/dotsyntax-16.m create mode 100644 gcc/testsuite/objc.dg/property/dotsyntax-17.m diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 20e23f8cd12..5f7d0c5cc34 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2010-11-15 Nicola Pero + + * c-typeck.c (build_unary_op): Use + objc_build_incr_expr_for_property_ref to build the pre/post + increment/decrement of an Objective-C property ref, and skip the + lvalue_or_else check in that case. + 2010-11-15 Martin Jambor PR tree-optimization/46349 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 4e31d6a1e18..a66f37acefd 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2010-11-15 Nicola Pero + + * c-common.h (objc_build_incr_expr_for_property_ref): New. + * stub-objc.c (objc_build_incr_expr_for_property_ref): New. + 2010-11-15 Nathan Froyd PR preprocessor/45038 diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index a28183a9500..cddad17348f 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1040,6 +1040,8 @@ extern void objc_add_property_declaration (location_t, tree, bool, bool, bool, extern tree objc_maybe_build_component_ref (tree, tree); extern tree objc_build_class_component_ref (tree, tree); extern tree objc_maybe_build_modify_expr (tree, tree); +extern tree objc_build_incr_expr_for_property_ref (location_t, enum tree_code, + 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); diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c index 9dd6ef52f89..5cd6e6d6e79 100644 --- a/gcc/c-family/stub-objc.c +++ b/gcc/c-family/stub-objc.c @@ -361,6 +361,15 @@ objc_maybe_build_modify_expr (tree ARG_UNUSED (lhs), tree ARG_UNUSED (rhs)) return 0; } +tree +objc_build_incr_expr_for_property_ref (location_t ARG_UNUSED (location), + enum tree_code ARG_UNUSED (code), + tree ARG_UNUSED (argument), + tree ARG_UNUSED (increment)) +{ + return 0; +} + void objc_add_synthesize_declaration (location_t ARG_UNUSED (start_locus), tree ARG_UNUSED (property_and_ivar_list)) diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 9018c4e933c..2bfa97be68e 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -3603,11 +3603,13 @@ build_unary_op (location_t location, goto return_build_unary_op; } - /* Complain about anything that is not a true lvalue. */ - if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR - || code == POSTINCREMENT_EXPR) - ? lv_increment - : lv_decrement))) + /* Complain about anything that is not a true lvalue. In + Objective-C, skip this check for property_refs. */ + if (!objc_is_property_ref (arg) + && !lvalue_or_else (arg, ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? lv_increment + : lv_decrement))) return error_mark_node; if (warn_cxx_compat && TREE_CODE (TREE_TYPE (arg)) == ENUMERAL_TYPE) @@ -3715,6 +3717,13 @@ build_unary_op (location_t location, inc = convert (argtype, inc); } + /* If 'arg' is an Objective-C PROPERTY_REF expression, then we + need to ask Objective-C to build the increment or decrement + expression for it. */ + if (objc_is_property_ref (arg)) + return objc_build_incr_expr_for_property_ref (location, code, + arg, inc); + /* Report a read-only lvalue. */ if (TYPE_READONLY (argtype)) { diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 418951aaa40..cdbec790eef 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2010-11-15 Nicola Pero + + * typeck.c (cp_build_unary_op): Use + objc_build_incr_expr_for_property_ref to build the pre/post + increment/decrement of an Objective-C property ref. + 2010-11-13 Jason Merrill * decl.c (cp_finish_decl): Use resolve_nondeduced_context for auto. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8557ac36d39..92a7d9ed6de 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5233,6 +5233,13 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, inc = cp_convert (argtype, inc); + /* If 'arg' is an Objective-C PROPERTY_REF expression, then we + need to ask Objective-C to build the increment or decrement + expression for it. */ + if (objc_is_property_ref (arg)) + return objc_build_incr_expr_for_property_ref (input_location, code, + arg, inc); + /* Complain about anything else that is not a true lvalue. */ if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 9dfc4f95721..c5103faddcd 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,9 @@ +2010-11-15 Nicola Pero + + * objc-act.c (objc_build_incr_expr_for_property_ref): New. + (objc_create_temporary_var): Moved it towards the beginning of the + file so that objc_build_incr_expr_for_property_ref can use it. + 2010-11-14 Nicola Pero * objc-act.c (objc_add_property_declaration): Check that the decl diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index da97e14ced2..8f953b66434 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -485,6 +485,33 @@ add_field_decl (tree type, const char *name, tree **chain) return field; } +/* Create a temporary variable of type 'type'. If 'name' is set, uses + the specified name, else use no name. Returns the declaration of + the type. The 'name' is mostly useful for debugging. +*/ +static tree +objc_create_temporary_var (tree type, const char *name) +{ + tree decl; + + if (name != NULL) + { + decl = build_decl (input_location, + VAR_DECL, get_identifier (name), type); + } + else + { + decl = build_decl (input_location, + VAR_DECL, NULL_TREE, type); + } + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + DECL_CONTEXT (decl) = current_function_decl; + + return decl; +} + /* Some platforms pass small structures through registers versus through an invisible pointer. Determine at what size structure is the transition point between the two possibilities. */ @@ -1766,6 +1793,116 @@ objc_maybe_build_modify_expr (tree lhs, tree rhs) return NULL_TREE; } +/* This hook is called by the frontend when one of the four unary + expressions PREINCREMENT_EXPR, POSTINCREMENT_EXPR, + PREDECREMENT_EXPR and POSTDECREMENT_EXPR is being built with an + argument which is a PROPERTY_REF. For example, this happens if you have + + object.count++; + + where 'count' is a property. We need to use the 'getter' and + 'setter' for the property in an appropriate way to build the + appropriate expression. 'code' is the code for the expression (one + of the four mentioned above); 'argument' is the PROPERTY_REF, and + 'increment' is how much we need to add or subtract. */ +tree +objc_build_incr_expr_for_property_ref (location_t location, + enum tree_code code, + tree argument, tree increment) +{ + /* Here are the expressions that we want to build: + + For PREINCREMENT_EXPR / PREDECREMENT_EXPR: + (temp = [object property] +/- increment, [object setProperty: temp], temp) + + For POSTINCREMENT_EXPR / POSTECREMENT_EXPR: + (temp = [object property], [object setProperty: temp +/- increment], temp) */ + + tree temp_variable_decl, bind; + /* s1, s2 and s3 are the tree statements that we need in the + compound expression. */ + tree s1, s2, s3; + + /* Safety check. */ + if (!argument || TREE_CODE (argument) != PROPERTY_REF) + return error_mark_node; + + /* Declare __objc_property_temp in a local bind. */ + temp_variable_decl = objc_create_temporary_var (TREE_TYPE (argument), "__objc_property_temp"); + DECL_SOURCE_LOCATION (temp_variable_decl) = location; + bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL); + SET_EXPR_LOCATION (bind, location); + TREE_SIDE_EFFECTS (bind) = 1; + add_stmt (bind); + + /* Now build the compound statement. */ + + /* Note that the 'getter' is generated at gimplify time; at this + time, we can simply put the property_ref (ie, argument) wherever + we want the getter ultimately to be. */ + + /* s1: __objc_property_temp = [object property] <+/- increment> */ + switch (code) + { + case PREINCREMENT_EXPR: + /* __objc_property_temp = [object property] + increment */ + s1 = build2 (MODIFY_EXPR, void_type_node, temp_variable_decl, + build2 (PLUS_EXPR, TREE_TYPE (argument), argument, increment)); + break; + case PREDECREMENT_EXPR: + /* __objc_property_temp = [object property] - increment */ + s1 = build2 (MODIFY_EXPR, void_type_node, temp_variable_decl, + build2 (MINUS_EXPR, TREE_TYPE (argument), argument, increment)); + break; + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + /* __objc_property_temp = [object property] */ + s1 = build2 (MODIFY_EXPR, void_type_node, temp_variable_decl, argument); + break; + default: + gcc_unreachable (); + } + SET_EXPR_LOCATION (s1, location); + + /* s2: [object setProperty: __objc_property_temp <+/- increment>] */ + switch (code) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + /* [object setProperty: __objc_property_temp] */ + s2 = objc_maybe_build_modify_expr (argument, temp_variable_decl); + break; + case POSTINCREMENT_EXPR: + /* [object setProperty: __objc_property_temp + increment] */ + s2 = objc_maybe_build_modify_expr (argument, + build2 (PLUS_EXPR, TREE_TYPE (argument), + temp_variable_decl, increment)); + break; + case POSTDECREMENT_EXPR: + /* [object setProperty: __objc_property_temp - increment] */ + s2 = objc_maybe_build_modify_expr (argument, + build2 (MINUS_EXPR, TREE_TYPE (argument), + temp_variable_decl, increment)); + break; + default: + gcc_unreachable (); + } + + /* This happens if building the setter failed because the property + is readonly. */ + if (s2 == error_mark_node) + return error_mark_node; + + SET_EXPR_LOCATION (s2, location); + + /* s3: __objc_property_temp */ + s3 = build1 (NOP_EXPR, TREE_TYPE (argument), temp_variable_decl); + SET_EXPR_LOCATION (s3, location); + + /* Now build the compound statement (s1, s2, s3) */ + return build_compound_expr (location, build_compound_expr (location, s1, s2), s3); +} + tree objc_build_method_signature (bool is_class_method, tree rettype, tree selector, tree optparms, bool ellipsis) @@ -4658,32 +4795,6 @@ get_class_ivars (tree interface, bool inherited) return ivar_chain; } -/* Create a temporary variable of type 'type'. If 'name' is set, uses - the specified name, else use no name. Returns the declaration of - the type. The 'name' is mostly useful for debugging. -*/ -static tree -objc_create_temporary_var (tree type, const char *name) -{ - tree decl; - - if (name != NULL) - { - decl = build_decl (input_location, - VAR_DECL, get_identifier (name), type); - } - else - { - decl = build_decl (input_location, - VAR_DECL, NULL_TREE, type); - } - TREE_USED (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - DECL_IGNORED_P (decl) = 1; - DECL_CONTEXT (decl) = current_function_decl; - - return decl; -} /* Exception handling constructs. We begin by having the parser do most of the work and passing us blocks. What we do next depends on whether diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f1ff5695488..c855ae3aa03 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2010-11-15 Nicola Pero + + * objc.dg/property/dotsyntax-16.m: New. + * objc.dg/property/dotsyntax-17.m: New. + * obj-c++.dg/property/dotsyntax-16.mm: New. + * obj-c++.dg/property/dotsyntax-17.mm: New. + * objc.dg/property/at-property-10.m: Uncommented using 'x++' + syntax with properties, which now works. + * obj-c++.dg/property/at-property-10.mm: Same change. + 2010-11-15 Martin Jambor PR tree-optimization/46349 diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-10.mm b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm index b867896f8b5..010c41bd396 100644 --- a/gcc/testsuite/obj-c++.dg/property/at-property-10.mm +++ b/gcc/testsuite/obj-c++.dg/property/at-property-10.mm @@ -44,9 +44,7 @@ int main (void) abort (); object.a = 99; - /* TODO: The following one does not work yet. */ - /* object.a++; */ - object.a = object.a + 1; + object.a++; if (object.a != 100) abort (); @@ -83,9 +81,7 @@ int main (void) 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) + for (object.a = 0; object.a < 99; object.a++) object2.a = object.a; if (object2.a != object.a - 1) diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm new file mode 100644 index 00000000000..e0ae3f6edeb --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm @@ -0,0 +1,92 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with pre/post increment and decrement. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + int i; + + object.count = 10; + if (object.count != 10) + abort (); + + /* First, test that they increment/decrement as expected. */ + object.count++; + if (object.count != 11) + abort (); + + ++object.count; + if (object.count != 12) + abort (); + + object.count--; + if (object.count != 11) + abort (); + + --object.count; + if (object.count != 10) + abort (); + + /* Now, test that they are pre/post increment/decrement, as + expected. */ + if (object.count++ != 10) + abort (); + + if (object.count != 11) + abort (); + + if (++object.count != 12) + abort (); + + if (object.count != 12) + abort (); + + if (object.count-- != 12) + abort (); + + if (object.count != 11) + abort (); + + if (--object.count != 10) + abort (); + + if (object.count != 10) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm new file mode 100644 index 00000000000..f3942fccb11 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm @@ -0,0 +1,68 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test errors with the dot-syntax with pre/post increment and decrement. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int count; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@property (assign, readonly) int count; +- (void) setWriteOnlyCount: (int)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize count; +- (void) setWriteOnlyCount: (int)value +{ + a = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + int i; + + object.count = 10; /* { dg-error "readonly property can not be set" } */ + if (object.count != 10) /* Ok */ + abort (); + + /* Test errors when trying to change a readonly property using + pre/post increment/decrement operators. */ + object.count++; /* { dg-error "readonly property can not be set" } */ + + ++object.count; /* { dg-error "readonly property can not be set" } */ + + object.count--; /* { dg-error "readonly property can not be set" } */ + + --object.count; /* { dg-error "readonly property can not be set" } */ + + /* Test errors when trying to change something using Objective-C 2.0 + dot-syntax but there is a setter but no getter. */ + object.writeOnlyCount = 10; /* Ok */ + + object.writeOnlyCount++; /* { dg-error "no .writeOnlyCount. getter found" } */ + + ++object.writeOnlyCount; /* { dg-error "no .writeOnlyCount. getter found" } */ + + object.writeOnlyCount--; /* { dg-error "no .writeOnlyCount. getter found" } */ + + --object.writeOnlyCount; /* { dg-error "no .writeOnlyCount. getter found" } */ + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/at-property-10.m b/gcc/testsuite/objc.dg/property/at-property-10.m index 945ada5da34..79d2ecdbbf0 100644 --- a/gcc/testsuite/objc.dg/property/at-property-10.m +++ b/gcc/testsuite/objc.dg/property/at-property-10.m @@ -47,9 +47,7 @@ int main (void) abort (); object.a = 99; - /* TODO: The following one does not work yet. */ - /* object.a++; */ - object.a = object.a + 1; + object.a++; if (object.a != 100) abort (); @@ -86,9 +84,7 @@ int main (void) 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) + for (object.a = 0; object.a < 99; object.a++) object2.a = object.a; if (object2.a != object.a - 1) diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-16.m b/gcc/testsuite/objc.dg/property/dotsyntax-16.m new file mode 100644 index 00000000000..e0ae3f6edeb --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-16.m @@ -0,0 +1,92 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test dot-syntax with pre/post increment and decrement. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) count; +- (void) setCount: (int)count; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) count +{ + return a; +} +- (void) setCount: (int)count +{ + a = count; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + int i; + + object.count = 10; + if (object.count != 10) + abort (); + + /* First, test that they increment/decrement as expected. */ + object.count++; + if (object.count != 11) + abort (); + + ++object.count; + if (object.count != 12) + abort (); + + object.count--; + if (object.count != 11) + abort (); + + --object.count; + if (object.count != 10) + abort (); + + /* Now, test that they are pre/post increment/decrement, as + expected. */ + if (object.count++ != 10) + abort (); + + if (object.count != 11) + abort (); + + if (++object.count != 12) + abort (); + + if (object.count != 12) + abort (); + + if (object.count-- != 12) + abort (); + + if (object.count != 11) + abort (); + + if (--object.count != 10) + abort (); + + if (object.count != 10) + abort (); + + return 0; +} + + diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-17.m b/gcc/testsuite/objc.dg/property/dotsyntax-17.m new file mode 100644 index 00000000000..f3942fccb11 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/dotsyntax-17.m @@ -0,0 +1,68 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test errors with the dot-syntax with pre/post increment and decrement. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int count; + int a; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@property (assign, readonly) int count; +- (void) setWriteOnlyCount: (int)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@synthesize count; +- (void) setWriteOnlyCount: (int)value +{ + a = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + int i; + + object.count = 10; /* { dg-error "readonly property can not be set" } */ + if (object.count != 10) /* Ok */ + abort (); + + /* Test errors when trying to change a readonly property using + pre/post increment/decrement operators. */ + object.count++; /* { dg-error "readonly property can not be set" } */ + + ++object.count; /* { dg-error "readonly property can not be set" } */ + + object.count--; /* { dg-error "readonly property can not be set" } */ + + --object.count; /* { dg-error "readonly property can not be set" } */ + + /* Test errors when trying to change something using Objective-C 2.0 + dot-syntax but there is a setter but no getter. */ + object.writeOnlyCount = 10; /* Ok */ + + object.writeOnlyCount++; /* { dg-error "no .writeOnlyCount. getter found" } */ + + ++object.writeOnlyCount; /* { dg-error "no .writeOnlyCount. getter found" } */ + + object.writeOnlyCount--; /* { dg-error "no .writeOnlyCount. getter found" } */ + + --object.writeOnlyCount; /* { dg-error "no .writeOnlyCount. getter found" } */ + + return 0; +} + +