From patchwork Wed Nov 3 00:03:10 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 69937 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 4AC94B6EF1 for ; Wed, 3 Nov 2010 11:03:26 +1100 (EST) Received: (qmail 11237 invoked by alias); 3 Nov 2010 00:03:23 -0000 Received: (qmail 11213 invoked by uid 22791); 3 Nov 2010 00:03:19 -0000 X-SWARE-Spam-Status: No, hits=-1.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, TW_BJ, TW_VZ X-Spam-Check-By: sourceware.org Received: from smtp191.iad.emailsrvr.com (HELO smtp191.iad.emailsrvr.com) (207.97.245.191) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 03 Nov 2010 00:03:12 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp49.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 56F8E19082C for ; Tue, 2 Nov 2010 20:03:10 -0400 (EDT) Received: from dynamic10.wm-web.iad.mlsrvr.com (dynamic10.wm-web.iad1a.rsapps.net [192.168.2.217]) by smtp49.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 4096B190790 for ; Tue, 2 Nov 2010 20:03:10 -0400 (EDT) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic10.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id 25AE94788083 for ; Tue, 2 Nov 2010 20:03:10 -0400 (EDT) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Wed, 3 Nov 2010 01:03:10 +0100 (CET) Date: Wed, 3 Nov 2010 01:03:10 +0100 (CET) Subject: ObjC/ObjC++ - support for dotsyntax without a declared property From: "Nicola Pero" To: "GCC Patches" MIME-Version: 1.0 X-Type: plain Message-ID: <1288742590.152924472@192.168.2.230> 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 the lack of support for the Objective-C 2.0 "dotsyntax" when a property is not explicitly declared. In Objective-C 2.0, you can use object.component even if an explicit @property named 'component' had not been explicitly declared; it's enough for the getter (or setter) to exist and they will automatically be used. Our implementation didn't allow for this. This patch fixes this problem; all existing testcases pass and four new testcases for dotsyntax are included (and now pass). :-) Ok to commit to trunk ? Thanks In gcc/objc/: 2010-11-02 Nicola Pero * objc-act.c (maybe_make_artificial_property_decl): New. (objc_maybe_build_component_ref): Call maybe_make_artificial_property_decl if a property can not be found. Do not call objc_finish_message_expr if PROPERTY_HAS_NO_GETTER. * objc-act.h Updated comments. (PROPERTY_HAS_NO_GETTER): New. (PROPERTY_HAS_NO_SETTER): New. * objc-tree.def: Updated comment. In gcc/testsuite/: 2010-11-02 Nicola Pero * objc.dg/property/dotsyntax-1.m: New. * objc.dg/property/dotsyntax-2.m: New. * obj-c++.dg/property/dotsyntax-1.mm: New. * obj-c++.dg/property/dotsyntax-2.mm: New. Index: objc/objc-act.c =================================================================== --- objc/objc-act.c (revision 166218) +++ objc/objc-act.c (working copy) @@ -1053,16 +1053,102 @@ lookup_property (tree interface_type, tree propert return inter; } +/* This is a subroutine of objc_maybe_build_component_ref. Search the + list of methods in the interface (and, failing that, 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. */ +static tree +maybe_make_artificial_property_decl (tree interface, tree protocol_list, tree component, bool is_class) +{ + tree getter_name = component; + tree setter_name = get_identifier (objc_build_property_setter_name (component)); + tree getter = NULL_TREE; + tree setter = NULL_TREE; + if (interface) + { + int flags = 0; + + if (is_class) + flags = OBJC_LOOKUP_CLASS; + + getter = lookup_method_static (interface, getter_name, flags); + setter = lookup_method_static (interface, setter_name, flags); + } + + /* Try the protocol_list if we didn't find anything in the interface. */ + if (!getter && !setter) + { + getter = lookup_method_in_protocol_list (protocol_list, getter_name, is_class); + setter = lookup_method_in_protocol_list (protocol_list, setter_name, is_class); + } + + /* There needs to be at least a getter or setter for this to be a + valid 'object.component' syntax. */ + if (getter || setter) + { + /* Yes ... determine the type of the expression. */ + tree property_decl; + tree type; + + if (getter) + type = TREE_VALUE (TREE_TYPE (getter)); + else + type = TREE_VALUE (TREE_TYPE (METHOD_SEL_ARGS (setter))); + + /* Create an artificial property declaration with the + information we collected on the type and getter/setter + names. */ + property_decl = make_node (PROPERTY_DECL); + + TREE_TYPE (property_decl) = type; + DECL_SOURCE_LOCATION (property_decl) = input_location; + TREE_DEPRECATED (property_decl) = 0; + DECL_ARTIFICIAL (property_decl) = 1; + + /* Add property-specific information. Note that one of + PROPERTY_GETTER_NAME or PROPERTY_SETTER_NAME may refer to a + non-existing method; this will generate an error when the + expression is later compiled. At this stage we don't know if + the getter or setter will be used, so we can't generate an + error. */ + PROPERTY_NAME (property_decl) = component; + PROPERTY_GETTER_NAME (property_decl) = getter_name; + PROPERTY_SETTER_NAME (property_decl) = setter_name; + PROPERTY_READONLY (property_decl) = 0; + PROPERTY_NONATOMIC (property_decl) = 0; + PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0; + PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; + PROPERTY_DYNAMIC (property_decl) = 0; + + if (!getter) + PROPERTY_HAS_NO_GETTER (property_decl) = 1; + + /* The following is currently unused, but it's nice to have + there. We may use it if we need in the future. */ + if (!setter) + PROPERTY_HAS_NO_SETTER (property_decl) = 1; + + return property_decl; + } + + return NULL_TREE; +} + /* This hook routine is invoked by the parser when an expression such as 'xxx.yyy' is parsed. We get a chance to process these expressions in a way that is specified to Objective-C (to implement - properties, or non-fragile ivars). If the expression is not an - Objective-C specified expression, we should return NULL_TREE; else - we return the expression. + the Objective-C 2.0 dot-syntax, properties, or non-fragile ivars). + If the expression is not an Objective-C specified expression, we + should return NULL_TREE; else we return the expression. - At the moment this only implements properties (not non-fragile - ivars yet), ie 'object.property'. */ + At the moment this only implements dot-syntax and properties (not + non-fragile ivars yet), ie 'object.property' or 'object.component' + where 'component' is not a declared property, but a valid getter or + setter for it could be found. */ tree objc_maybe_build_component_ref (tree object, tree property_ident) { @@ -1089,6 +1175,17 @@ objc_maybe_build_component_ref (tree object, tree : NULL_TREE); if (rprotos) x = lookup_property_in_protocol_list (rprotos, property_ident); + + if (x == NULL_TREE) + { + /* Ok, no property. Maybe it was an object.component + dot-syntax without a declared property. Look for + getter/setter methods and internally declare an artifical + property based on them if found. */ + x = maybe_make_artificial_property_decl (NULL_TREE, rprotos, + property_ident, + false); + } } else { @@ -1115,6 +1212,14 @@ objc_maybe_build_component_ref (tree object, tree if (x == NULL_TREE) x = lookup_property_in_protocol_list (protocol_list, property_ident); + + if (x == NULL_TREE) + { + /* Ok, no property. Try the dot-syntax without a + declared property. */ + x = maybe_make_artificial_property_decl (interface_type, protocol_list, + property_ident, false); + } } } @@ -1144,10 +1249,16 @@ objc_maybe_build_component_ref (tree object, tree TODO: This can be made more efficient; in particular we don't need to build the whole message call, we could just work on - the selector. */ - objc_finish_message_expr (object, - PROPERTY_GETTER_NAME (x), - NULL_TREE); + the selector. + + If the PROPERTY_HAS_NO_GETTER() (ie, it is an artificial + property decl created to deal with a dotsyntax not really + referring to an existing property) then do not try to build a + call to the getter as there is no getter. */ + if (!PROPERTY_HAS_NO_GETTER (x)) + objc_finish_message_expr (object, + PROPERTY_GETTER_NAME (x), + NULL_TREE); return expression; } @@ -1197,6 +1308,9 @@ objc_maybe_build_modify_expr (tree lhs, tree rhs) { tree setter_argument = build_tree_list (NULL_TREE, rhs); tree setter; + + /* TODO: Check that the setter return type is 'void'. */ + /* TODO: Decay argument in C. */ setter = objc_finish_message_expr (object_expr, PROPERTY_SETTER_NAME (property_decl), Index: objc/ChangeLog =================================================================== --- objc/ChangeLog (revision 166218) +++ objc/ChangeLog (working copy) @@ -1,3 +1,15 @@ +2010-11-02 Nicola Pero + + * objc-act.c (maybe_make_artificial_property_decl): New. + (objc_maybe_build_component_ref): Call + maybe_make_artificial_property_decl if a property can not be + found. Do not call objc_finish_message_expr if + PROPERTY_HAS_NO_GETTER. + * objc-act.h Updated comments. + (PROPERTY_HAS_NO_GETTER): New. + (PROPERTY_HAS_NO_SETTER): New. + * objc-tree.def: Updated comment. + 2010-11-01 Nicola Pero Implemented format and noreturn attributes for Objective-C methods. Index: objc/objc-tree.def =================================================================== --- objc/objc-tree.def (revision 166218) +++ objc/objc-tree.def (working copy) @@ -55,7 +55,11 @@ DEFTREECODE (CLASS_REFERENCE_EXPR, "class_referenc * else, it will remain as a PROPERTY_REF until we get to gimplification; at that point, we convert each PROPERTY_REF into a 'getter' call during ObjC/ObjC++ gimplify. -*/ + + Please note that when the Objective-C 2.0 "dot-syntax" 'object.component' + is encountered, where 'component' is not a property but there are valid + setter/getter methods for it, an artificial PROPERTY_DECL is generated + and used in the PROPERTY_REF. */ DEFTREECODE (PROPERTY_REF, "property_ref", tcc_expression, 2) /* Index: objc/objc-act.h =================================================================== --- objc/objc-act.h (revision 166218) +++ objc/objc-act.h (working copy) @@ -62,6 +62,11 @@ tree objc_eh_personality (void); /* TREE_TYPE is the type (int, float, etc) of the property. */ +/* DECL_ARTIFICIAL is set to 1 if the PROPERTY_DECL is an artificial + property declaration created when the dot-syntax object.component + is used with no actual @property matching the component, but a + valid getter/setter. */ + /* PROPERTY_NAME is the name of the property. */ #define PROPERTY_NAME(DECL) DECL_NAME(DECL) @@ -99,9 +104,21 @@ typedef enum objc_property_assign_semantics { declaration has been parsed); otherwise, it is set to 0. */ #define PROPERTY_DYNAMIC(DECL) DECL_LANG_FLAG_2 (DECL) +/* PROPERTY_HAS_NO_GETTER can be 0 or 1. Normally it is 0, but if + this is an artificial PROPERTY_DECL that we generate even without a + getter, it is set to 1. */ +#define PROPERTY_HAS_NO_GETTER(DECL) DECL_LANG_FLAG_3 (DECL) +/* PROPERTY_HAS_NO_SETTER can be 0 or 1. Normally it is 0, but if + this is an artificial PROPERTY_DECL that we generate even without a + setter, it is set to 1. */ +#define PROPERTY_HAS_NO_SETTER(DECL) DECL_LANG_FLAG_4 (DECL) + /* PROPERTY_REF. A PROPERTY_REF represents an 'object.property' - expression. */ + expression. It is normally used for property access, but when + the Objective-C 2.0 "dot-syntax" (object.component) is used + with no matching property, a PROPERTY_REF is still created to + represent it, with an artificial PROPERTY_DECL. */ /* PROPERTY_REF_OBJECT is the object whose property we are accessing. */ @@ -109,7 +126,9 @@ typedef enum objc_property_assign_semantics { /* PROPERTY_REF_PROPERTY_DECL is the PROPERTY_DECL for the property used in the expression. From it, you can get the property type, - and the getter/setter names. */ + and the getter/setter names. This PROPERTY_DECL could be artificial + if we are processing an 'object.component' syntax with no matching + declared property. */ #define PROPERTY_REF_PROPERTY_DECL(NODE) TREE_OPERAND (PROPERTY_REF_CHECK (NODE), 1) Index: testsuite/ChangeLog =================================================================== --- testsuite/ChangeLog (revision 166218) +++ testsuite/ChangeLog (working copy) @@ -1,3 +1,10 @@ +2010-11-02 Nicola Pero + + * objc.dg/property/dotsyntax-1.m: New. + * objc.dg/property/dotsyntax-2.m: New. + * obj-c++.dg/property/dotsyntax-1.mm: New. + * obj-c++.dg/property/dotsyntax-2.mm: New. + 2010-11-02 H.J. Lu * gcc.target/i386/avx-vzeroupper-15.c: New. Index: testsuite/objc.dg/property/dotsyntax-1.m =================================================================== --- testsuite/objc.dg/property/dotsyntax-1.m (revision 0) +++ testsuite/objc.dg/property/dotsyntax-1.m (revision 0) @@ -0,0 +1,62 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ + +/* Test the 'dot syntax' without a declarated property. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; + 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]; + + object.count = 40; + if (object.count != 40) + abort (); + + object.next = object; + if (object.next != object) + abort (); + + return 0; +} + + Index: testsuite/objc.dg/property/dotsyntax-2.m =================================================================== --- testsuite/objc.dg/property/dotsyntax-2.m (revision 0) +++ testsuite/objc.dg/property/dotsyntax-2.m (revision 0) @@ -0,0 +1,71 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ + +/* Test the 'dot syntax' without a declarated property. This tests the case where + only the setter (or only the getter) exists. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; + id b; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) a; +- (void) setCount: (int)value; +- (id) b; +- (void) setNext: (id)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) a +{ + return a; +} +- (void) setCount: (int)value +{ + a = value; +} +- (id) b +{ + return b; +} +- (void) setNext: (id)value +{ + b = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + /* This should work because -setCount: exists (even if -count does + not). */ + object.count = 40; + + /* This should work because -a exists (even if -setA: does not). */ + if (object.a != 40) + abort (); + + /* This should work because -setNext: exists (even if -next does + not). */ + object.next = object; + + /* This should work because -b exists (even if -setB: does not). */ + if (object.b != object) + abort (); + + return 0; +} + + Index: testsuite/obj-c++.dg/property/dotsyntax-2.mm =================================================================== --- testsuite/obj-c++.dg/property/dotsyntax-2.mm (revision 0) +++ testsuite/obj-c++.dg/property/dotsyntax-2.mm (revision 0) @@ -0,0 +1,71 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ + +/* Test the 'dot syntax' without a declarated property. This tests the case where + only the setter (or only the getter) exists. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; + id b; +} ++ (id) initialize; ++ (id) alloc; +- (id) init; +- (int) a; +- (void) setCount: (int)value; +- (id) b; +- (void) setNext: (id)value; +@end + +@implementation MyRootClass ++ (id) initialize { return self; } ++ (id) alloc { return class_createInstance (self, 0); } +- (id) init { return self; } +- (int) a +{ + return a; +} +- (void) setCount: (int)value +{ + a = value; +} +- (id) b +{ + return b; +} +- (void) setNext: (id)value +{ + b = value; +} +@end + +int main (void) +{ + MyRootClass *object = [[MyRootClass alloc] init]; + + /* This should work because -setCount: exists (even if -count does + not). */ + object.count = 40; + + /* This should work because -a exists (even if -setA: does not). */ + if (object.a != 40) + abort (); + + /* This should work because -setNext: exists (even if -next does + not). */ + object.next = object; + + /* This should work because -b exists (even if -setB: does not). */ + if (object.b != object) + abort (); + + return 0; +} + + Index: testsuite/obj-c++.dg/property/dotsyntax-1.mm =================================================================== --- testsuite/obj-c++.dg/property/dotsyntax-1.mm (revision 0) +++ testsuite/obj-c++.dg/property/dotsyntax-1.mm (revision 0) @@ -0,0 +1,62 @@ +/* Contributed by Nicola Pero , November 2010. */ +/* { dg-do run } */ + +/* Test the 'dot syntax' without a declarated property. */ + +#include +#include +#include + +@interface MyRootClass +{ + Class isa; + int a; + 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]; + + object.count = 40; + if (object.count != 40) + abort (); + + object.next = object; + if (object.next != object) + abort (); + + return 0; +} + +