From patchwork Sat Nov 27 00:22:05 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 73255 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 5BCFEB70E8 for ; Sat, 27 Nov 2010 11:22:37 +1100 (EST) Received: (qmail 8228 invoked by alias); 27 Nov 2010 00:22:31 -0000 Received: (qmail 8198 invoked by uid 22791); 27 Nov 2010 00:22:23 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL, BAYES_00, TW_BJ, 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; Sat, 27 Nov 2010 00:22:13 +0000 Received: from eggs.gnu.org ([140.186.70.92]:58579) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1PM8YK-0007OT-Nk for gcc-patches@gnu.org; Fri, 26 Nov 2010 19:22:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PM8YI-0007J5-O4 for gcc-patches@gnu.org; Fri, 26 Nov 2010 19:22:10 -0500 Received: from smtp151.iad.emailsrvr.com ([207.97.245.151]:33098) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PM8YI-0007Iv-IX for gcc-patches@gnu.org; Fri, 26 Nov 2010 19:22:06 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp45.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id F23399055B for ; Fri, 26 Nov 2010 19:22:05 -0500 (EST) Received: from dynamic3.wm-web.iad.mlsrvr.com (dynamic3.wm-web.iad1a.rsapps.net [192.168.2.152]) by smtp45.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id DF91390145 for ; Fri, 26 Nov 2010 19:22:05 -0500 (EST) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic3.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id A58B3332006E for ; Fri, 26 Nov 2010 19:22:05 -0500 (EST) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Sat, 27 Nov 2010 01:22:05 +0100 (CET) Date: Sat, 27 Nov 2010 01:22:05 +0100 (CET) Subject: ObjC/ObjC++ patch: implementation of @optional @properties From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1290817325.675814659@192.168.2.227> 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 ObjC/ObjC++ patch adds the final missing @property bit that I was planning to do for 4.6, which is support for @properties marked as @optional inside a @protocol. 4 testcases are included. :-) Ok to commit ? Thanks In gcc/objc/: 2010-11-27 Nicola Pero Implemented optional properties. * objc-act.h (PROPERTY_OPTIONAL): New. * objc-act.c (objc_add_property_declaration): Set PROPERTY_OPTIONAL if appropriate. (finish_class): When generating definitions of setter and getter methods associated with a property for a protocol, mark them as optional if the property is optional. (maybe_make_artificial_property_decl): Added 'getter_name' argument. Set PROPERTY_OPTIONAL. (objc_maybe_build_component_ref): Updated calls to maybe_make_artificial_property_decl. Added code for optional, readonly properties. (objc_build_class_component_ref): Updated call to maybe_make_artificial_property_decl. In gcc/testsuite/: 2010-11-27 Nicola Pero * objc.dg/property/at-property-24.m: New. * objc.dg/property/at-property-25.m: New. * obj-c++.dg/property/at-property-24.mm: New. * obj-c++.dg/property/at-property-25.mm: New. Index: objc/objc-act.c =================================================================== --- objc/objc-act.c (revision 167188) +++ objc/objc-act.c (working copy) @@ -1181,7 +1181,7 @@ objc_add_property_declaration (location_t location /* An existing property was found; check that it has the same types, or it is compatible. */ location_t original_location = DECL_SOURCE_LOCATION (x); - + if (PROPERTY_NONATOMIC (x) != parsed_property_nonatomic) { warning_at (location, 0, @@ -1293,6 +1293,13 @@ objc_add_property_declaration (location_t location PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (property_decl) = 0; + /* Remember the fact that the property was found in the @optional + section in a @protocol, or not. */ + if (objc_method_optional_flag) + PROPERTY_OPTIONAL (property_decl) = 1; + else + PROPERTY_OPTIONAL (property_decl) = 0; + /* Note that PROPERTY_GETTER_NAME is always set for all PROPERTY_DECLs, and PROPERTY_SETTER_NAME is always set for all PROPERTY_DECLs where PROPERTY_READONLY == 0. Any time we deal @@ -1310,18 +1317,22 @@ objc_add_property_declaration (location_t location in the implementation, and failing that, the protocol list) provided for a 'setter' or 'getter' for 'component' with default names (ie, if 'component' is "name", then search for "name" and - "setName:"). If any is found, then create an artificial property - that uses them. Return NULL_TREE if 'getter' or 'setter' could not - be found. */ + "setName:"). It is also possible to specify a different + 'getter_name' (this is used for @optional readonly properties). If + any is found, then create an artificial property that uses them. + Return NULL_TREE if 'getter' or 'setter' could not be found. */ static tree maybe_make_artificial_property_decl (tree interface, tree implementation, - tree protocol_list, tree component, bool is_class) + tree protocol_list, tree component, bool is_class, + tree getter_name) { - tree getter_name = component; tree setter_name = get_identifier (objc_build_property_setter_name (component)); tree getter = NULL_TREE; tree setter = NULL_TREE; + if (getter_name == NULL_TREE) + getter_name = component; + /* First, check the @interface and all superclasses. */ if (interface) { @@ -1401,6 +1412,7 @@ maybe_make_artificial_property_decl (tree interfac PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0; PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (property_decl) = 0; + PROPERTY_OPTIONAL (property_decl) = 0; if (!getter) PROPERTY_HAS_NO_GETTER (property_decl) = 1; @@ -1481,7 +1493,7 @@ objc_maybe_build_component_ref (tree object, tree properties. */ if (!IS_CLASS (rtype)) x = lookup_property_in_protocol_list (rprotos, property_ident); - + if (x == NULL_TREE) { /* Ok, no property. Maybe it was an @@ -1493,8 +1505,26 @@ objc_maybe_build_component_ref (tree object, tree NULL_TREE, rprotos, property_ident, - IS_CLASS (rtype)); + IS_CLASS (rtype), + NULL_TREE); } + else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x)) + { + /* This is a special, complicated case. If the + property is optional, and is read-only, then the + property is always used for reading, but an + eventual existing non-property setter can be used + for writing. We create an artificial property + decl copying the getter from the optional + property, and looking up the setter in the + interface. */ + x = maybe_make_artificial_property_decl (NULL_TREE, + NULL_TREE, + rprotos, + property_ident, + false, + PROPERTY_GETTER_NAME (x)); + } } } else if (objc_method_context) @@ -1538,8 +1568,23 @@ objc_maybe_build_component_ref (tree object, tree x = maybe_make_artificial_property_decl (interface_type, implementation, NULL_TREE, property_ident, - (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)); + (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL), + NULL_TREE); } + else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x)) + { + tree implementation = NULL_TREE; + + if (t == self_decl) + implementation = objc_implementation_context; + + x = maybe_make_artificial_property_decl (interface_type, + implementation, + NULL_TREE, + property_ident, + false, + PROPERTY_GETTER_NAME (x)); + } } } } @@ -1603,8 +1648,25 @@ objc_maybe_build_component_ref (tree object, tree implementation, protocol_list, property_ident, - IS_CLASS (rtype)); + IS_CLASS (rtype), + NULL_TREE); } + else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x)) + { + tree implementation = NULL_TREE; + + if (objc_implementation_context + && CLASS_NAME (objc_implementation_context) + == OBJC_TYPE_NAME (interface_type)) + implementation = objc_implementation_context; + + x = maybe_make_artificial_property_decl (interface_type, + implementation, + protocol_list, + property_ident, + false, + PROPERTY_GETTER_NAME (x)); + } } } } @@ -1703,7 +1765,7 @@ objc_build_class_component_ref (tree class_name, t x = maybe_make_artificial_property_decl (rtype, NULL_TREE, NULL_TREE, property_ident, - true); + true, NULL_TREE); if (x) { @@ -10515,7 +10577,10 @@ finish_class (tree klass) getter_decl = build_method_decl (INSTANCE_METHOD_DECL, rettype, PROPERTY_GETTER_NAME (x), NULL_TREE, false); - objc_add_method (objc_interface_context, getter_decl, false, false); + if (PROPERTY_OPTIONAL (x)) + objc_add_method (objc_interface_context, getter_decl, false, true); + else + objc_add_method (objc_interface_context, getter_decl, false, false); METHOD_PROPERTY_CONTEXT (getter_decl) = x; } @@ -10555,7 +10620,10 @@ finish_class (tree klass) ret_type, selector, build_tree_list (NULL_TREE, NULL_TREE), false); - objc_add_method (objc_interface_context, setter_decl, false, false); + if (PROPERTY_OPTIONAL (x)) + objc_add_method (objc_interface_context, setter_decl, false, true); + else + objc_add_method (objc_interface_context, setter_decl, false, false); METHOD_PROPERTY_CONTEXT (setter_decl) = x; } } Index: objc/ChangeLog =================================================================== --- objc/ChangeLog (revision 167188) +++ objc/ChangeLog (working copy) @@ -1,3 +1,20 @@ +2010-11-27 Nicola Pero + + Implemented optional properties. + * objc-act.h (PROPERTY_OPTIONAL): New. + * objc-act.c (objc_add_property_declaration): Set + PROPERTY_OPTIONAL if appropriate. + (finish_class): When generating definitions of setter and getter + methods associated with a property for a protocol, mark them as + optional if the property is optional. + (maybe_make_artificial_property_decl): Added 'getter_name' + argument. Set PROPERTY_OPTIONAL. + (objc_maybe_build_component_ref): Updated calls to + maybe_make_artificial_property_decl. Added code for optional, + readonly properties. + (objc_build_class_component_ref): Updated call to + maybe_make_artificial_property_decl. + 2010-11-25 Nicola Pero * objc-act.c (objc_build_struct): Install TYPE_OBJC_INTERFACE Index: objc/objc-act.h =================================================================== --- objc/objc-act.h (revision 167188) +++ objc/objc-act.h (working copy) @@ -113,6 +113,11 @@ typedef enum objc_property_assign_semantics { setter, it is set to 1. */ #define PROPERTY_HAS_NO_SETTER(DECL) DECL_LANG_FLAG_4 (DECL) +/* PROPERTY_OPTIONAL can be 0 or 1. Normally it is 0, but if this is + a property declared as @optional in a @protocol, then it is set to + 1. */ +#define PROPERTY_OPTIONAL(DECL) DECL_LANG_FLAG_5 (DECL) + /* PROPERTY_REF. A PROPERTY_REF represents an 'object.property' expression. It is normally used for property access, but when the Objective-C 2.0 "dot-syntax" (object.component) is used Index: testsuite/ChangeLog =================================================================== --- testsuite/ChangeLog (revision 167188) +++ testsuite/ChangeLog (working copy) @@ -1,3 +1,10 @@ +2010-11-27 Nicola Pero + + * objc.dg/property/at-property-24.m: New. + * objc.dg/property/at-property-25.m: New. + * obj-c++.dg/property/at-property-24.mm: New. + * obj-c++.dg/property/at-property-25.mm: New. + 2010-11-26 Rainer Orth * lib/gnat.exp: Load gcc.exp. Index: testsuite/objc.dg/property/at-property-24.m =================================================================== --- testsuite/objc.dg/property/at-property-24.m (revision 0) +++ testsuite/objc.dg/property/at-property-24.m (revision 0) @@ -0,0 +1,118 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @optional @properties. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +/* Use a different getters/setters, so that the only way to compile + object.countX is to find the actual @property. */ +@protocol count +@required +/* @required + @synthesize. */ +@property (getter=number1, setter=setNumber1:) int count1; +/* @required + manual setters/getters. */ +@property (getter=number2, setter=setNumber2:) int count2; + +@optional +/* @optional + @synthesize. */ +@property (getter=number3, setter=setNumber3:) int count3; +/* @optional + manual setters/getters. */ +@property (getter=number4, setter=setNumber4:) int count4; + +@optional +/* @optional + readonly, with a setter added in the class itself. */ +@property (readonly, getter=number5) int count5; +@end + +@interface MySubClass : MyRootClass +{ + int count1; + int count2; + int count3; + int count4; + int count5; +} +- (void) setCount5: (int)value; +@end + +@implementation MySubClass +@synthesize count1; +- (int) number2 +{ + return count2; +} +- (void) setNumber2: (int)value +{ + count2 = value; +} +@synthesize count3; +- (int) number4 +{ + return count4; +} +- (void) setNumber4: (int)value +{ + count4 = value; +} +- (int) number5 +{ + return count5; +} +- (void) setCount5: (int)value +{ + count5 = value; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + /* First, test that @required and @optional properties work as + expected if implemented either via @synthesize or manually. */ + object.count1 = 44; + if (object.count1 != 44) + abort (); + + object.count2 = 88; + if (object.count2 != 88) + abort (); + + object.count3 = 77; + if (object.count3 != 77) + abort (); + + object.count4 = 11; + if (object.count4 != 11) + abort (); + + /* Now, test the complication: @optional @property which is + readonly, but which has a setter manually implemented. + Apparently it is possible to use the dotsyntax and the @optional + @property getter is used when reading, while the manual setter is + used when writing. */ + object.count5 = 99; + if (object.count5 != 99) + abort (); + + return 0; +} Index: testsuite/objc.dg/property/at-property-25.m =================================================================== --- testsuite/objc.dg/property/at-property-25.m (revision 0) +++ testsuite/objc.dg/property/at-property-25.m (revision 0) @@ -0,0 +1,87 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test warnings and non-warnings with @optional @properties. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count +@optional +@property int count1; +@property (readonly) int count2; +@end + + +/* A class that implements all the properties. */ +@interface MySubClass1 : MyRootClass +{ + int count1; + int count2; +} +@end + +@implementation MySubClass1 +@synthesize count1; +@synthesize count2; +@end + + +/* A class that implements nothing; no warnings as the properties are + all optional. */ +@interface MySubClass2 : MyRootClass +@end + +@implementation MySubClass2 +@end + + +@protocol count2 +@required +@property int count1; +@property (readonly) int count2; +@end + +/* A class that implements all the properties. */ +@interface MySubClass3 : MyRootClass +{ + int count1; + int count2; +} +@end + +@implementation MySubClass3 +@synthesize count1; +@synthesize count2; +@end + + +/* A class that implements nothing; warnings as the properties are + all required. */ +@interface MySubClass4 : MyRootClass +@end + +@implementation MySubClass4 +@end + +/* { dg-warning "incomplete implementation of class" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..setCount1:. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..count1. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..count2. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "class .MySubClass4. does not fully implement the .count2. protocol" "" { target *-*-* } 81 } */ Index: testsuite/obj-c++.dg/property/at-property-25.mm =================================================================== --- testsuite/obj-c++.dg/property/at-property-25.mm (revision 0) +++ testsuite/obj-c++.dg/property/at-property-25.mm (revision 0) @@ -0,0 +1,87 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do compile } */ + +/* Test warnings and non-warnings with @optional @properties. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +@protocol count +@optional +@property int count1; +@property (readonly) int count2; +@end + + +/* A class that implements all the properties. */ +@interface MySubClass1 : MyRootClass +{ + int count1; + int count2; +} +@end + +@implementation MySubClass1 +@synthesize count1; +@synthesize count2; +@end + + +/* A class that implements nothing; no warnings as the properties are + all optional. */ +@interface MySubClass2 : MyRootClass +@end + +@implementation MySubClass2 +@end + + +@protocol count2 +@required +@property int count1; +@property (readonly) int count2; +@end + +/* A class that implements all the properties. */ +@interface MySubClass3 : MyRootClass +{ + int count1; + int count2; +} +@end + +@implementation MySubClass3 +@synthesize count1; +@synthesize count2; +@end + + +/* A class that implements nothing; warnings as the properties are + all required. */ +@interface MySubClass4 : MyRootClass +@end + +@implementation MySubClass4 +@end + +/* { dg-warning "incomplete implementation of class" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..setCount1:. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..count1. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "method definition for ..count2. not found" "" { target *-*-* } 81 } */ +/* { dg-warning "class .MySubClass4. does not fully implement the .count2. protocol" "" { target *-*-* } 81 } */ Index: testsuite/obj-c++.dg/property/at-property-24.mm =================================================================== --- testsuite/obj-c++.dg/property/at-property-24.mm (revision 0) +++ testsuite/obj-c++.dg/property/at-property-24.mm (revision 0) @@ -0,0 +1,118 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +/* Test @optional @properties. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +@end + +/* Use a different getters/setters, so that the only way to compile + object.countX is to find the actual @property. */ +@protocol count +@required +/* @required + @synthesize. */ +@property (getter=number1, setter=setNumber1:) int count1; +/* @required + manual setters/getters. */ +@property (getter=number2, setter=setNumber2:) int count2; + +@optional +/* @optional + @synthesize. */ +@property (getter=number3, setter=setNumber3:) int count3; +/* @optional + manual setters/getters. */ +@property (getter=number4, setter=setNumber4:) int count4; + +@optional +/* @optional + readonly, with a setter added in the class itself. */ +@property (readonly, getter=number5) int count5; +@end + +@interface MySubClass : MyRootClass +{ + int count1; + int count2; + int count3; + int count4; + int count5; +} +- (void) setCount5: (int)value; +@end + +@implementation MySubClass +@synthesize count1; +- (int) number2 +{ + return count2; +} +- (void) setNumber2: (int)value +{ + count2 = value; +} +@synthesize count3; +- (int) number4 +{ + return count4; +} +- (void) setNumber4: (int)value +{ + count4 = value; +} +- (int) number5 +{ + return count5; +} +- (void) setCount5: (int)value +{ + count5 = value; +} +@end + +int main (void) +{ + MySubClass *object = [[MySubClass alloc] init]; + + /* First, test that @required and @optional properties work as + expected if implemented either via @synthesize or manually. */ + object.count1 = 44; + if (object.count1 != 44) + abort (); + + object.count2 = 88; + if (object.count2 != 88) + abort (); + + object.count3 = 77; + if (object.count3 != 77) + abort (); + + object.count4 = 11; + if (object.count4 != 11) + abort (); + + /* Now, test the complication: @optional @property which is + readonly, but which has a setter manually implemented. + Apparently it is possible to use the dotsyntax and the @optional + @property getter is used when reading, while the manual setter is + used when writing. */ + object.count5 = 99; + if (object.count5 != 99) + abort (); + + return 0; +}