===================================================================
@@ -1,3 +1,8 @@
+2010-11-14 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * c-common.h (objc_build_incr_expr_for_property_ref): New.
+ * stub-objc.c (objc_build_incr_expr_for_property_ref): New.
+
2010-11-12 Joseph Myers <joseph@codesourcery.com>
* c-common.h (c_family_lang_mask): Declare.
===================================================================
@@ -1040,6 +1040,8 @@ extern void objc_add_property_declaration (locatio
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);
===================================================================
@@ -361,6 +361,15 @@ objc_maybe_build_modify_expr (tree ARG_UNUSED (lhs
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))
===================================================================
@@ -485,6 +485,33 @@ add_field_decl (tree type, const char *name, tree
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,7 +1793,117 @@ 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
===================================================================
@@ -1,5 +1,11 @@
2010-11-14 Nicola Pero <nicola.pero@meta-innovation.com>
+ * 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 <nicola.pero@meta-innovation.com>
+
* objc-act.c (objc_add_property_declaration): Check that the decl
we received from the parser is a FIELD_DECL; reject array and
bitfield properties. Convert the warning when a property is
===================================================================
@@ -1,3 +1,10 @@
+2010-11-14 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * 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-13 Paolo Bonzini <bonzini@gnu.org>
PR c/46462
===================================================================
@@ -1,3 +1,13 @@
+2010-11-14 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * 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-14 Paolo Bonzini <bonzini@gnu.org>
PR c/46475
===================================================================
@@ -0,0 +1,68 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
+/* { dg-do compile } */
+
+/* Test errors with the dot-syntax with pre/post increment and decrement. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@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;
+}
+
+
===================================================================
@@ -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)
===================================================================
@@ -0,0 +1,92 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, 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 <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@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;
+}
+
+
===================================================================
@@ -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)
===================================================================
@@ -0,0 +1,68 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
+/* { dg-do compile } */
+
+/* Test errors with the dot-syntax with pre/post increment and decrement. */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@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;
+}
+
+
===================================================================
@@ -5233,6 +5233,13 @@ cp_build_unary_op (enum tree_code code, tree xarg,
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)
===================================================================
@@ -1,3 +1,9 @@
+2010-11-14 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * 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 <jason@redhat.com>
* decl.c (cp_finish_decl): Use resolve_nondeduced_context for auto.
===================================================================
@@ -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))
{