In gcc/objc/: 2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com>
In gcc/objc/: 2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com> * objc-act.c (objc_build_setter_call): New. (objc_maybe_build_modify_expr): Rewritten to build a compound statement. (objc_build_incr_expr_for_property_ref): Updated calls to objc_maybe_build_modify_expr to call objc_build_setter_call instead. Use build_modify_expr () instead of build2 (MODIFY_EXPR, ...). Use convert () instead of build1 (NOP_EXPR, ...). Use TREE_NO_WARNING on the final compound statement to silence C++ warnings. In gcc/testsuite/: 2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com> * objc.dg/property/dotsyntax-18.m: New. * objc.dg/property/dotsyntax-19.m: New. * objc.dg/property/dotsyntax-20.m: New. * obj-c++.dg/property/dotsyntax-18.mm: New. * obj-c++.dg/property/dotsyntax-19.mm: New. * obj-c++.dg/property/dotsyntax-20.mm: New. * objc.dg/property/dotsyntax-4.m: Removed some unused variables and code. * objc.dg/property/dotsyntax-6.m: Same change. * objc.dg/property/dotsyntax-16.m: Same change. * objc.dg/property/dotsyntax-17.m: Same change. * obj-c++.dg/property/dotsyntax-4.mm: Same change. * obj-c++.dg/property/dotsyntax-6.mm: Same change. * obj-c++.dg/property/dotsyntax-16.mm: Same change. * obj-c++.dg/property/dotsyntax-17.mm: Same change. * objc.dg/property/at-property-22.m: Added missing casts. * obj-c++.dg/property/at-property-22.mm: Same change. From-SVN: r166779
This commit is contained in:
parent
567b99c86e
commit
b6cfe8acc5
19 changed files with 709 additions and 107 deletions
|
@ -1,3 +1,15 @@
|
|||
2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* objc-act.c (objc_build_setter_call): New.
|
||||
(objc_maybe_build_modify_expr): Rewritten to build a compound
|
||||
statement.
|
||||
(objc_build_incr_expr_for_property_ref): Updated calls to
|
||||
objc_maybe_build_modify_expr to call objc_build_setter_call
|
||||
instead. Use build_modify_expr () instead of build2 (MODIFY_EXPR,
|
||||
...). Use convert () instead of build1 (NOP_EXPR, ...). Use
|
||||
TREE_NO_WARNING on the final compound statement to silence C++
|
||||
warnings.
|
||||
|
||||
2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* objc-act.c (objc_build_incr_expr_for_property_ref): New.
|
||||
|
|
|
@ -1748,6 +1748,42 @@ objc_is_property_ref (tree node)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* This function builds a setter call for a PROPERTY_REF (real, for a
|
||||
declared property, or artificial, for a dot-syntax accessor which
|
||||
is not corresponding to a property). 'lhs' must be a PROPERTY_REF
|
||||
(the caller must check this beforehand). 'rhs' is the value to
|
||||
assign to the property. A plain setter call is returned, or
|
||||
error_mark_node if the property is readonly. */
|
||||
|
||||
static tree
|
||||
objc_build_setter_call (tree lhs, tree rhs)
|
||||
{
|
||||
tree object_expr = PROPERTY_REF_OBJECT (lhs);
|
||||
tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs);
|
||||
|
||||
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: Check that the setter return type is 'void'. */
|
||||
|
||||
/* TODO: Decay arguments in C. */
|
||||
setter = objc_finish_message_expr (object_expr,
|
||||
PROPERTY_SETTER_NAME (property_decl),
|
||||
setter_argument);
|
||||
return setter;
|
||||
}
|
||||
|
||||
/* Unreachable, but the compiler may not realize. */
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1767,27 +1803,69 @@ objc_maybe_build_modify_expr (tree lhs, tree rhs)
|
|||
{
|
||||
if (lhs && TREE_CODE (lhs) == PROPERTY_REF)
|
||||
{
|
||||
tree object_expr = PROPERTY_REF_OBJECT (lhs);
|
||||
tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs);
|
||||
/* Building a simple call to the setter method would work for cases such as
|
||||
|
||||
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;
|
||||
object.count = 1;
|
||||
|
||||
/* TODO: Check that the setter return type is 'void'. */
|
||||
but wouldn't work for cases such as
|
||||
|
||||
/* TODO: Decay argument in C. */
|
||||
setter = objc_finish_message_expr (object_expr,
|
||||
PROPERTY_SETTER_NAME (property_decl),
|
||||
setter_argument);
|
||||
return setter;
|
||||
}
|
||||
count = object2.count = 1;
|
||||
|
||||
to get these to work with very little effort, we build a
|
||||
compound statement which does the setter call (to set the
|
||||
property to 'rhs'), but which can also be evaluated returning
|
||||
the 'rhs'. So, we want to create the following:
|
||||
|
||||
(temp = rhs; [object setProperty: temp]; 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, compound_expr;
|
||||
|
||||
/* TODO: If 'rhs' is a constant, we could maybe do without the
|
||||
'temp' variable ? */
|
||||
|
||||
/* Declare __objc_property_temp in a local bind. */
|
||||
temp_variable_decl = objc_create_temporary_var (TREE_TYPE (rhs), "__objc_property_temp");
|
||||
DECL_SOURCE_LOCATION (temp_variable_decl) = input_location;
|
||||
bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL);
|
||||
SET_EXPR_LOCATION (bind, input_location);
|
||||
TREE_SIDE_EFFECTS (bind) = 1;
|
||||
add_stmt (bind);
|
||||
|
||||
/* Now build the compound statement. */
|
||||
|
||||
/* s1: __objc_property_temp = rhs */
|
||||
s1 = build_modify_expr (input_location, temp_variable_decl, NULL_TREE,
|
||||
NOP_EXPR,
|
||||
input_location, rhs, NULL_TREE);
|
||||
SET_EXPR_LOCATION (s1, input_location);
|
||||
|
||||
/* s2: [object setProperty: __objc_property_temp] */
|
||||
s2 = objc_build_setter_call (lhs, temp_variable_decl);
|
||||
|
||||
/* 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, input_location);
|
||||
|
||||
/* s3: __objc_property_temp */
|
||||
s3 = convert (TREE_TYPE (lhs), temp_variable_decl);
|
||||
|
||||
/* Now build the compound statement (s1, s2, s3) */
|
||||
compound_expr = build_compound_expr (input_location, build_compound_expr (input_location, s1, s2), s3);
|
||||
|
||||
/* Without this, with -Wall you get a 'valued computed is not
|
||||
used' every time there is a "object.property = x" where the
|
||||
value of the resulting MODIFY_EXPR is not used. That is
|
||||
correct (maybe a more sophisticated implementation could
|
||||
avoid generating the compound expression if not needed), but
|
||||
we need to turn it off. */
|
||||
TREE_NO_WARNING (compound_expr) = 1;
|
||||
return compound_expr;
|
||||
}
|
||||
else
|
||||
return NULL_TREE;
|
||||
|
@ -1821,7 +1899,7 @@ objc_build_incr_expr_for_property_ref (location_t location,
|
|||
tree temp_variable_decl, bind;
|
||||
/* s1, s2 and s3 are the tree statements that we need in the
|
||||
compound expression. */
|
||||
tree s1, s2, s3;
|
||||
tree s1, s2, s3, compound_expr;
|
||||
|
||||
/* Safety check. */
|
||||
if (!argument || TREE_CODE (argument) != PROPERTY_REF)
|
||||
|
@ -1846,23 +1924,28 @@ objc_build_incr_expr_for_property_ref (location_t location,
|
|||
{
|
||||
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));
|
||||
s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
|
||||
NOP_EXPR,
|
||||
location, build2 (PLUS_EXPR, TREE_TYPE (argument),
|
||||
argument, increment), NULL_TREE);
|
||||
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));
|
||||
s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
|
||||
NOP_EXPR,
|
||||
location, build2 (MINUS_EXPR, TREE_TYPE (argument),
|
||||
argument, increment), NULL_TREE);
|
||||
break;
|
||||
case POSTINCREMENT_EXPR:
|
||||
case POSTDECREMENT_EXPR:
|
||||
/* __objc_property_temp = [object property] */
|
||||
s1 = build2 (MODIFY_EXPR, void_type_node, temp_variable_decl, argument);
|
||||
s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
|
||||
NOP_EXPR,
|
||||
location, argument, NULL_TREE);
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
SET_EXPR_LOCATION (s1, location);
|
||||
|
||||
/* s2: [object setProperty: __objc_property_temp <+/- increment>] */
|
||||
switch (code)
|
||||
|
@ -1870,19 +1953,19 @@ objc_build_incr_expr_for_property_ref (location_t location,
|
|||
case PREINCREMENT_EXPR:
|
||||
case PREDECREMENT_EXPR:
|
||||
/* [object setProperty: __objc_property_temp] */
|
||||
s2 = objc_maybe_build_modify_expr (argument, temp_variable_decl);
|
||||
s2 = objc_build_setter_call (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));
|
||||
s2 = objc_build_setter_call (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));
|
||||
s2 = objc_build_setter_call (argument,
|
||||
build2 (MINUS_EXPR, TREE_TYPE (argument),
|
||||
temp_variable_decl, increment));
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
|
@ -1896,11 +1979,15 @@ objc_build_incr_expr_for_property_ref (location_t location,
|
|||
SET_EXPR_LOCATION (s2, location);
|
||||
|
||||
/* s3: __objc_property_temp */
|
||||
s3 = build1 (NOP_EXPR, TREE_TYPE (argument), temp_variable_decl);
|
||||
SET_EXPR_LOCATION (s3, location);
|
||||
s3 = convert (TREE_TYPE (argument), temp_variable_decl);
|
||||
|
||||
/* Now build the compound statement (s1, s2, s3) */
|
||||
return build_compound_expr (location, build_compound_expr (location, s1, s2), s3);
|
||||
compound_expr = build_compound_expr (location, build_compound_expr (location, s1, s2), s3);
|
||||
|
||||
/* Prevent C++ from warning with -Wall that "right operand of comma
|
||||
operator has no effect". */
|
||||
TREE_NO_WARNING (compound_expr) = 1;
|
||||
return compound_expr;
|
||||
}
|
||||
|
||||
tree
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* objc.dg/property/dotsyntax-18.m: New.
|
||||
* objc.dg/property/dotsyntax-19.m: New.
|
||||
* objc.dg/property/dotsyntax-20.m: New.
|
||||
* obj-c++.dg/property/dotsyntax-18.mm: New.
|
||||
* obj-c++.dg/property/dotsyntax-19.mm: New.
|
||||
* obj-c++.dg/property/dotsyntax-20.mm: New.
|
||||
* objc.dg/property/dotsyntax-4.m: Removed some unused variables and code.
|
||||
* objc.dg/property/dotsyntax-6.m: Same change.
|
||||
* objc.dg/property/dotsyntax-16.m: Same change.
|
||||
* objc.dg/property/dotsyntax-17.m: Same change.
|
||||
* obj-c++.dg/property/dotsyntax-4.mm: Same change.
|
||||
* obj-c++.dg/property/dotsyntax-6.mm: Same change.
|
||||
* obj-c++.dg/property/dotsyntax-16.mm: Same change.
|
||||
* obj-c++.dg/property/dotsyntax-17.mm: Same change.
|
||||
* objc.dg/property/at-property-22.m: Added missing casts.
|
||||
* obj-c++.dg/property/at-property-22.mm: Same change.
|
||||
|
||||
2010-11-15 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR tree-optimization/46491
|
||||
|
|
|
@ -128,31 +128,31 @@ int main (void)
|
|||
if (object.penum != Black)
|
||||
abort ();
|
||||
|
||||
object.pcharp = 0;
|
||||
object.pcharp = (char *)0;
|
||||
if (object.pcharp != 0)
|
||||
abort ();
|
||||
|
||||
object.pshortp = 0;
|
||||
object.pshortp = (short *)0;
|
||||
if (object.pshortp != 0)
|
||||
abort ();
|
||||
|
||||
object.pintp = 0;
|
||||
object.pintp = (int *)0;
|
||||
if (object.pintp != 0)
|
||||
abort ();
|
||||
|
||||
object.plongp = 0;
|
||||
object.plongp = (long *)0;
|
||||
if (object.plongp != 0)
|
||||
abort ();
|
||||
|
||||
object.pfloatp = 0;
|
||||
object.pfloatp = (float *)0;
|
||||
if (object.pfloatp != 0)
|
||||
abort ();
|
||||
|
||||
object.pdoublep = 0;
|
||||
object.pdoublep = (double *)0;
|
||||
if (object.pdoublep != 0)
|
||||
abort ();
|
||||
|
||||
object.penump = 0;
|
||||
object.penump = (enum colour *)0;
|
||||
if (object.penump != 0)
|
||||
abort ();
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
int i;
|
||||
|
||||
object.count = 10;
|
||||
if (object.count != 10)
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
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 */
|
||||
|
|
90
gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm
Normal file
90
gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* 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 tricky assignments. */
|
||||
|
||||
#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;
|
||||
- (int) somethingToExecuteOnlyOnce;
|
||||
@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;
|
||||
}
|
||||
- (int) somethingToExecuteOnlyOnce
|
||||
{
|
||||
a++;
|
||||
return 10;
|
||||
}
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object1 = [[MyRootClass alloc] init];
|
||||
MyRootClass *object2 = [[MyRootClass alloc] init];
|
||||
MyRootClass *object3 = [[MyRootClass alloc] init];
|
||||
int i;
|
||||
|
||||
object1.count = 10;
|
||||
if (object1.count != 10)
|
||||
abort ();
|
||||
|
||||
object2.count = 10;
|
||||
if (object2.count != 10)
|
||||
abort ();
|
||||
|
||||
/* Test multiple assignments to a constant. */
|
||||
object1.count = object2.count = 20;
|
||||
|
||||
if (object1.count != 20 || object2.count != 20)
|
||||
abort ();
|
||||
|
||||
i = object1.count = 30;
|
||||
|
||||
if (i != 30 || object1.count != 30)
|
||||
abort ();
|
||||
|
||||
i = object2.count = 30;
|
||||
|
||||
if (i != 30 || object2.count != 30)
|
||||
abort ();
|
||||
|
||||
/* Test a simple assignment to something with a side-effect; the
|
||||
'rhs' should be evaluated only once. */
|
||||
object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
|
||||
|
||||
if (object1.count != 30 || object2.count != 31)
|
||||
abort ();
|
||||
|
||||
/* Test multiple assignments with side effects. */
|
||||
object3.count = object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
|
||||
|
||||
if (object1.count != 30 || object2.count != 32 || object3.count != 30)
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
113
gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm
Normal file
113
gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* 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 more tricky assignments. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
@interface MyRootClass
|
||||
{
|
||||
Class isa;
|
||||
id a;
|
||||
id b;
|
||||
int p1;
|
||||
float p2;
|
||||
}
|
||||
+ (id) initialize;
|
||||
+ (id) alloc;
|
||||
- (id) init;
|
||||
|
||||
@property (assign) id object1;
|
||||
@property (assign) id object2;
|
||||
- (id) test;
|
||||
- (id) myself;
|
||||
- (id) nilObject;
|
||||
|
||||
@property int p1;
|
||||
@property float p2;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ (id) initialize { return self; }
|
||||
+ (id) alloc { return class_createInstance (self, 0); }
|
||||
- (id) init { return self; }
|
||||
@synthesize object1 = a;
|
||||
@synthesize object2 = b;
|
||||
- (id) test
|
||||
{
|
||||
/* Test multiple assignments with 'self'. */
|
||||
self.object1 = self.object2 = self;
|
||||
|
||||
if (self.object1 != self || self.object2 != self)
|
||||
abort ();
|
||||
|
||||
/* Test multiple assignments with a conditional and method calls. */
|
||||
self.object1 = self.object2 = (self ? [self myself] : [self nilObject]);
|
||||
|
||||
if (self.object1 != self || self.object2 != self)
|
||||
abort ();
|
||||
|
||||
self.object1 = self.object2 = (self ? [self nilObject] : [self myself]);
|
||||
|
||||
if (self.object1 != nil || self.object2 != nil)
|
||||
abort ();
|
||||
|
||||
return self.object1;
|
||||
}
|
||||
- (id) myself
|
||||
{
|
||||
return self;
|
||||
}
|
||||
- (id) nilObject
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@synthesize p1;
|
||||
@synthesize p2;
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
MyRootClass *object1 = [[MyRootClass alloc] init];
|
||||
|
||||
[object test];
|
||||
|
||||
/* Now, test multiple assignments with different types. Use
|
||||
int/float as they seem to happily crash the compiler in gimplify
|
||||
if proper conversions are not being generated by the
|
||||
frontend. ;-) */
|
||||
object.p1 = object.p2 = 12;
|
||||
|
||||
if (object.p1 != 12 || object.p2 != 12)
|
||||
abort ();
|
||||
|
||||
object.p1 = object.p2 = 2.7;
|
||||
|
||||
if (object.p1 != 2)
|
||||
abort ();
|
||||
|
||||
/* Just try a different loop, mixing in a few different standard C
|
||||
constructs to cover a few other cases. */
|
||||
object.p1 = 10;
|
||||
object1.p1 = 0;
|
||||
while (object.p1)
|
||||
{
|
||||
object1.p1 += ((object.p2 = 4.56) ? 0 : object.p1);
|
||||
object.p1--;
|
||||
}
|
||||
|
||||
if (object.p1 != 0 || object1.p1 != 0)
|
||||
abort ();
|
||||
|
||||
if ((object.p1 = 0))
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
67
gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm
Normal file
67
gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-Wall" } */
|
||||
|
||||
/* Test warnings with the dot-syntax. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
@interface MyRootClass
|
||||
{
|
||||
Class isa;
|
||||
id a;
|
||||
id b;
|
||||
int p1;
|
||||
int p2;
|
||||
}
|
||||
+ (id) initialize;
|
||||
+ (id) alloc;
|
||||
- (id) init;
|
||||
|
||||
@property int p1;
|
||||
@property int p2;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ (id) initialize { return self; }
|
||||
+ (id) alloc { return class_createInstance (self, 0); }
|
||||
- (id) init { return self; }
|
||||
@synthesize p1;
|
||||
@synthesize p2;
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
|
||||
/* First, test that the artificial code generated by dot-syntax does
|
||||
not generate unexpected warnings. */
|
||||
|
||||
/* All of the following should generate no warnings. */
|
||||
object.p1 = 0;
|
||||
object.p2 = 0;
|
||||
object.p1 = object.p2 = 0;
|
||||
if (object.p1 > 0)
|
||||
object.p2 = 0;
|
||||
|
||||
object.p1++;
|
||||
++object.p1;
|
||||
object.p1--;
|
||||
--object.p1;
|
||||
|
||||
while (object.p1)
|
||||
object.p1--;
|
||||
|
||||
/* Now test some warnings. */
|
||||
object.p1; /* This warning does not seem to be produced in C++. dg-warning "value computed is not used" */
|
||||
|
||||
/* TODO: It would be good to get the following to warn. */
|
||||
if (object.p1 = 0) /* dg-warning "suggest parentheses around assignment used as truth value" */
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -9,9 +9,6 @@
|
|||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
static int a;
|
||||
static id b;
|
||||
|
||||
@interface MyRootClass
|
||||
{
|
||||
Class isa;
|
||||
|
@ -19,38 +16,16 @@ static id b;
|
|||
+ (id) initialize;
|
||||
+ (id) alloc;
|
||||
- (id) init;
|
||||
+ (int) count;
|
||||
+ (void) setCount: (int)value;
|
||||
+ (id) next;
|
||||
+ (void) setNext: (id)value;
|
||||
@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)value
|
||||
{
|
||||
a = value;
|
||||
}
|
||||
+ (id) next
|
||||
{
|
||||
return b;
|
||||
}
|
||||
+ (void) setNext: (id)value
|
||||
{
|
||||
b = value;
|
||||
}
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
|
||||
MyRootClass.invalid = 40; /* { dg-error "could not find setter.getter" } */
|
||||
if (MyRootClass.invalid != 40) /* { dg-error "could not find setter.getter" } */
|
||||
abort ();
|
||||
|
@ -60,9 +35,9 @@ int main (void)
|
|||
abort ();
|
||||
|
||||
MyRootClass.int; /* { dg-error "expected identifier" } */
|
||||
/* { dg-error "expected" "" { target *-*-* } 62 } */
|
||||
/* { dg-error "expected" "" { target *-*-* } 37 } */
|
||||
if (MyRootClass.int) /* { dg-error "expected identifier" } */
|
||||
/* { dg-error "expected" "" { target *-*-* } 64 } */
|
||||
/* { dg-error "expected" "" { target *-*-* } 39 } */
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
@class MyRootClass;
|
||||
|
||||
static int c;
|
||||
static MyRootClass *shared_root = nil;
|
||||
|
||||
@interface MyRootClass
|
||||
|
|
|
@ -128,31 +128,31 @@ int main (void)
|
|||
if (object.penum != Black)
|
||||
abort ();
|
||||
|
||||
object.pcharp = 0;
|
||||
object.pcharp = (char *)0;
|
||||
if (object.pcharp != 0)
|
||||
abort ();
|
||||
|
||||
object.pshortp = 0;
|
||||
object.pshortp = (short *)0;
|
||||
if (object.pshortp != 0)
|
||||
abort ();
|
||||
|
||||
object.pintp = 0;
|
||||
object.pintp = (int *)0;
|
||||
if (object.pintp != 0)
|
||||
abort ();
|
||||
|
||||
object.plongp = 0;
|
||||
object.plongp = (long *)0;
|
||||
if (object.plongp != 0)
|
||||
abort ();
|
||||
|
||||
object.pfloatp = 0;
|
||||
object.pfloatp = (float *)0;
|
||||
if (object.pfloatp != 0)
|
||||
abort ();
|
||||
|
||||
object.pdoublep = 0;
|
||||
object.pdoublep = (double *)0;
|
||||
if (object.pdoublep != 0)
|
||||
abort ();
|
||||
|
||||
object.penump = 0;
|
||||
object.penump = (enum colour *)0;
|
||||
if (object.penump != 0)
|
||||
abort ();
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
int i;
|
||||
|
||||
object.count = 10;
|
||||
if (object.count != 10)
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
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 */
|
||||
|
|
90
gcc/testsuite/objc.dg/property/dotsyntax-18.m
Normal file
90
gcc/testsuite/objc.dg/property/dotsyntax-18.m
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* 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 tricky assignments. */
|
||||
|
||||
#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;
|
||||
- (int) somethingToExecuteOnlyOnce;
|
||||
@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;
|
||||
}
|
||||
- (int) somethingToExecuteOnlyOnce
|
||||
{
|
||||
a++;
|
||||
return 10;
|
||||
}
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object1 = [[MyRootClass alloc] init];
|
||||
MyRootClass *object2 = [[MyRootClass alloc] init];
|
||||
MyRootClass *object3 = [[MyRootClass alloc] init];
|
||||
int i;
|
||||
|
||||
object1.count = 10;
|
||||
if (object1.count != 10)
|
||||
abort ();
|
||||
|
||||
object2.count = 10;
|
||||
if (object2.count != 10)
|
||||
abort ();
|
||||
|
||||
/* Test multiple assignments to a constant. */
|
||||
object1.count = object2.count = 20;
|
||||
|
||||
if (object1.count != 20 || object2.count != 20)
|
||||
abort ();
|
||||
|
||||
i = object1.count = 30;
|
||||
|
||||
if (i != 30 || object1.count != 30)
|
||||
abort ();
|
||||
|
||||
i = object2.count = 30;
|
||||
|
||||
if (i != 30 || object2.count != 30)
|
||||
abort ();
|
||||
|
||||
/* Test a simple assignment to something with a side-effect; the
|
||||
'rhs' should be evaluated only once. */
|
||||
object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
|
||||
|
||||
if (object1.count != 30 || object2.count != 31)
|
||||
abort ();
|
||||
|
||||
/* Test multiple assignments with side effects. */
|
||||
object3.count = object1.count = ([object2 somethingToExecuteOnlyOnce] > 0 ? 30 : 45);
|
||||
|
||||
if (object1.count != 30 || object2.count != 32 || object3.count != 30)
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
113
gcc/testsuite/objc.dg/property/dotsyntax-19.m
Normal file
113
gcc/testsuite/objc.dg/property/dotsyntax-19.m
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* 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 more tricky assignments. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
@interface MyRootClass
|
||||
{
|
||||
Class isa;
|
||||
id a;
|
||||
id b;
|
||||
int p1;
|
||||
float p2;
|
||||
}
|
||||
+ (id) initialize;
|
||||
+ (id) alloc;
|
||||
- (id) init;
|
||||
|
||||
@property (assign) id object1;
|
||||
@property (assign) id object2;
|
||||
- (id) test;
|
||||
- (id) myself;
|
||||
- (id) nilObject;
|
||||
|
||||
@property int p1;
|
||||
@property float p2;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ (id) initialize { return self; }
|
||||
+ (id) alloc { return class_createInstance (self, 0); }
|
||||
- (id) init { return self; }
|
||||
@synthesize object1 = a;
|
||||
@synthesize object2 = b;
|
||||
- (id) test
|
||||
{
|
||||
/* Test multiple assignments with 'self'. */
|
||||
self.object1 = self.object2 = self;
|
||||
|
||||
if (self.object1 != self || self.object2 != self)
|
||||
abort ();
|
||||
|
||||
/* Test multiple assignments with a conditional and method calls. */
|
||||
self.object1 = self.object2 = (self ? [self myself] : [self nilObject]);
|
||||
|
||||
if (self.object1 != self || self.object2 != self)
|
||||
abort ();
|
||||
|
||||
self.object1 = self.object2 = (self ? [self nilObject] : [self myself]);
|
||||
|
||||
if (self.object1 != nil || self.object2 != nil)
|
||||
abort ();
|
||||
|
||||
return self.object1;
|
||||
}
|
||||
- (id) myself
|
||||
{
|
||||
return self;
|
||||
}
|
||||
- (id) nilObject
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@synthesize p1;
|
||||
@synthesize p2;
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
MyRootClass *object1 = [[MyRootClass alloc] init];
|
||||
|
||||
[object test];
|
||||
|
||||
/* Now, test multiple assignments with different types. Use
|
||||
int/float as they seem to happily crash the compiler in gimplify
|
||||
if proper conversions are not being generated by the
|
||||
frontend. ;-) */
|
||||
object.p1 = object.p2 = 12;
|
||||
|
||||
if (object.p1 != 12 || object.p2 != 12)
|
||||
abort ();
|
||||
|
||||
object.p1 = object.p2 = 2.7;
|
||||
|
||||
if (object.p1 != 2)
|
||||
abort ();
|
||||
|
||||
/* Just try a different loop, mixing in a few different standard C
|
||||
constructs to cover a few other cases. */
|
||||
object.p1 = 10;
|
||||
object1.p1 = 0;
|
||||
while (object.p1)
|
||||
{
|
||||
object1.p1 += ((object.p2 = 4.56) ? 0 : object.p1);
|
||||
object.p1--;
|
||||
}
|
||||
|
||||
if (object.p1 != 0 || object1.p1 != 0)
|
||||
abort ();
|
||||
|
||||
if ((object.p1 = 0))
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
67
gcc/testsuite/objc.dg/property/dotsyntax-20.m
Normal file
67
gcc/testsuite/objc.dg/property/dotsyntax-20.m
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-Wall" } */
|
||||
|
||||
/* Test warnings with the dot-syntax. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
@interface MyRootClass
|
||||
{
|
||||
Class isa;
|
||||
id a;
|
||||
id b;
|
||||
int p1;
|
||||
int p2;
|
||||
}
|
||||
+ (id) initialize;
|
||||
+ (id) alloc;
|
||||
- (id) init;
|
||||
|
||||
@property int p1;
|
||||
@property int p2;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ (id) initialize { return self; }
|
||||
+ (id) alloc { return class_createInstance (self, 0); }
|
||||
- (id) init { return self; }
|
||||
@synthesize p1;
|
||||
@synthesize p2;
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
|
||||
/* First, test that the artificial code generated by dot-syntax does
|
||||
not generate unexpected warnings. */
|
||||
|
||||
/* All of the following should generate no warnings. */
|
||||
object.p1 = 0;
|
||||
object.p2 = 0;
|
||||
object.p1 = object.p2 = 0;
|
||||
if (object.p1 > 0)
|
||||
object.p2 = 0;
|
||||
|
||||
object.p1++;
|
||||
++object.p1;
|
||||
object.p1--;
|
||||
--object.p1;
|
||||
|
||||
while (object.p1)
|
||||
object.p1--;
|
||||
|
||||
/* Now test some warnings. */
|
||||
object.p1; /* { dg-warning "value computed is not used" } */
|
||||
|
||||
/* TODO: It would be good to get the following to warn. */
|
||||
if (object.p1 = 0) /* dg-warning "suggest parentheses around assignment used as truth value" */
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -9,9 +9,6 @@
|
|||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
static int a;
|
||||
static id b;
|
||||
|
||||
@interface MyRootClass
|
||||
{
|
||||
Class isa;
|
||||
|
@ -19,38 +16,16 @@ static id b;
|
|||
+ (id) initialize;
|
||||
+ (id) alloc;
|
||||
- (id) init;
|
||||
+ (int) count;
|
||||
+ (void) setCount: (int)value;
|
||||
+ (id) next;
|
||||
+ (void) setNext: (id)value;
|
||||
@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)value
|
||||
{
|
||||
a = value;
|
||||
}
|
||||
+ (id) next
|
||||
{
|
||||
return b;
|
||||
}
|
||||
+ (void) setNext: (id)value
|
||||
{
|
||||
b = value;
|
||||
}
|
||||
@end
|
||||
|
||||
int main (void)
|
||||
{
|
||||
MyRootClass *object = [[MyRootClass alloc] init];
|
||||
|
||||
MyRootClass.invalid = 40; /* { dg-error "could not find setter.getter" } */
|
||||
if (MyRootClass.invalid != 40) /* { dg-error "could not find setter.getter" } */
|
||||
abort ();
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
@class MyRootClass;
|
||||
|
||||
static int c;
|
||||
static MyRootClass *shared_root = nil;
|
||||
|
||||
@interface MyRootClass
|
||||
|
|
Loading…
Add table
Reference in a new issue