===================================================================
@@ -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;
}
}
===================================================================
@@ -1,3 +1,20 @@
+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-25 Nicola Pero <nicola.pero@meta-innovation.com>
* objc-act.c (objc_build_struct): Install TYPE_OBJC_INTERFACE
===================================================================
@@ -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
===================================================================
@@ -1,3 +1,10 @@
+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-26 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* lib/gnat.exp: Load gcc.exp.
===================================================================
@@ -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;
+}
===================================================================
@@ -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 } */
===================================================================
@@ -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 } */
===================================================================
@@ -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;
+}