diff options
author | nicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-27 10:06:59 +0000 |
---|---|---|
committer | nicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-27 10:06:59 +0000 |
commit | db49621607d7c5d6f06e52561c8830e3a6be9442 (patch) | |
tree | 3286544b1f9262f2a2f7654ba7439ed2294ca00d | |
parent | c7d2e7f799def96785e9b1fa09c6ad4c76b16a52 (diff) | |
download | gcc-db49621607d7c5d6f06e52561c8830e3a6be9442.tar.gz |
In gcc/objc/:
2010-11-27 Nicola Pero <nicola.pero@meta-innovation.com>
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 <nicola.pero@meta-innovation.com>
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167197 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/objc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 94 | ||||
-rw-r--r-- | gcc/objc/objc-act.h | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/obj-c++.dg/property/at-property-24.mm | 118 | ||||
-rw-r--r-- | gcc/testsuite/obj-c++.dg/property/at-property-25.mm | 87 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/property/at-property-24.m | 118 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/property/at-property-25.m | 87 |
8 files changed, 520 insertions, 13 deletions
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 7c890ce7e2e..1ebff02f1ca 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,5 +1,22 @@ 2010-11-27 Nicola Pero <nicola.pero@meta-innovation.com> + 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-27 Nicola Pero <nicola.pero@meta-innovation.com> + * objc-act.c (objc_build_struct): Fixed loops that save and restore TYPE_OBJC_INFO to iterate over all variants of the type; a special case for the current type is then no longer required. diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 232708f6dbb..70056d39430 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1181,7 +1181,7 @@ objc_add_property_declaration (location_t location, tree decl, /* 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, tree decl, 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, tree decl, 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 interface, tree implementation, 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 property_ident) 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,7 +1505,25 @@ objc_maybe_build_component_ref (tree object, tree property_ident) 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)); } } } @@ -1538,7 +1568,22 @@ objc_maybe_build_component_ref (tree object, tree property_ident) 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 property_ident) 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, tree property_ident) x = maybe_make_artificial_property_decl (rtype, NULL_TREE, NULL_TREE, property_ident, - true); + true, NULL_TREE); if (x) { @@ -10534,7 +10596,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; } @@ -10574,7 +10639,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; } } diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index f612e745d04..6403161da7b 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d0b568a735e..7b6f1306e9b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2010-11-27 Nicola Pero <nicola.pero@meta-innovation.com> + * 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-27 Nicola Pero <nicola.pero@meta-innovation.com> + * objc.dg/protocol-qualifier-1.m: New. * objc.dg/protocol-qualifier-2.m: New. * obj-c++.dg/protocol-qualifier-1.mm: New. diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-24.mm b/gcc/testsuite/obj-c++.dg/property/at-property-24.mm new file mode 100644 index 00000000000..b4a7699f6e4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-24.mm @@ -0,0 +1,118 @@ +/* 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 @optional @properties. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@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 <count> +{ + 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; +} diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-25.mm b/gcc/testsuite/obj-c++.dg/property/at-property-25.mm new file mode 100644 index 00000000000..422a29e552c --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/at-property-25.mm @@ -0,0 +1,87 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test warnings and non-warnings with @optional @properties. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@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 <count> +{ + 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 <count> +@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 <count2> +{ + 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 <count2> +@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 } */ diff --git a/gcc/testsuite/objc.dg/property/at-property-24.m b/gcc/testsuite/objc.dg/property/at-property-24.m new file mode 100644 index 00000000000..b4a7699f6e4 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-24.m @@ -0,0 +1,118 @@ +/* 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 @optional @properties. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@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 <count> +{ + 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; +} diff --git a/gcc/testsuite/objc.dg/property/at-property-25.m b/gcc/testsuite/objc.dg/property/at-property-25.m new file mode 100644 index 00000000000..422a29e552c --- /dev/null +++ b/gcc/testsuite/objc.dg/property/at-property-25.m @@ -0,0 +1,87 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010. */ +/* { dg-do compile } */ + +/* Test warnings and non-warnings with @optional @properties. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +@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 <count> +{ + 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 <count> +@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 <count2> +{ + 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 <count2> +@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 } */ |