From patchwork Mon Nov 15 20:06:46 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 71272 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id BD5C2B70E9 for ; Tue, 16 Nov 2010 07:08:08 +1100 (EST) Received: (qmail 25936 invoked by alias); 15 Nov 2010 20:08:04 -0000 Received: (qmail 25873 invoked by uid 22791); 15 Nov 2010 20:07:57 -0000 X-SWARE-Spam-Status: No, hits=-0.4 required=5.0 tests=AWL, BAYES_40, TW_BJ, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 15 Nov 2010 20:07:00 +0000 Received: from eggs.gnu.org ([140.186.70.92]:48077) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PI5KK-0002w8-1h for gcc-patches@gnu.org; Mon, 15 Nov 2010 15:06:56 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PI5KB-0006Nn-7R for gcc-patches@gnu.org; Mon, 15 Nov 2010 15:06:57 -0500 Received: from smtp131.iad.emailsrvr.com ([207.97.245.131]:49685) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PI5KB-0006NQ-0t for gcc-patches@gnu.org; Mon, 15 Nov 2010 15:06:47 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp43.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 7F34D2D04E3 for ; Mon, 15 Nov 2010 15:06:46 -0500 (EST) Received: from dynamic12.wm-web.iad.mlsrvr.com (dynamic12.wm-web.iad1a.rsapps.net [192.168.2.219]) by smtp43.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 691C62D04D0 for ; Mon, 15 Nov 2010 15:06:46 -0500 (EST) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic12.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id 16D162168086 for ; Mon, 15 Nov 2010 15:06:46 -0500 (EST) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Mon, 15 Nov 2010 21:06:46 +0100 (CET) Date: Mon, 15 Nov 2010 21:06:46 +0100 (CET) Subject: ObjC/ObjC++: fixed Objective-C 2.0 dot-syntax with multiple assignments and related tricky cases From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1289851606.089714360@192.168.2.229> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch fixes using the Objective-C 2.0 dot-syntax in cases such as object1.property = object2.property = x; A number of testcases are included showing this and related cases compiling and running fine :-) It also tidies up some details in the implementation of "object.property++" and similar that I submitted in my previous patch, and cleans up some related testcases. Ok to commit to trunk ? Thanks In gcc/objc/: 2010-11-15 Nicola Pero * 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 * 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. Index: gcc/objc/objc-act.c =================================================================== --- gcc/objc/objc-act.c (revision 166763) +++ gcc/objc/objc-act.c (working copy) @@ -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 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 { 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 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 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 Index: gcc/objc/ChangeLog =================================================================== --- gcc/objc/ChangeLog (revision 166763) +++ gcc/objc/ChangeLog (working copy) @@ -1,5 +1,17 @@ 2010-11-15 Nicola Pero + * 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 + * 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. Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (revision 166763) +++ gcc/testsuite/ChangeLog (working copy) @@ -1,5 +1,24 @@ 2010-11-15 Nicola Pero + * 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 Nicola Pero + * objc.dg/property/dotsyntax-16.m: New. * objc.dg/property/dotsyntax-17.m: New. * obj-c++.dg/property/dotsyntax-16.mm: New. Index: gcc/testsuite/objc.dg/property/at-property-22.m =================================================================== --- gcc/testsuite/objc.dg/property/at-property-22.m (revision 166763) +++ gcc/testsuite/objc.dg/property/at-property-22.m (working copy) @@ -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 (); Index: gcc/testsuite/objc.dg/property/dotsyntax-17.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-17.m (revision 166763) +++ gcc/testsuite/objc.dg/property/dotsyntax-17.m (working copy) @@ -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 */ Index: gcc/testsuite/objc.dg/property/dotsyntax-19.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-19.m (revision 0) +++ gcc/testsuite/objc.dg/property/dotsyntax-19.m (revision 0) @@ -0,0 +1,113 @@ +/* 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 more tricky assignments. */ + +#include +#include +#include + +@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; +} + + Index: gcc/testsuite/objc.dg/property/dotsyntax-20.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-20.m (revision 0) +++ gcc/testsuite/objc.dg/property/dotsyntax-20.m (revision 0) @@ -0,0 +1,67 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +/* Test warnings with the dot-syntax. */ + +#include +#include +#include + +@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; +} + + Index: gcc/testsuite/objc.dg/property/dotsyntax-16.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-16.m (revision 166763) +++ gcc/testsuite/objc.dg/property/dotsyntax-16.m (working copy) @@ -37,7 +37,6 @@ int main (void) { MyRootClass *object = [[MyRootClass alloc] init]; - int i; object.count = 10; if (object.count != 10) Index: gcc/testsuite/objc.dg/property/dotsyntax-18.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-18.m (revision 0) +++ gcc/testsuite/objc.dg/property/dotsyntax-18.m (revision 0) @@ -0,0 +1,90 @@ +/* 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 tricky assignments. */ + +#include +#include +#include + +@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; +} + + Index: gcc/testsuite/objc.dg/property/dotsyntax-4.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-4.m (revision 166763) +++ gcc/testsuite/objc.dg/property/dotsyntax-4.m (working copy) @@ -9,9 +9,6 @@ #include #include -static int a; -static id b; - @interface MyRootClass { Class isa; @@ -19,38 +16,16 @@ + (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 (); Index: gcc/testsuite/objc.dg/property/dotsyntax-6.m =================================================================== --- gcc/testsuite/objc.dg/property/dotsyntax-6.m (revision 166763) +++ gcc/testsuite/objc.dg/property/dotsyntax-6.m (working copy) @@ -10,7 +10,6 @@ @class MyRootClass; -static int c; static MyRootClass *shared_root = nil; @interface MyRootClass Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-19.mm (revision 0) @@ -0,0 +1,113 @@ +/* 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 more tricky assignments. */ + +#include +#include +#include + +@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; +} + + Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm (revision 166763) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-4.mm (working copy) @@ -9,9 +9,6 @@ #include #include -static int a; -static id b; - @interface MyRootClass { Class isa; @@ -19,38 +16,16 @@ + (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; Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-20.mm (revision 0) @@ -0,0 +1,67 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +/* Test warnings with the dot-syntax. */ + +#include +#include +#include + +@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; +} + + Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm (revision 0) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-18.mm (revision 0) @@ -0,0 +1,90 @@ +/* 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 tricky assignments. */ + +#include +#include +#include + +@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; +} + + Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm (revision 166763) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-17.mm (working copy) @@ -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 */ Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm (revision 166763) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-6.mm (working copy) @@ -10,7 +10,6 @@ @class MyRootClass; -static int c; static MyRootClass *shared_root = nil; @interface MyRootClass Index: gcc/testsuite/obj-c++.dg/property/at-property-22.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/at-property-22.mm (revision 166763) +++ gcc/testsuite/obj-c++.dg/property/at-property-22.mm (working copy) @@ -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 (); Index: gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm =================================================================== --- gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm (revision 166763) +++ gcc/testsuite/obj-c++.dg/property/dotsyntax-16.mm (working copy) @@ -37,7 +37,6 @@ int main (void) { MyRootClass *object = [[MyRootClass alloc] init]; - int i; object.count = 10; if (object.count != 10)