aboutsummaryrefslogtreecommitdiff
path: root/gcc/objc/objc-act.c
diff options
context:
space:
mode:
authorNicola Pero <nicola.pero@meta-innovation.com>2010-11-01 20:06:36 +0000
committerNicola Pero <nicola@gcc.gnu.org>2010-11-01 20:06:36 +0000
commit8f07a2aa357fd67ca7ef1e640424bc605c6cec31 (patch)
tree53252370c4f738209d137b61fe83ed7b6b403a21 /gcc/objc/objc-act.c
parent1fccc6c3464c8862297bdf74d7bf22ac245e4639 (diff)
downloadgcc-8f07a2aa357fd67ca7ef1e640424bc605c6cec31.zip
gcc-8f07a2aa357fd67ca7ef1e640424bc605c6cec31.tar.gz
gcc-8f07a2aa357fd67ca7ef1e640424bc605c6cec31.tar.bz2
In gcc/objc/: 2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com>
In gcc/objc/: 2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com> Implemented Objective-C 2.0 property accessors. * objc-act.h (enum objc_tree_index): Added OCTI_GET_PROPERTY_DECL, OCTI_SET_PROPERTY_DECL, OCTI_COPY_STRUCT_DECL, OCTI_GET_PROPERTY_STRUCT_DECL and OCTI_SET_PROPERTY_STRUCT_DECL. (objc_getProperty_decl): New. (objc_setProperty_decl): New. (objc_copyStruct_decl): New. (objc_getPropertyStruct_decl): New. (objc_setPropertyStruct_decl): New. * objc-act.c (build_objc_property_accessor_helpers): New. (synth_module_prologue): Call build_objc_property_accessor_helpers. (lookup_ivar): New. (objc_synthesize_getter): Implemented synthesizing getters that work with properties that are not nonatomic, assign properties. (objc_synthesize_setter): Implemented synthesizing setters that work with properties that are not nonatomic, assign properties. In gcc/testsuite/: 2010-11-01 Nicola Pero <nicola.pero@meta-innovation.com> Implemented Objective-C 2.0 property accessors. * objc.dg/property/at-property-6.m: Use nonatomic properties to avoid testing more complex accessors in this testcase which is not about them. * objc.dg/property/at-property-7.m: Same change. * objc.dg/property/at-property-8.m: Same change. * objc.dg/property/at-property-9.m: Same change. * objc.dg/property/at-property-10.m: Same change. * objc.dg/property/at-property-11.m: Same change. * obj-c++.dg/property/at-property-6.mm: Same change. * obj-c++.dg/property/at-property-7.mm: Same change. * obj-c++.dg/property/at-property-8.mm: Same change. * obj-c++.dg/property/at-property-9.mm: Same change. * obj-c++.dg/property/at-property-10.mm: Same change. * obj-c++.dg/property/at-property-11.mm: Same change. * objc.dg/property/at-property-12.m: New. * objc.dg/property/at-property-13.m: New. * obj-c++.dg/property/at-property-12.mm: New. * obj-c++.dg/property/at-property-13.mm: New. From-SVN: r166143
Diffstat (limited to 'gcc/objc/objc-act.c')
-rw-r--r--gcc/objc/objc-act.c435
1 files changed, 393 insertions, 42 deletions
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index e564da5..00e2a43 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -178,6 +178,7 @@ static int match_proto_with_proto (tree, tree, int);
static tree lookup_property (tree, tree);
static tree lookup_property_in_list (tree, tree);
static tree lookup_property_in_protocol_list (tree, tree);
+static void build_objc_property_accessor_helpers (void);
static void objc_xref_basetypes (tree, tree);
@@ -2348,6 +2349,10 @@ synth_module_prologue (void)
build_category_template ();
build_objc_exception_stuff ();
+ /* Declare objc_getProperty, object_setProperty and other property
+ accessor helpers. */
+ build_objc_property_accessor_helpers ();
+
if (flag_next_runtime)
build_next_objc_exception_stuff ();
@@ -7938,6 +7943,7 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility,
return klass;
}
+
static tree
is_ivar (tree decl_chain, tree ident)
{
@@ -8516,11 +8522,120 @@ objc_build_property_setter_name (tree ident)
return string;
}
+/* This routine prepares the declarations of the property accessor
+ helper functions (objc_getProperty(), etc) that are used when
+ @synthesize is used. */
+static void
+build_objc_property_accessor_helpers (void)
+{
+ tree type;
+
+ /* Declare the following function:
+ id
+ objc_getProperty (id self, SEL _cmd,
+ ptrdiff_t offset, BOOL is_atomic); */
+ type = build_function_type_list (objc_object_type,
+ objc_object_type,
+ objc_selector_type,
+ ptrdiff_type_node,
+ boolean_type_node,
+ NULL_TREE);
+ objc_getProperty_decl = add_builtin_function ("objc_getProperty",
+ type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ TREE_NOTHROW (objc_getProperty_decl) = 0;
+
+ /* Declare the following function:
+ void
+ objc_setProperty (id self, SEL _cmd,
+ ptrdiff_t offset, id new_value,
+ BOOL is_atomic, BOOL should_copy); */
+ type = build_function_type_list (void_type_node,
+ objc_object_type,
+ objc_selector_type,
+ ptrdiff_type_node,
+ objc_object_type,
+ boolean_type_node,
+ boolean_type_node,
+ NULL_TREE);
+ objc_setProperty_decl = add_builtin_function ("objc_setProperty",
+ type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ TREE_NOTHROW (objc_setProperty_decl) = 0;
+
+ /* This is the type of all of the following functions
+ (objc_copyStruct(), objc_getPropertyStruct() and
+ objc_setPropertyStruct()). */
+ type = build_function_type_list (void_type_node,
+ ptr_type_node,
+ const_ptr_type_node,
+ ptrdiff_type_node,
+ boolean_type_node,
+ boolean_type_node,
+ NULL_TREE);
+
+ if (flag_next_runtime)
+ {
+ /* Declare the following function:
+ void
+ objc_copyStruct (void *destination, const void *source,
+ ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */
+ objc_copyStruct_decl = add_builtin_function ("objc_copyStruct",
+ type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ TREE_NOTHROW (objc_copyStruct_decl) = 0;
+ objc_getPropertyStruct_decl = NULL_TREE;
+ objc_setPropertyStruct_decl = NULL_TREE;
+ }
+ else
+ {
+ objc_copyStruct_decl = NULL_TREE;
+
+ /* Declare the following function:
+ void
+ objc_getPropertyStruct (void *destination, const void *source,
+ ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */
+ objc_getPropertyStruct_decl = add_builtin_function ("objc_getPropertyStruct",
+ type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ TREE_NOTHROW (objc_getPropertyStruct_decl) = 0;
+ /* Declare the following function:
+ void
+ objc_setPropertyStruct (void *destination, const void *source,
+ ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */
+ objc_setPropertyStruct_decl = add_builtin_function ("objc_setPropertyStruct",
+ type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ TREE_NOTHROW (objc_setPropertyStruct_decl) = 0;
+ }
+}
+
+/* This looks up an ivar in a class (including superclasses). */
+static tree
+lookup_ivar (tree interface, tree instance_variable_name)
+{
+ while (interface)
+ {
+ tree decl_chain;
+
+ for (decl_chain = CLASS_IVARS (interface); decl_chain; decl_chain = DECL_CHAIN (decl_chain))
+ if (DECL_NAME (decl_chain) == instance_variable_name)
+ return decl_chain;
+
+ /* Not found. Search superclass if any. */
+ if (CLASS_SUPER_NAME (interface))
+ interface = lookup_interface (CLASS_SUPER_NAME (interface));
+ }
+
+ return NULL_TREE;
+}
+
/* This routine synthesizes a 'getter' method. This is only called
for @synthesize properties. */
static void
-objc_synthesize_getter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
+objc_synthesize_getter (tree klass, tree class_method, tree property)
{
+ location_t location = DECL_SOURCE_LOCATION (property);
tree fn, decl;
tree body;
tree ret_val;
@@ -8543,29 +8658,150 @@ objc_synthesize_getter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
/* Adapt the 'decl'. Use the source location of the @synthesize
statement for error messages. */
decl = copy_node (decl);
- DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (property);
+ DECL_SOURCE_LOCATION (decl) = location;
objc_start_method_definition (false /* is_class_method */, decl, NULL_TREE);
body = c_begin_compound_stmt (true);
- /* TODO: Implement PROPERTY_NONATOMIC, use objc_getProperty etc as
- appropriate. The following code just always does direct ivar
- access. */
+ /* Now we need to decide how we build the getter. There are three
+ cases:
+
+ for 'copy' or 'retain' properties we need to use the
+ objc_getProperty() accessor helper which knows about retain and
+ copy. It supports both 'nonatomic' and 'atomic' access.
- /* return self->_property_name; */
+ for 'nonatomic, assign' properties we can access the instance
+ variable directly. 'nonatomic' means we don't have to use locks,
+ and 'assign' means we don't have to worry about retain or copy.
+ If you combine the two, it means we can just access the instance
+ variable directly.
+
+ for 'atomic, assign' properties we use objc_copyStruct() (for the
+ next runtime) or objc_getPropertyStruct() (for the GNU runtime). */
+ switch (PROPERTY_ASSIGN_SEMANTICS (property))
+ {
+ case OBJC_PROPERTY_RETAIN:
+ case OBJC_PROPERTY_COPY:
+ {
+ /* We build "return objc_getProperty (self, _cmd, offset, is_atomic);" */
+ tree cmd, ivar, offset, is_atomic;
+ cmd = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
+
+ /* Find the ivar to compute the offset. */
+ ivar = lookup_ivar (klass, PROPERTY_IVAR_NAME (property));
+ if (!ivar || is_private (ivar))
+ {
+ /* This should never happen. */
+ error_at (location,
+ "can not find instance variable associated with property");
+ ret_val = error_mark_node;
+ break;
+ }
+ offset = byte_position (ivar);
+
+ if (PROPERTY_NONATOMIC (property))
+ is_atomic = boolean_false_node;
+ else
+ is_atomic = boolean_true_node;
+
+ ret_val = build_function_call
+ (location,
+ /* Function prototype. */
+ objc_getProperty_decl,
+ /* Parameters. */
+ tree_cons /* self */
+ (NULL_TREE, self_decl,
+ tree_cons /* _cmd */
+ (NULL_TREE, cmd,
+ tree_cons /* offset */
+ (NULL_TREE, offset,
+ tree_cons /* is_atomic */
+ (NULL_TREE, is_atomic, NULL_TREE)))));
+ }
+ break;
+ case OBJC_PROPERTY_ASSIGN:
+ if (PROPERTY_NONATOMIC (property))
+ {
+ /* We build "return self->PROPERTY_IVAR_NAME;" */
+ ret_val = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
+ break;
+ }
+ else
+ {
+ /* We build
+ <property type> __objc_property_temp;
+ objc_getPropertyStruct (&__objc_property_temp,
+ &(self->PROPERTY_IVAR_NAME),
+ sizeof (type of self->PROPERTY_IVAR_NAME),
+ is_atomic,
+ false)
+ return __objc_property_temp;
+
+ For the NeXT runtime, we need to use objc_copyStruct
+ instead of objc_getPropertyStruct. */
+ tree objc_property_temp_decl, function_decl, function_call;
+ tree size_of, is_atomic;
+
+ objc_property_temp_decl = objc_create_temporary_var (TREE_TYPE (property), "__objc_property_temp");
+ DECL_SOURCE_LOCATION (objc_property_temp_decl) = location;
+ objc_property_temp_decl = lang_hooks.decls.pushdecl (objc_property_temp_decl);
+
+ /* sizeof (ivar type). Since the ivar and the property have
+ the same type, there is no need to lookup the ivar. */
+ size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
+ true /* is_sizeof */,
+ false /* complain */);
+
+ if (PROPERTY_NONATOMIC (property))
+ is_atomic = boolean_false_node;
+ else
+ is_atomic = boolean_true_node;
+
+ if (flag_next_runtime)
+ function_decl = objc_copyStruct_decl;
+ else
+ function_decl = objc_getPropertyStruct_decl;
+
+ function_call = build_function_call
+ (location,
+ /* Function prototype. */
+ function_decl,
+ /* Parameters. */
+ tree_cons /* &__objc_property_temp_decl */
+ /* Warning: note that using build_fold_addr_expr_loc()
+ here causes invalid code to be generated. */
+ (NULL_TREE, build_unary_op (location, ADDR_EXPR, objc_property_temp_decl, 0),
+ tree_cons /* &(self->PROPERTY_IVAR_NAME); */
+ (NULL_TREE, build_fold_addr_expr_loc (location,
+ objc_lookup_ivar
+ (NULL_TREE, PROPERTY_IVAR_NAME (property))),
+ tree_cons /* sizeof (PROPERTY_IVAR) */
+ (NULL_TREE, size_of,
+ tree_cons /* is_atomic */
+ (NULL_TREE, is_atomic,
+ /* TODO: This is currently ignored by the GNU
+ runtime, but what about the next one ? */
+ tree_cons /* has_strong */
+ (NULL_TREE, boolean_true_node, NULL_TREE))))));
+
+ add_stmt (function_call);
+
+ ret_val = objc_property_temp_decl;
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ }
- /* PROPERTY_IVAR_NAME is always defined if we got here, and should
- be a valid instance variable. */
- ret_val = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
gcc_assert (ret_val);
#ifdef OBJCPLUS
finish_return_stmt (ret_val);
#else
- (void)c_finish_return (DECL_SOURCE_LOCATION (property), ret_val, NULL);
+ c_finish_return (location, ret_val, NULL_TREE);
#endif
- add_stmt (c_end_compound_stmt (DECL_SOURCE_LOCATION (property), body, true));
+ add_stmt (c_end_compound_stmt (location, body, true));
fn = current_function_decl;
#ifdef OBJCPLUS
finish_function ();
@@ -8578,8 +8814,10 @@ objc_synthesize_getter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
static void
objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
{
- tree fn, decl, lhs, rhs;
+ location_t location = DECL_SOURCE_LOCATION (property);
+ tree fn, decl;
tree body;
+ tree new_value, statement;
/* If user has implemented a setter with same name then do nothing. */
if (lookup_method (CLASS_NST_METHODS (objc_implementation_context),
@@ -8605,40 +8843,153 @@ objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
body = c_begin_compound_stmt (true);
- /* TODO: Implement PROPERTY_NONATOMIC, use objc_getProperty etc as
- appropriate. The following code just always does direct ivar
- access. */
-
- /* _property_name = _value; */
-
- /* PROPERTY_IVAR_NAME is always defined if we got here, and should
- be a valid instance variable. */
- lhs = objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property));
- gcc_assert (lhs);
-
- /* TODO: Lookup the argument in a more robust way so that it works
- even if the method prototype does not call it '_value'. */
- rhs = lookup_name (get_identifier ("_value"));
+ /* The 'new_value' is the only argument to the method, which is the
+ 3rd argument of the function, after self and _cmd. We use twice
+ TREE_CHAIN to move forward two arguments. */
+ new_value = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)));
/* This would presumably happen if the user has specified a
- prototype for the setter that is not the correct one. */
- if (rhs == NULL_TREE)
+ prototype for the setter that does not have an argument! */
+ if (new_value == NULL_TREE)
{
/* TODO: This should be caught much earlier than this. */
- /* We couldn't find the '_value' identifier in the current
- context; presumably the user didn't have a '_value'
- argument. */
- error_at (DECL_SOURCE_LOCATION (decl), "invalid setter, missing _value argument");
- /* Just recover somehow. */
- rhs = lhs;
- }
-
- /* FIXME: NULL types to get compile. */
- add_stmt (build_modify_expr (DECL_SOURCE_LOCATION (decl),
- lhs, NULL_TREE, NOP_EXPR,
- DECL_SOURCE_LOCATION (decl), rhs, NULL_TREE));
-
- add_stmt (c_end_compound_stmt (DECL_SOURCE_LOCATION (decl), body, true));
+ error_at (DECL_SOURCE_LOCATION (decl), "invalid setter, it must have one argument");
+ /* Try to recover somehow. */
+ new_value = error_mark_node;
+ }
+
+ /* Now we need to decide how we build the setter. There are three
+ cases:
+
+ for 'copy' or 'retain' properties we need to use the
+ objc_setProperty() accessor helper which knows about retain and
+ copy. It supports both 'nonatomic' and 'atomic' access.
+
+ for 'nonatomic, assign' properties we can access the instance
+ variable directly. 'nonatomic' means we don't have to use locks,
+ and 'assign' means we don't have to worry about retain or copy.
+ If you combine the two, it means we can just access the instance
+ variable directly.
+
+ for 'atomic, assign' properties we use objc_copyStruct() (for the
+ next runtime) or objc_setPropertyStruct() (for the GNU runtime). */
+ switch (PROPERTY_ASSIGN_SEMANTICS (property))
+ {
+ case OBJC_PROPERTY_RETAIN:
+ case OBJC_PROPERTY_COPY:
+ {
+ /* We build "objc_setProperty (self, _cmd, new_value, offset, is_atomic, should_copy);" */
+ tree cmd, ivar, offset, is_atomic, should_copy;
+ cmd = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
+
+ /* Find the ivar to compute the offset. */
+ ivar = lookup_ivar (klass, PROPERTY_IVAR_NAME (property));
+ if (!ivar || is_private (ivar))
+ {
+ error_at (location,
+ "can not find instance variable associated with property");
+ statement = error_mark_node;
+ break;
+ }
+ offset = byte_position (ivar);
+
+ if (PROPERTY_NONATOMIC (property))
+ is_atomic = boolean_false_node;
+ else
+ is_atomic = boolean_true_node;
+
+ if (PROPERTY_ASSIGN_SEMANTICS (property) == OBJC_PROPERTY_COPY)
+ should_copy = boolean_true_node;
+ else
+ should_copy = boolean_false_node;
+
+ statement = build_function_call
+ (location,
+ /* Function prototype. */
+ objc_setProperty_decl,
+ /* Parameters. */
+ tree_cons /* self */
+ (NULL_TREE, self_decl,
+ tree_cons /* _cmd */
+ (NULL_TREE, cmd,
+ tree_cons /* offset */
+ (NULL_TREE, offset,
+ tree_cons /* new_value */
+ (NULL_TREE, new_value,
+ tree_cons /* is_atomic */
+ (NULL_TREE, is_atomic,
+ tree_cons /* should_copy */
+ (NULL_TREE, should_copy, NULL_TREE)))))));
+ }
+ break;
+ case OBJC_PROPERTY_ASSIGN:
+ if (PROPERTY_NONATOMIC (property))
+ {
+ /* We build "self->PROPERTY_IVAR_NAME = new_value;" */
+ statement = build_modify_expr
+ (location,
+ objc_lookup_ivar (NULL_TREE, PROPERTY_IVAR_NAME (property)),
+ NULL_TREE, NOP_EXPR,
+ location, new_value, NULL_TREE);
+ break;
+ }
+ else
+ {
+ /* We build
+ objc_setPropertyStruct (&(self->PROPERTY_IVAR_NAME),
+ &new_value,
+ sizeof (type of self->PROPERTY_IVAR_NAME),
+ is_atomic,
+ false)
+
+ For the NeXT runtime, we need to use objc_copyStruct
+ instead of objc_getPropertyStruct. */
+ tree function_decl, size_of, is_atomic;
+
+ /* sizeof (ivar type). Since the ivar and the property have
+ the same type, there is no need to lookup the ivar. */
+ size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
+ true /* is_sizeof */,
+ false /* complain */);
+
+ if (PROPERTY_NONATOMIC (property))
+ is_atomic = boolean_false_node;
+ else
+ is_atomic = boolean_true_node;
+
+ if (flag_next_runtime)
+ function_decl = objc_copyStruct_decl;
+ else
+ function_decl = objc_setPropertyStruct_decl;
+
+ statement = build_function_call
+ (location,
+ /* Function prototype. */
+ function_decl,
+ /* Parameters. */
+ tree_cons /* &(self->PROPERTY_IVAR_NAME); */
+ (NULL_TREE, build_fold_addr_expr_loc (location,
+ objc_lookup_ivar
+ (NULL_TREE, PROPERTY_IVAR_NAME (property))),
+ tree_cons /* &new_value */
+ (NULL_TREE, build_fold_addr_expr_loc (location, new_value),
+ tree_cons /* sizeof (PROPERTY_IVAR) */
+ (NULL_TREE, size_of,
+ tree_cons /* is_atomic */
+ (NULL_TREE, is_atomic,
+ /* TODO: This is currently ignored by the GNU
+ runtime, but what about the next one ? */
+ tree_cons /* has_strong */
+ (NULL_TREE, boolean_true_node, NULL_TREE))))));
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ gcc_assert (statement);
+
+ add_stmt (statement);
+ add_stmt (c_end_compound_stmt (location, body, true));
fn = current_function_decl;
#ifdef OBJCPLUS
finish_function ();