In gcc/: 2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com>
In gcc/: 2010-11-15 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. In gcc/c-family/: 2010-11-15 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. In gcc/cp/: 2010-11-15 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. In gcc/objc/: 2010-11-15 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. In gcc/testsuite/: 2010-11-15 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. From-SVN: r166763
This commit is contained in:
parent
4cc13d9d7a
commit
925e8657ce
16 changed files with 527 additions and 43 deletions
|
@ -1,3 +1,10 @@
|
|||
2010-11-15 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-15 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
PR tree-optimization/46349
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2010-11-15 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-15 Nathan Froyd <froydnj@codesourcery.com>
|
||||
|
||||
PR preprocessor/45038
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2010-11-15 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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2010-11-15 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
2010-11-15 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-15 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
PR tree-optimization/46349
|
||||
|
|
|
@ -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)
|
||||
|
|
92
gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm
Normal file
92
gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
|
68
gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm
Normal file
68
gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm
Normal file
|
@ -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)
|
||||
|
|
92
gcc/testsuite/objc.dg/property/dotsyntax-16.m
Normal file
92
gcc/testsuite/objc.dg/property/dotsyntax-16.m
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
|
68
gcc/testsuite/objc.dg/property/dotsyntax-17.m
Normal file
68
gcc/testsuite/objc.dg/property/dotsyntax-17.m
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue