diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-18 10:33:36 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-18 10:33:36 +0000 |
commit | 0f15bf2ebe4b001a06ab7869f0c7bcbb74b5469e (patch) | |
tree | 7393ac7f037f04ea997b60a08f0eba639c9798d6 /gcc/objc | |
parent | 80135bd9bbf06da9d0214ece3c59c301d3af3a2b (diff) | |
download | gcc-0f15bf2ebe4b001a06ab7869f0c7bcbb74b5469e.tar.gz |
2010-11-18 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 166897
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@166899 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/objc')
-rw-r--r-- | gcc/objc/ChangeLog | 119 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 1201 | ||||
-rw-r--r-- | gcc/objc/objc-act.h | 6 |
3 files changed, 1001 insertions, 325 deletions
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 9bde682663a..dd4814891a7 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,120 @@ +2010-11-17 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (lookup_method_in_protocol_list): Search methods in + PROTOCOL_OPTIONAL_CLS_METHODS / PROTOCOL_OPTIONAL_NST_METHODS if + they are not found in PROTOCOL_CLS_METHODS / PROTOCOL_NST_METHODS. + +2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (objc_build_setter_call): New. + (objc_maybe_build_modify_expr): Rewritten to build a compound + statement. + (objc_build_incr_expr_for_property_ref): Updated calls to + objc_maybe_build_modify_expr to call objc_build_setter_call + instead. Use build_modify_expr () instead of build2 (MODIFY_EXPR, + ...). Use convert () instead of build1 (NOP_EXPR, ...). Use + TREE_NO_WARNING on the final compound statement to silence C++ + warnings. + +2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (objc_build_incr_expr_for_property_ref): New. + (objc_create_temporary_var): Moved it towards the beginning of the + file so that objc_build_incr_expr_for_property_ref can use it. + +2010-11-14 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (objc_add_property_declaration): Check that the decl + we received from the parser is a FIELD_DECL; reject array and + bitfield properties. Convert the warning when a property is + readonly and a setter is specified into an error. Convert errors + when a property declaration does not match a property declaration + in a superclass into warnings. + (objc_add_synthesize_declaration_for_property): Use + DECL_BIT_FIELD_TYPE to determine the type of an instance variable + if it is a bitfield. Throw an error if we are asked to synthesize + setters/getters for a bitfield instance variable but the property + is not appropriate - it must be assign and nonatomic. If the + property is readonly, allow the instance variable type to be a + specialization of the property type. + (objc_type_valid_for_messaging): Fixed returning 'false' for a + Class qualified with a protocol when the 'accept_classes' argument + is 'false'. + +2010-11-13 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (objc_get_protocol_qualified_type): detect cases + where we are asked to attach a protocol to something which is not + an Objective-C object type, and produce an error. + +2010-11-11 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (objc_add_property_declaration): Check that the type + of a property and of an inherited property match. + (objc_maybe_build_component_ref): Tidied up indentation and + comments. + (objc_common_type): Added new type of check (-5). + (objc_add_synthesize_declaration_for_property): Check that the + property to synthesize and the instance variable to use have the + same type. + +2010-11-10 Joseph Myers <joseph@codesourcery.com> + + * objc-act.c (objc_init): Use %' in diagnostic. + (objc_set_method_opt): Remove trailing '.' from diagnostic. + +2010-11-10 Joseph Myers <joseph@codesourcery.com> + + * objc-act.c (dump_base_name): Don't declare here. + +2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (objc_add_dynamic_declaration_for_property): Do not + search for the @property declation only in the current context, + but also in inherited properties. Do not mark the original + PROPERTY_DECL in the @interface or @protocol with + PROPERTY_DYNAMIC. + (check_methods): To check if a method is associated with a + @dynamic property, search for the property in IMPL_PROPERTY_DECL. + (check_accessible_methods): Same change. + * objc-act.h: Updated comment. + +2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (objc_add_synthesize_declaration_for_property): + Iterate over IMPL_PROPERTY_DECL, not CLASS_PROPERTY_DECL, when + checking for an existing @synthesize or @dynamic declaration. + Search for an inherited @property declaration if none is found in + the local interface. If the required instance variable does not + exist, return instead of trying to continue to prevent a compiler + crash later. Check that the instance variable is not already + being used by another @synthesize. + (objc_add_dynamic_declaration_for_property): Iterate over + IMPL_PROPERTY_DECL, not CLASS_PROPERTY_DECL, when checking for an + existing @synthesize or @dynamic declaration. + (objc_synthesize_getter): Search for the getter declaration in + protocols and superclasses as well. + (objc_synthesize_setter): Search for the setter declaration in + protocols and superclasses as well. + +2010-11-08 Nicola Pero <nicola.pero@meta-innovation.com> + + * objc-act.c (lookup_property): When checking categories, also + check the protocols attached to each. + (objc_add_property_declaration): Determine the + PROPERTY_SETTER_NAME and PROPERTY_GETTER_NAME here. Tidied up + error message. Search for an existing property declaration with + the same name which would be inherited from the class hiearchy, + and produce an error if it has incompatible attributes. + (check_methods): Changed second parameter. If the method is a + getter or setter for a property, do not warn if it is inherited as + opposed to implemented directly in the class. + (check_protocol): Updated calls to check_methods. + (finish_class): Do not determine the PROPERTY_SETTER_NAME and + PROPERTY_GETTER_NAME here; this is now done earlier, in + objc_add_property_declaration. + * objc-act.h (CLASS_NAME, CLASS_SUPER_NAME): Added comments. + 2010-11-06 Nicola Pero <nicola.pero@meta-innovation.com> Fixed using the Objective-C 2.0 syntax with self and super. @@ -613,7 +730,7 @@ (objc_push_parm): Rebuild the PARM_DECL if its type has been decayed. -2010-09-28 Nicola Pero <nicola@nicola.brainstorm.co.uk> +2010-09-28 Nicola Pero <nicola.pero@meta-innovation.com> * objc-act.c (encode_type): Fixed encoding enums with the next runtime. diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index fd5244e389a..96a3998221a 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -414,9 +414,6 @@ static char *errbuf; /* Buffer for error diagnostics */ extern enum debug_info_type write_symbols; -/* Data imported from toplev.c. */ - -extern const char *dump_base_name; static int flag_typed_selectors; @@ -488,6 +485,33 @@ add_field_decl (tree type, const char *name, tree **chain) return field; } +/* Create a temporary variable of type 'type'. If 'name' is set, uses + the specified name, else use no name. Returns the declaration of + the type. The 'name' is mostly useful for debugging. +*/ +static tree +objc_create_temporary_var (tree type, const char *name) +{ + tree decl; + + if (name != NULL) + { + decl = build_decl (input_location, + VAR_DECL, get_identifier (name), type); + } + else + { + decl = build_decl (input_location, + VAR_DECL, NULL_TREE, type); + } + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + DECL_CONTEXT (decl) = current_function_decl; + + return decl; +} + /* Some platforms pass small structures through registers versus through an invisible pointer. Determine at what size structure is the transition point between the two possibilities. */ @@ -562,7 +586,7 @@ objc_init (void) register char * const dumpname = concat (dump_base_name, ".decl", NULL); gen_declaration_file = fopen (dumpname, "w"); if (gen_declaration_file == 0) - fatal_error ("can't open %s: %m", dumpname); + fatal_error ("can%'t open %s: %m", dumpname); free (dumpname); } @@ -625,30 +649,44 @@ static tree lookup_method_in_protocol_list (tree rproto_list, tree sel_name, int is_class) { - tree rproto, p; - tree fnd = 0; + tree rproto, p, m; for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) { - p = TREE_VALUE (rproto); + p = TREE_VALUE (rproto); + m = NULL_TREE; if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) { - if ((fnd = lookup_method (is_class - ? PROTOCOL_CLS_METHODS (p) - : PROTOCOL_NST_METHODS (p), sel_name))) - ; - else if (PROTOCOL_LIST (p)) - fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p), - sel_name, is_class); + /* First, search the @required protocol methods. */ + if (is_class) + m = lookup_method (PROTOCOL_CLS_METHODS (p), sel_name); + else + m = lookup_method (PROTOCOL_NST_METHODS (p), sel_name); + + if (m) + return m; + + /* If still not found, search the @optional protocol methods. */ + if (is_class) + m = lookup_method (PROTOCOL_OPTIONAL_CLS_METHODS (p), sel_name); + else + m = lookup_method (PROTOCOL_OPTIONAL_NST_METHODS (p), sel_name); + + if (m) + return m; + + /* If still not found, search the attached protocols. */ + if (PROTOCOL_LIST (p)) + m = lookup_method_in_protocol_list (PROTOCOL_LIST (p), + sel_name, is_class); + if (m) + return m; } else { ; /* An identifier...if we could not find a protocol. */ } - - if (fnd) - return fnd; } return 0; @@ -824,11 +862,83 @@ objc_set_method_opt (bool optional) if (!objc_interface_context || TREE_CODE (objc_interface_context) != PROTOCOL_INTERFACE_TYPE) { - error ("@optional/@required is allowed in @protocol context only."); + error ("@optional/@required is allowed in @protocol context only"); objc_method_optional_flag = false; } } +/* This routine looks for a given PROPERTY in a list of CLASS, CATEGORY, or + PROTOCOL. */ +static tree +lookup_property_in_list (tree chain, tree property) +{ + tree x; + for (x = CLASS_PROPERTY_DECL (chain); x; x = TREE_CHAIN (x)) + if (PROPERTY_NAME (x) == property) + return x; + return NULL_TREE; +} + +/* This routine looks for a given PROPERTY in the tree chain of RPROTO_LIST. */ +static tree lookup_property_in_protocol_list (tree rproto_list, tree property) +{ + tree rproto, x; + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) + { + tree p = TREE_VALUE (rproto); + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + { + if ((x = lookup_property_in_list (p, property))) + return x; + if (PROTOCOL_LIST (p)) + return lookup_property_in_protocol_list (PROTOCOL_LIST (p), property); + } + else + { + ; /* An identifier...if we could not find a protocol. */ + } + } + return NULL_TREE; +} + +/* This routine looks up the PROPERTY in current INTERFACE, its categories and up the + chain of interface hierarchy. */ +static tree +lookup_property (tree interface_type, tree property) +{ + tree inter = interface_type; + while (inter) + { + tree x, category; + if ((x = lookup_property_in_list (inter, property))) + return x; + /* Failing that, look for the property in each category of the class. */ + category = inter; + while ((category = CLASS_CATEGORY_LIST (category))) + { + if ((x = lookup_property_in_list (category, property))) + return x; + + /* When checking a category, also check the protocols + attached with the category itself. */ + if (CLASS_PROTOCOL_LIST (category) + && (x = lookup_property_in_protocol_list + (CLASS_PROTOCOL_LIST (category), property))) + return x; + } + + /* Failing to find in categories, look for property in protocol list. */ + if (CLASS_PROTOCOL_LIST (inter) + && (x = lookup_property_in_protocol_list + (CLASS_PROTOCOL_LIST (inter), property))) + return x; + + /* Failing that, climb up the inheritance hierarchy. */ + inter = lookup_interface (CLASS_SUPER_NAME (inter)); + } + return inter; +} + /* This routine is called by the parser when a @property... declaration is found. 'decl' is the declaration of the property (type/identifier), and the other arguments represent @@ -879,8 +989,7 @@ objc_add_property_declaration (location_t location, tree decl, if (parsed_property_readonly && parsed_property_setter_ident) { - /* Maybe this should be an error ? The Apple documentation says it is a warning. */ - warning_at (location, 0, "%<readonly%> attribute conflicts with %<setter%> attribute"); + error_at (location, "%<readonly%> attribute conflicts with %<setter%> attribute"); property_readonly = false; } @@ -920,29 +1029,43 @@ objc_add_property_declaration (location_t location, tree decl, /* At this point we know that we are either in an interface, a category, or a protocol. */ - if (parsed_property_setter_ident) + /* We expect a FIELD_DECL from the parser. Make sure we didn't get + something else, as that would confuse the checks below. */ + if (TREE_CODE (decl) != FIELD_DECL) { - /* The setter should be terminated by ':', but the parser only - gives us an identifier without ':'. So, we need to add ':' - at the end. */ - const char *parsed_setter = IDENTIFIER_POINTER (parsed_property_setter_ident); - size_t length = strlen (parsed_setter); - char *final_setter = (char *)alloca (length + 2); + error_at (location, "invalid property declaration"); + return; + } - sprintf (final_setter, "%s:", parsed_setter); - parsed_property_setter_ident = get_identifier (final_setter); + /* Do some spot-checks for the most obvious invalid types. */ + + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + { + error_at (location, "property can not be an array"); + return; } - /* Check that the property does not have an initial value specified. - This should never happen as the parser doesn't allow this, but - it's just in case. */ + /* The C++/ObjC++ parser seems to reject the ':' for a bitfield when + parsing, while the C/ObjC parser accepts it and gives us a + FIELD_DECL with a DECL_INITIAL set. So we use the DECL_INITIAL + to check for a bitfield when doing ObjC. */ +#ifndef OBJCPLUS if (DECL_INITIAL (decl)) { - error_at (location, "property can not have an initial value"); - return; + /* A @property is not an actual variable, but it is a way to + describe a pair of accessor methods, so its type (which is + the type of the return value of the getter and the first + argument of the setter) can't be a bitfield (as return values + and arguments of functions can not be bitfields). The + underlying instance variable could be a bitfield, but that is + a different matter. */ + error_at (location, "property can not be a bit-field"); + return; } +#endif - /* TODO: Check that the property type is an Objective-C object or a "POD". */ + /* TODO: Check that the property type is an Objective-C object or a + "POD". */ /* Implement -Wproperty-assign-default (which is enabled by default). */ if (warn_property_assign_default @@ -984,8 +1107,39 @@ objc_add_property_declaration (location_t location, tree decl, && !objc_type_valid_for_messaging (TREE_TYPE (decl), true)) error_at (location, "%<copy%> attribute is only valid for Objective-C objects"); + /* Now determine the final property getter and setter names. They + will be stored in the PROPERTY_DECL, from which they'll always be + extracted and used. */ + + /* Adjust, or fill in, setter and getter names. We overwrite the + parsed_property_setter_ident and parsed_property_getter_ident + with the final setter and getter identifiers that will be + used. */ + if (parsed_property_setter_ident) + { + /* The setter should be terminated by ':', but the parser only + gives us an identifier without ':'. So, we need to add ':' + at the end. */ + const char *parsed_setter = IDENTIFIER_POINTER (parsed_property_setter_ident); + size_t length = strlen (parsed_setter); + char *final_setter = (char *)alloca (length + 2); + + sprintf (final_setter, "%s:", parsed_setter); + parsed_property_setter_ident = get_identifier (final_setter); + } + else + { + if (!property_readonly) + parsed_property_setter_ident = get_identifier (objc_build_property_setter_name + (DECL_NAME (decl))); + } + + if (!parsed_property_getter_ident) + parsed_property_getter_ident = DECL_NAME (decl); + /* Check for duplicate property declarations. We first check the - immediate context for a property with the same name. */ + immediate context for a property with the same name. Any such + declarations are an error. */ for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) { if (PROPERTY_NAME (x) == DECL_NAME (decl)) @@ -995,14 +1149,150 @@ objc_add_property_declaration (location_t location, tree decl, error_at (location, "redeclaration of property %qD", decl); if (original_location != UNKNOWN_LOCATION) - inform (original_location, "originally declared here"); + inform (original_location, "originally specified here"); return; } } - /* TODO: Shall we check here for other property declaractions (in - the superclass, other categories or protocols) with the same name - and conflicting types ? */ + /* We now need to check for existing property declarations (in the + superclass, other categories or protocols) and check that the new + declaration is not in conflict with existing ones. */ + + /* Search for a previous, existing declaration of a property with + the same name in superclasses, protocols etc. If one is found, + it will be in the 'x' variable. */ + x = NULL_TREE; + + /* Note that, for simplicity, the following may search again the + local context. That's Ok as nothing will be found (else we'd + have thrown an error above); it's only a little inefficient, but + the code is simpler. */ + switch (TREE_CODE (objc_interface_context)) + { + case CLASS_INTERFACE_TYPE: + /* Look up the property in the current @interface (which will + find nothing), then its protocols and categories and + superclasses. */ + x = lookup_property (objc_interface_context, DECL_NAME (decl)); + break; + case CATEGORY_INTERFACE_TYPE: + /* Look up the property in the main @interface, then protocols + and categories (one of them is ours, and will find nothing) + and superclasses. */ + x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)), + DECL_NAME (decl)); + break; + case PROTOCOL_INTERFACE_TYPE: + /* Looks up the property in any protocols attached to the + current protocol. */ + if (PROTOCOL_LIST (objc_interface_context)) + { + x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context), + DECL_NAME (decl)); + } + break; + default: + gcc_unreachable (); + } + + if (x != NULL_TREE) + { + /* 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, + "'nonatomic' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + if (PROPERTY_GETTER_NAME (x) != parsed_property_getter_ident) + { + warning_at (location, 0, + "'getter' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + /* We can only compare the setter names if both the old and new property have a setter. */ + if (!property_readonly && !PROPERTY_READONLY(x)) + { + if (PROPERTY_SETTER_NAME (x) != parsed_property_setter_ident) + { + warning_at (location, 0, + "'setter' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + } + + if (PROPERTY_ASSIGN_SEMANTICS (x) != property_assign_semantics) + { + warning_at (location, 0, + "assign semantics attributes of property %qD conflict with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + /* It's ok to have a readonly property that becomes a readwrite, but not vice versa. */ + if (PROPERTY_READONLY (x) == 0 && property_readonly == 1) + { + warning_at (location, 0, + "'readonly' attribute of property %qD conflicts with previous declaration", decl); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + /* We now check that the new and old property declarations have + the same types (or compatible one). In the Objective-C + tradition of loose type checking, we do type-checking but + only generate warnings (not errors) if they do not match. + For non-readonly properties, the types must match exactly; + for readonly properties, it is allowed to use a "more + specialized" type in the new property declaration. Eg, the + superclass has a getter returning (NSArray *) and the + subclass a getter returning (NSMutableArray *). The object's + getter returns an (NSMutableArray *); but if you cast the + object to the superclass, which is allowed, you'd still + expect the getter to return an (NSArray *), which works since + an (NSMutableArray *) is an (NSArray *) too. So, the set of + objects belonging to the type of the new @property should be + a subset of the set of objects belonging to the type of the + old @property. This is what "specialization" means. And the + reason it only applies to readonly properties is that for a + readwrite property the setter would have the opposite + requirement - ie that the superclass type is more specialized + then the subclass one; hence the only way to satisfy both + constraints is that the types match. */ + + /* If the types are not the same in the C sense, we warn ... */ + if (!comptypes (TREE_TYPE (x), TREE_TYPE (decl)) + /* ... unless the property is readonly, in which case we + allow a new, more specialized, declaration. */ + && (!property_readonly + || !objc_compare_types (TREE_TYPE (x), + TREE_TYPE (decl), -5, NULL_TREE))) + { + warning_at (location, 0, + "type of property %qD conflicts with previous declaration", decl); + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + } /* Create a PROPERTY_DECL node. */ property_decl = make_node (PROPERTY_DECL); @@ -1022,74 +1312,18 @@ objc_add_property_declaration (location_t location, tree decl, PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (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 + with a getter or setter, we should get the PROPERTY_DECL and use + PROPERTY_GETTER_NAME and PROPERTY_SETTER_NAME to know the correct + names. */ + /* Add the PROPERTY_DECL to the list of properties for the class. */ TREE_CHAIN (property_decl) = CLASS_PROPERTY_DECL (objc_interface_context); CLASS_PROPERTY_DECL (objc_interface_context) = property_decl; } -/* This routine looks for a given PROPERTY in a list of CLASS, CATEGORY, or - PROTOCOL. */ -static tree -lookup_property_in_list (tree chain, tree property) -{ - tree x; - for (x = CLASS_PROPERTY_DECL (chain); x; x = TREE_CHAIN (x)) - if (PROPERTY_NAME (x) == property) - return x; - return NULL_TREE; -} - -/* This routine looks for a given PROPERTY in the tree chain of RPROTO_LIST. */ -static tree lookup_property_in_protocol_list (tree rproto_list, tree property) -{ - tree rproto, x; - for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) - { - tree p = TREE_VALUE (rproto); - if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) - { - if ((x = lookup_property_in_list (p, property))) - return x; - if (PROTOCOL_LIST (p)) - return lookup_property_in_protocol_list (PROTOCOL_LIST (p), property); - } - else - { - ; /* An identifier...if we could not find a protocol. */ - } - } - return NULL_TREE; -} - -/* This routine looks up the PROPERTY in current INTERFACE, its categories and up the - chain of interface hierarchy. */ -static tree -lookup_property (tree interface_type, tree property) -{ - tree inter = interface_type; - while (inter) - { - tree x, category; - if ((x = lookup_property_in_list (inter, property))) - return x; - /* Failing that, look for the property in each category of the class. */ - category = inter; - while ((category = CLASS_CATEGORY_LIST (category))) - if ((x = lookup_property_in_list (category, property))) - return x; - - /* Failing to find in categories, look for property in protocol list. */ - if (CLASS_PROTOCOL_LIST (inter) - && (x = lookup_property_in_protocol_list ( - CLASS_PROTOCOL_LIST (inter), property))) - return x; - - /* Failing that, climb up the inheritance hierarchy. */ - inter = lookup_interface (CLASS_SUPER_NAME (inter)); - } - return inter; -} - /* This is a subroutine of objc_maybe_build_component_ref. Search the list of methods in the interface (and, failing that, the local list in the implementation, and failing that, the protocol list) @@ -1295,19 +1529,17 @@ objc_maybe_build_component_ref (tree object, tree property_ident) t = TREE_OPERAND (t, 0); if (t == UOBJC_SUPER_decl) - interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template)); + { + /* TODO: Check if this is correct also for 'super' in categories. */ + interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template)); + } else if (t == self_decl) interface_type = lookup_interface (CLASS_NAME (implementation_template)); - /* TODO: Protocols. */ - if (interface_type) { if (TREE_CODE (objc_method_context) != CLASS_METHOD_DECL) - { - x = lookup_property (interface_type, property_ident); - /* TODO: Protocols. */ - } + x = lookup_property (interface_type, property_ident); if (x == NULL_TREE) { @@ -1322,8 +1554,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident) if (t == self_decl) implementation = objc_implementation_context; - /* TODO: Protocols. */ - x = maybe_make_artificial_property_decl (interface_type, implementation, NULL_TREE, property_ident, @@ -1398,8 +1628,6 @@ objc_maybe_build_component_ref (tree object, tree property_ident) } } - /* TODO: Fix compiling super.accessor. */ - if (x) { tree expression; @@ -1534,6 +1762,42 @@ objc_is_property_ref (tree node) return false; } +/* This function builds a setter call for a PROPERTY_REF (real, for a + declared property, or artificial, for a dot-syntax accessor which + is not corresponding to a property). 'lhs' must be a PROPERTY_REF + (the caller must check this beforehand). 'rhs' is the value to + assign to the property. A plain setter call is returned, or + error_mark_node if the property is readonly. */ + +static tree +objc_build_setter_call (tree lhs, tree rhs) +{ + tree object_expr = PROPERTY_REF_OBJECT (lhs); + tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs); + + if (PROPERTY_READONLY (property_decl)) + { + error ("readonly property can not be set"); + return error_mark_node; + } + else + { + tree setter_argument = build_tree_list (NULL_TREE, rhs); + tree setter; + + /* TODO: Check that the setter return type is 'void'. */ + + /* TODO: Decay arguments in C. */ + setter = objc_finish_message_expr (object_expr, + PROPERTY_SETTER_NAME (property_decl), + setter_argument); + return setter; + } + + /* Unreachable, but the compiler may not realize. */ + return error_mark_node; +} + /* This hook routine is called when a MODIFY_EXPR is being built. We check what is being modified; if it is a PROPERTY_REF, we need to generate a 'setter' function call for the property. If this is not @@ -1553,32 +1817,193 @@ objc_maybe_build_modify_expr (tree lhs, tree rhs) { if (lhs && TREE_CODE (lhs) == PROPERTY_REF) { - tree object_expr = PROPERTY_REF_OBJECT (lhs); - tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs); + /* Building a simple call to the setter method would work for cases such as - if (PROPERTY_READONLY (property_decl)) - { - error ("readonly property can not be set"); - return error_mark_node; - } - else - { - tree setter_argument = build_tree_list (NULL_TREE, rhs); - tree setter; + object.count = 1; - /* TODO: Check that the setter return type is 'void'. */ + but wouldn't work for cases such as - /* TODO: Decay argument in C. */ - setter = objc_finish_message_expr (object_expr, - PROPERTY_SETTER_NAME (property_decl), - setter_argument); - return setter; - } + count = object2.count = 1; + + to get these to work with very little effort, we build a + compound statement which does the setter call (to set the + property to 'rhs'), but which can also be evaluated returning + the 'rhs'. So, we want to create the following: + + (temp = rhs; [object setProperty: temp]; temp) + */ + tree temp_variable_decl, bind; + /* s1, s2 and s3 are the tree statements that we need in the + compound expression. */ + tree s1, s2, s3, compound_expr; + + /* TODO: If 'rhs' is a constant, we could maybe do without the + 'temp' variable ? */ + + /* Declare __objc_property_temp in a local bind. */ + temp_variable_decl = objc_create_temporary_var (TREE_TYPE (rhs), "__objc_property_temp"); + DECL_SOURCE_LOCATION (temp_variable_decl) = input_location; + bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL); + SET_EXPR_LOCATION (bind, input_location); + TREE_SIDE_EFFECTS (bind) = 1; + add_stmt (bind); + + /* Now build the compound statement. */ + + /* s1: __objc_property_temp = rhs */ + s1 = build_modify_expr (input_location, temp_variable_decl, NULL_TREE, + NOP_EXPR, + input_location, rhs, NULL_TREE); + SET_EXPR_LOCATION (s1, input_location); + + /* s2: [object setProperty: __objc_property_temp] */ + s2 = objc_build_setter_call (lhs, temp_variable_decl); + + /* This happens if building the setter failed because the property + is readonly. */ + if (s2 == error_mark_node) + return error_mark_node; + + SET_EXPR_LOCATION (s2, input_location); + + /* s3: __objc_property_temp */ + s3 = convert (TREE_TYPE (lhs), temp_variable_decl); + + /* Now build the compound statement (s1, s2, s3) */ + compound_expr = build_compound_expr (input_location, build_compound_expr (input_location, s1, s2), s3); + + /* Without this, with -Wall you get a 'valued computed is not + used' every time there is a "object.property = x" where the + value of the resulting MODIFY_EXPR is not used. That is + correct (maybe a more sophisticated implementation could + avoid generating the compound expression if not needed), but + we need to turn it off. */ + TREE_NO_WARNING (compound_expr) = 1; + return compound_expr; } else return NULL_TREE; } +/* This hook is called by the frontend when one of the four unary + expressions PREINCREMENT_EXPR, POSTINCREMENT_EXPR, + PREDECREMENT_EXPR and POSTDECREMENT_EXPR is being built with an + argument which is a PROPERTY_REF. For example, this happens if you have + + object.count++; + + where 'count' is a property. We need to use the 'getter' and + 'setter' for the property in an appropriate way to build the + appropriate expression. 'code' is the code for the expression (one + of the four mentioned above); 'argument' is the PROPERTY_REF, and + 'increment' is how much we need to add or subtract. */ +tree +objc_build_incr_expr_for_property_ref (location_t location, + enum tree_code code, + tree argument, tree increment) +{ + /* Here are the expressions that we want to build: + + For PREINCREMENT_EXPR / PREDECREMENT_EXPR: + (temp = [object property] +/- increment, [object setProperty: temp], temp) + + For POSTINCREMENT_EXPR / POSTECREMENT_EXPR: + (temp = [object property], [object setProperty: temp +/- increment], temp) */ + + tree temp_variable_decl, bind; + /* s1, s2 and s3 are the tree statements that we need in the + compound expression. */ + tree s1, s2, s3, compound_expr; + + /* Safety check. */ + if (!argument || TREE_CODE (argument) != PROPERTY_REF) + return error_mark_node; + + /* Declare __objc_property_temp in a local bind. */ + temp_variable_decl = objc_create_temporary_var (TREE_TYPE (argument), "__objc_property_temp"); + DECL_SOURCE_LOCATION (temp_variable_decl) = location; + bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL); + SET_EXPR_LOCATION (bind, location); + TREE_SIDE_EFFECTS (bind) = 1; + add_stmt (bind); + + /* Now build the compound statement. */ + + /* Note that the 'getter' is generated at gimplify time; at this + time, we can simply put the property_ref (ie, argument) wherever + we want the getter ultimately to be. */ + + /* s1: __objc_property_temp = [object property] <+/- increment> */ + switch (code) + { + case PREINCREMENT_EXPR: + /* __objc_property_temp = [object property] + increment */ + s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE, + NOP_EXPR, + location, build2 (PLUS_EXPR, TREE_TYPE (argument), + argument, increment), NULL_TREE); + break; + case PREDECREMENT_EXPR: + /* __objc_property_temp = [object property] - increment */ + s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE, + NOP_EXPR, + location, build2 (MINUS_EXPR, TREE_TYPE (argument), + argument, increment), NULL_TREE); + break; + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + /* __objc_property_temp = [object property] */ + s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE, + NOP_EXPR, + location, argument, NULL_TREE); + break; + default: + gcc_unreachable (); + } + + /* s2: [object setProperty: __objc_property_temp <+/- increment>] */ + switch (code) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + /* [object setProperty: __objc_property_temp] */ + s2 = objc_build_setter_call (argument, temp_variable_decl); + break; + case POSTINCREMENT_EXPR: + /* [object setProperty: __objc_property_temp + increment] */ + s2 = objc_build_setter_call (argument, + build2 (PLUS_EXPR, TREE_TYPE (argument), + temp_variable_decl, increment)); + break; + case POSTDECREMENT_EXPR: + /* [object setProperty: __objc_property_temp - increment] */ + s2 = objc_build_setter_call (argument, + build2 (MINUS_EXPR, TREE_TYPE (argument), + temp_variable_decl, increment)); + break; + default: + gcc_unreachable (); + } + + /* This happens if building the setter failed because the property + is readonly. */ + if (s2 == error_mark_node) + return error_mark_node; + + SET_EXPR_LOCATION (s2, location); + + /* s3: __objc_property_temp */ + s3 = convert (TREE_TYPE (argument), temp_variable_decl); + + /* Now build the compound statement (s1, s2, s3) */ + compound_expr = build_compound_expr (location, build_compound_expr (location, s1, s2), s3); + + /* Prevent C++ from warning with -Wall that "right operand of comma + operator has no effect". */ + TREE_NO_WARNING (compound_expr) = 1; + return compound_expr; +} + tree objc_build_method_signature (bool is_class_method, tree rettype, tree selector, tree optparms, bool ellipsis) @@ -1975,8 +2400,8 @@ objc_common_type (tree type1, tree type2) returning 'true', this routine may issue warnings related to, e.g., protocol conformance. When returning 'false', the routine must produce absolutely no warnings; the C or C++ front-end will do so - instead, if needed. If either LTYP or RTYP is not an Objective-C type, - the routine must return 'false'. + instead, if needed. If either LTYP or RTYP is not an Objective-C + type, the routine must return 'false'. The ARGNO parameter is encoded as follows: >= 1 Parameter number (CALLEE contains function being called); @@ -1984,8 +2409,11 @@ objc_common_type (tree type1, tree type2) -1 Assignment; -2 Initialization; -3 Comparison (LTYP and RTYP may match in either direction); - -4 Silent comparison (for C++ overload resolution). - */ + -4 Silent comparison (for C++ overload resolution); + -5 Silent "specialization" comparison for RTYP to be a "specialization" + of LTYP (a specialization means that RTYP is LTYP plus some constraints, + so that each object of type RTYP is also of type LTYP). This is used + when comparing property types. */ bool objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) @@ -2070,11 +2498,24 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE) rcls = NULL_TREE; - /* If either type is an unqualified 'id', we're done. */ - if ((!lproto && objc_is_object_id (ltyp)) - || (!rproto && objc_is_object_id (rtyp))) - return true; - + /* If either type is an unqualified 'id', we're done. This is because + an 'id' can be assigned to or from any type with no warnings. */ + if (argno != -5) + { + if ((!lproto && objc_is_object_id (ltyp)) + || (!rproto && objc_is_object_id (rtyp))) + return true; + } + else + { + /* For property checks, though, an 'id' is considered the most + general type of object, hence if you try to specialize an + 'NSArray *' (ltyp) property with an 'id' (rtyp) one, we need + to warn. */ + if (!lproto && objc_is_object_id (ltyp)) + return true; + } + pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp)); /* If the underlying types are the same, and at most one of them has @@ -2090,13 +2531,22 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) else { if (!pointers_compatible) - pointers_compatible - = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp)); + { + /* Again, if any of the two is an 'id', we're satisfied, + unless we're comparing properties, in which case only an + 'id' on the left-hand side (old property) is good + enough. */ + if (argno != -5) + pointers_compatible + = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp)); + else + pointers_compatible = objc_is_object_id (ltyp); + } if (!pointers_compatible) pointers_compatible = DERIVED_FROM_P (ltyp, rtyp); - if (!pointers_compatible && argno <= -3) + if (!pointers_compatible && (argno == -3 || argno == -4)) pointers_compatible = DERIVED_FROM_P (rtyp, ltyp); } @@ -2122,6 +2572,7 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) ObjC-specific. */ switch (argno) { + case -5: case -4: return false; @@ -2348,7 +2799,22 @@ objc_get_protocol_qualified_type (tree interface, tree protocols) : xref_tag (RECORD_TYPE, type)); } else - return interface; + { + /* This case happens when we are given an 'interface' which + is not a valid class name. For example if a typedef was + used, and 'interface' really is the identifier of the + typedef, but when you resolve it you don't get an + Objective-C class, but something else, such as 'int'. + This is an error; protocols make no sense unless you use + them with Objective-C objects. */ + error_at (input_location, "only Objective-C object types can be qualified with a protocol"); + + /* Try to recover. Ignore the invalid class name, and treat + the object as an 'id' to silence further warnings about + the class. */ + type = objc_object_type; + is_ptr = true; + } } if (protocols) @@ -4430,32 +4896,6 @@ get_class_ivars (tree interface, bool inherited) return ivar_chain; } -/* Create a temporary variable of type 'type'. If 'name' is set, uses - the specified name, else use no name. Returns the declaration of - the type. The 'name' is mostly useful for debugging. -*/ -static tree -objc_create_temporary_var (tree type, const char *name) -{ - tree decl; - - if (name != NULL) - { - decl = build_decl (input_location, - VAR_DECL, get_identifier (name), type); - } - else - { - decl = build_decl (input_location, - VAR_DECL, NULL_TREE, type); - } - TREE_USED (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - DECL_IGNORED_P (decl) = 1; - DECL_CONTEXT (decl) = current_function_decl; - - return decl; -} /* Exception handling constructs. We begin by having the parser do most of the work and passing us blocks. What we do next depends on whether @@ -8216,7 +8656,10 @@ objc_add_method (tree klass, tree method, int is_class, bool is_optional) { tree mth; - /* @optional methods are added to protocol's OPTIONAL list */ + /* @optional methods are added to protocol's OPTIONAL list. Note + that this disables checking that the methods are implemented by + classes implementing the protocol, since these checks only use + the CLASS_CLS_METHODS and CLASS_NST_METHODS. */ if (is_optional) { gcc_assert (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE); @@ -8564,20 +9007,44 @@ objc_is_public (tree expr, tree identifier) return 1; } -/* Make sure all entries in CHAIN are also in LIST. */ +/* Make sure all methods in CHAIN (a list of method declarations from + an @interface or a @protocol) are in IMPLEMENTATION (the + implementation context). This is used to check for example that + all methods declared in an @interface were implemented in an + @implementation. + + Some special methods (property setters/getters) are special and if + they are not found in IMPLEMENTATION, we look them up in its + superclasses. */ static int -check_methods (tree chain, tree list, int mtype) +check_methods (tree chain, tree implementation, int mtype) { int first = 1; + tree list; + + if (mtype == (int)'+') + list = CLASS_CLS_METHODS (implementation); + else + list = CLASS_NST_METHODS (implementation); while (chain) { /* If the method is associated with a dynamic property, then it is Ok not to have the method implementation, as it will be - generated dynamically at runtime. */ - tree property = METHOD_PROPERTY_CONTEXT (chain); - if (property != NULL_TREE && PROPERTY_DYNAMIC (property)) + generated dynamically at runtime. To decide if the method is + associated with a @dynamic property, we search the list of + @synthesize and @dynamic for this implementation, and look + for any @dynamic property with the same setter or getter name + as this method. */ + tree x; + for (x = IMPL_PROPERTY_DECL (implementation); x; x = TREE_CHAIN (x)) + if (PROPERTY_DYNAMIC (x) + && (PROPERTY_GETTER_NAME (x) == METHOD_SEL_NAME (chain) + || PROPERTY_SETTER_NAME (x) == METHOD_SEL_NAME (chain))) + break; + + if (x != NULL_TREE) { chain = TREE_CHAIN (chain); /* next method... */ continue; @@ -8585,17 +9052,67 @@ check_methods (tree chain, tree list, int mtype) if (!lookup_method (list, chain)) { + /* If the method is a property setter/getter, we'll still + allow it to be missing if it is implemented by + 'interface' or any of its superclasses. */ + tree property = METHOD_PROPERTY_CONTEXT (chain); + if (property) + { + /* Note that since this is a property getter/setter, it + is obviously an instance method. */ + tree interface = NULL_TREE; + + /* For a category, first check the main class + @interface. */ + if (TREE_CODE (implementation) == CATEGORY_IMPLEMENTATION_TYPE) + { + interface = lookup_interface (CLASS_NAME (implementation)); + + /* If the method is found in the main class, it's Ok. */ + if (lookup_method (CLASS_NST_METHODS (interface), chain)) + { + chain = DECL_CHAIN (chain); + continue; + } + + /* Else, get the superclass. */ + if (CLASS_SUPER_NAME (interface)) + interface = lookup_interface (CLASS_SUPER_NAME (interface)); + else + interface = NULL_TREE; + } + + /* Get the superclass for classes. */ + if (TREE_CODE (implementation) == CLASS_IMPLEMENTATION_TYPE) + { + if (CLASS_SUPER_NAME (implementation)) + interface = lookup_interface (CLASS_SUPER_NAME (implementation)); + else + interface = NULL_TREE; + } + + /* Now, interface is the superclass, if any; go check it. */ + if (interface) + { + if (lookup_method_static (interface, chain, 0)) + { + chain = DECL_CHAIN (chain); + continue; + } + } + /* Else, fall through - warn. */ + } if (first) { - switch (TREE_CODE (objc_implementation_context)) + switch (TREE_CODE (implementation)) { case CLASS_IMPLEMENTATION_TYPE: warning (0, "incomplete implementation of class %qE", - CLASS_NAME (objc_implementation_context)); + CLASS_NAME (implementation)); break; case CATEGORY_IMPLEMENTATION_TYPE: warning (0, "incomplete implementation of category %qE", - CLASS_SUPER_NAME (objc_implementation_context)); + CLASS_SUPER_NAME (implementation)); break; default: gcc_unreachable (); @@ -8652,13 +9169,21 @@ check_methods_accessible (tree chain, tree context, int mtype) { /* If the method is associated with a dynamic property, then it is Ok not to have the method implementation, as it will be - generated dynamically at runtime. */ - tree property = METHOD_PROPERTY_CONTEXT (chain); - if (property != NULL_TREE && PROPERTY_DYNAMIC (property)) + generated dynamically at runtime. Search for any @dynamic + property with the same setter or getter name as this + method. TODO: Use a hashtable lookup. */ + tree x; + for (x = IMPL_PROPERTY_DECL (base_context); x; x = TREE_CHAIN (x)) + if (PROPERTY_DYNAMIC (x) + && (PROPERTY_GETTER_NAME (x) == METHOD_SEL_NAME (chain) + || PROPERTY_SETTER_NAME (x) == METHOD_SEL_NAME (chain))) + break; + + if (x != NULL_TREE) { chain = TREE_CHAIN (chain); /* next method... */ continue; - } + } context = base_context; while (context) @@ -8733,10 +9258,10 @@ check_protocol (tree p, const char *type, tree name) if (warn_protocol) { f1 = check_methods (PROTOCOL_CLS_METHODS (p), - CLASS_CLS_METHODS (objc_implementation_context), + objc_implementation_context, '+'); f2 = check_methods (PROTOCOL_NST_METHODS (p), - CLASS_NST_METHODS (objc_implementation_context), + objc_implementation_context, '-'); } else @@ -9151,7 +9676,7 @@ lookup_ivar (tree interface, tree instance_variable_name) /* This routine synthesizes a 'getter' method. This is only called for @synthesize properties. */ static void -objc_synthesize_getter (tree klass, tree class_method, tree property) +objc_synthesize_getter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree property) { location_t location = DECL_SOURCE_LOCATION (property); tree fn, decl; @@ -9163,9 +9688,9 @@ objc_synthesize_getter (tree klass, tree class_method, tree property) PROPERTY_GETTER_NAME (property))) return; - /* Find declaration of the property getter in the interface. There - must be one. TODO: Search superclasses as well. */ - decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_GETTER_NAME (property)); + /* Find declaration of the property getter in the interface (or + superclass, or protocol). There must be one. */ + decl = lookup_method_static (klass, PROPERTY_GETTER_NAME (property), 0); /* If one not declared in the interface, this condition has already been reported as user error (because property was not declared in @@ -9330,7 +9855,7 @@ objc_synthesize_getter (tree klass, tree class_method, tree property) /* This routine synthesizes a 'setter' method. */ static void -objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property) +objc_synthesize_setter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree property) { location_t location = DECL_SOURCE_LOCATION (property); tree fn, decl; @@ -9342,9 +9867,9 @@ objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro PROPERTY_SETTER_NAME (property))) return; - /* Find declaration of the property setter in the interface. There - must be one. TODO: Search superclasses as well. */ - decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_SETTER_NAME (property)); + /* Find declaration of the property setter in the interface (or + superclass, or protocol). There must be one. */ + decl = lookup_method_static (klass, PROPERTY_SETTER_NAME (property), 0); /* If one not declared in the interface, this condition has already been reported as user error (because property was not declared in @@ -9524,10 +10049,11 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac { /* Find the @property declaration. */ tree property; + tree x; /* Check that synthesize or dynamic has not already been used for the same property. */ - for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property)) + for (property = IMPL_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property)) if (PROPERTY_NAME (property) == property_name) { location_t original_location = DECL_SOURCE_LOCATION (property); @@ -9544,12 +10070,9 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac return; } - /* Check that the property is declared in the interface. */ - /* TODO: This only check the immediate class; we need to check the - superclass (and categories ?) as well. */ - for (property = CLASS_PROPERTY_DECL (interface); property; property = TREE_CHAIN (property)) - if (PROPERTY_NAME (property) == property_name) - break; + /* Check that the property is declared in the interface. It could + also be declared in a superclass or protocol. */ + property = lookup_property (interface, property_name); if (!property) { @@ -9573,16 +10096,97 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac /* Check that the instance variable exists. You can only use an instance variable from the same class, not one from the - superclass. */ - if (!is_ivar (CLASS_IVARS (interface), ivar_name)) - error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar", - IDENTIFIER_POINTER (property_name)); + superclass (this makes sense as it allows us to check that an + instance variable is only used in one synthesized property). */ + { + tree ivar = is_ivar (CLASS_IVARS (interface), ivar_name); + tree type_of_ivar; + if (!ivar) + { + error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar", + IDENTIFIER_POINTER (property_name)); + return; + } + + if (DECL_BIT_FIELD_TYPE (ivar)) + type_of_ivar = DECL_BIT_FIELD_TYPE (ivar); + else + type_of_ivar = TREE_TYPE (ivar); + + /* If the instance variable has a different C type, we throw an error ... */ + if (!comptypes (TREE_TYPE (property), type_of_ivar) + /* ... unless the property is readonly, in which case we allow + the instance variable to be more specialized (this means we + can generate the getter all right and it works). */ + && (!PROPERTY_READONLY (property) + || !objc_compare_types (TREE_TYPE (property), + type_of_ivar, -5, NULL_TREE))) + { + location_t original_location = DECL_SOURCE_LOCATION (ivar); + + error_at (location, "property %qs is using instance variable %qs of incompatible type", + IDENTIFIER_POINTER (property_name), + IDENTIFIER_POINTER (ivar_name)); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + } - /* TODO: Check that the types of the instance variable and of the - property match. */ + /* If the instance variable is a bitfield, the property must be + 'assign', 'nonatomic' because the runtime getter/setter helper + do not work with bitfield instance variables. */ + if (DECL_BIT_FIELD_TYPE (ivar)) + { + /* If there is an error, we return and not generate any + getter/setter because trying to set up the runtime + getter/setter helper calls with bitfields is at high risk + of ICE. */ + + if (PROPERTY_ASSIGN_SEMANTICS (property) != OBJC_PROPERTY_ASSIGN) + { + location_t original_location = DECL_SOURCE_LOCATION (ivar); + + error_at (location, "'assign' property %qs is using bit-field instance variable %qs", + IDENTIFIER_POINTER (property_name), + IDENTIFIER_POINTER (ivar_name)); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + + if (!PROPERTY_NONATOMIC (property)) + { + location_t original_location = DECL_SOURCE_LOCATION (ivar); + + error_at (location, "'atomic' property %qs is using bit-field instance variable %qs", + IDENTIFIER_POINTER (property_name), + IDENTIFIER_POINTER (ivar_name)); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + return; + } + } + } - /* TODO: Check that no other property is using the same instance + /* Check that no other property is using the same instance variable. */ + for (x = IMPL_PROPERTY_DECL (objc_implementation_context); x; x = TREE_CHAIN (x)) + if (PROPERTY_IVAR_NAME (x) == ivar_name) + { + location_t original_location = DECL_SOURCE_LOCATION (x); + + error_at (location, "property %qs is using the same instance variable as property %qs", + IDENTIFIER_POINTER (property_name), + IDENTIFIER_POINTER (PROPERTY_NAME (x))); + + if (original_location != UNKNOWN_LOCATION) + inform (original_location, "originally specified here"); + + /* We keep going on. This won't cause the compiler to fail; + the failure would most likely be at runtime. */ + } /* Note that a @synthesize (and only a @synthesize) always sets PROPERTY_IVAR_NAME to a non-NULL_TREE. You can recognize a @@ -9664,7 +10268,7 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface, /* Check that synthesize or dynamic has not already been used for the same property. */ - for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property)) + for (property = IMPL_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property)) if (PROPERTY_NAME (property) == property_name) { location_t original_location = DECL_SOURCE_LOCATION (property); @@ -9681,11 +10285,9 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface, return; } - /* Check that the property is declared in the corresponding - interface. */ - for (property = CLASS_PROPERTY_DECL (interface); property; property = TREE_CHAIN (property)) - if (PROPERTY_NAME (property) == property_name) - break; + /* Check that the property is declared in the interface. It could + also be declared in a superclass or protocol. */ + property = lookup_property (interface, property_name); if (!property) { @@ -9695,16 +10297,6 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface, } else { - /* Mark the original PROPERTY_DECL as dynamic. The reason is - that the setter and getter methods in the interface have a - METHOD_PROPERTY_CONTEXT that points to the original - PROPERTY_DECL; when we check that these methods have been - implemented, we need to easily find that they are associated - with a dynamic property. TODO: Clean this up; maybe the - @property PROPERTY_DECL should contain a reference to the - @dynamic PROPERTY_DECL ? */ - PROPERTY_DYNAMIC (property) = 1; - /* We have to copy the property, because we want to chain it to the implementation context, and we want to store the source location of the @synthesize, not of the original @@ -9829,9 +10421,9 @@ finish_class (tree klass) { /* Ensure that all method listed in the interface contain bodies. */ check_methods (CLASS_CLS_METHODS (implementation_template), - CLASS_CLS_METHODS (objc_implementation_context), '+'); + objc_implementation_context, '+'); check_methods (CLASS_NST_METHODS (implementation_template), - CLASS_NST_METHODS (objc_implementation_context), '-'); + objc_implementation_context, '-'); if (CLASS_PROTOCOL_LIST (implementation_template)) check_protocols (CLASS_PROTOCOL_LIST (implementation_template), @@ -9848,12 +10440,12 @@ finish_class (tree klass) { /* Generate what needed for property; setters, getters, etc. */ objc_gen_property_data (implementation_template, category); - + /* Ensure all method listed in the interface contain bodies. */ check_methods (CLASS_CLS_METHODS (category), - CLASS_CLS_METHODS (objc_implementation_context), '+'); + objc_implementation_context, '+'); check_methods (CLASS_NST_METHODS (category), - CLASS_NST_METHODS (objc_implementation_context), '-'); + objc_implementation_context, '-'); if (CLASS_PROTOCOL_LIST (category)) check_protocols (CLASS_PROTOCOL_LIST (category), @@ -9870,104 +10462,69 @@ finish_class (tree klass) tree x; for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) { - /* Store the getter name that we used into the property. - It is used to generate the right getter calls; - moreover, when a @synthesize is processed, it copies - everything from the property, including the - PROPERTY_GETTER_NAME. We want to be sure that - @synthesize will get exactly the right - PROPERTY_GETTER_NAME. */ - if (PROPERTY_GETTER_NAME (x) == NULL_TREE) - PROPERTY_GETTER_NAME (x) = PROPERTY_NAME (x); - /* Now we check that the appropriate getter is declared, and if not, we declare one ourselves. */ - { - tree getter_decl = lookup_method (CLASS_NST_METHODS (klass), - PROPERTY_GETTER_NAME (x)); - - if (getter_decl) - { - /* TODO: Check that the declaration is consistent with the property. */ - ; - } - else - { - /* Generate an instance method declaration for the - getter; for example "- (id) name;". In general - it will be of the form - -(type)property_getter_name; */ - tree rettype = build_tree_list (NULL_TREE, TREE_TYPE (x)); - 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); - METHOD_PROPERTY_CONTEXT (getter_decl) = x; - } - } + tree getter_decl = lookup_method (CLASS_NST_METHODS (klass), + PROPERTY_GETTER_NAME (x)); + + if (getter_decl) + { + /* TODO: Check that the declaration is consistent with the property. */ + ; + } + else + { + /* Generate an instance method declaration for the + getter; for example "- (id) name;". In general it + will be of the form + -(type)property_getter_name; */ + tree rettype = build_tree_list (NULL_TREE, TREE_TYPE (x)); + 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); + METHOD_PROPERTY_CONTEXT (getter_decl) = x; + } if (PROPERTY_READONLY (x) == 0) { - /* Store the setter name that we used into the - property. It is used when generating setter calls; - moreover, when a @synthesize is processed, it - copies everything from the property, including the - PROPERTY_SETTER_NAME. We want to be sure that - @synthesize will get exactly the right - PROPERTY_SETTER_NAME. */ - if (PROPERTY_SETTER_NAME (x) == NULL_TREE) - PROPERTY_SETTER_NAME (x) = get_identifier (objc_build_property_setter_name - (PROPERTY_NAME (x))); - /* Now we check that the appropriate setter is declared, and if not, we declare on ourselves. */ - { - tree setter_decl = lookup_method (CLASS_NST_METHODS (klass), - PROPERTY_SETTER_NAME (x)); - - if (setter_decl) - { - /* TODO: Check that the declaration is consistent with the property. */ - ; - } - else - { - /* The setter name is something like 'setName:'. - We need the substring 'setName' to build the - method declaration due to how the declaration - works. TODO: build_method_decl() will then - generate back 'setName:' from 'setName'; it - would be more efficient to hook into - there. */ - const char *full_setter_name = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (x)); - size_t length = strlen (full_setter_name); - char *setter_name = (char *) alloca (length); - tree ret_type, selector, arg_type, arg_name; - - strcpy (setter_name, full_setter_name); - setter_name[length - 1] = '\0'; - ret_type = build_tree_list (NULL_TREE, void_type_node); - arg_type = build_tree_list (NULL_TREE, TREE_TYPE (x)); - arg_name = get_identifier ("_value"); - selector = objc_build_keyword_decl (get_identifier (setter_name), - arg_type, arg_name, NULL); - setter_decl = build_method_decl (INSTANCE_METHOD_DECL, - ret_type, selector, - build_tree_list (NULL_TREE, NULL_TREE), - false); - objc_add_method (objc_interface_context, setter_decl, false, false); - METHOD_PROPERTY_CONTEXT (setter_decl) = x; - } - } - - /* Note how at this point (once an @interface or @protocol - have been processed), 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 with a getter - or setter, we should get the PROPERTY_DECL and use - PROPERTY_GETTER_NAME and PROPERTY_SETTER_NAME to know - the correct names. */ + tree setter_decl = lookup_method (CLASS_NST_METHODS (klass), + PROPERTY_SETTER_NAME (x)); + + if (setter_decl) + { + /* TODO: Check that the declaration is consistent with the property. */ + ; + } + else + { + /* The setter name is something like 'setName:'. + We need the substring 'setName' to build the + method declaration due to how the declaration + works. TODO: build_method_decl() will then + generate back 'setName:' from 'setName'; it + would be more efficient to hook into there. */ + const char *full_setter_name = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (x)); + size_t length = strlen (full_setter_name); + char *setter_name = (char *) alloca (length); + tree ret_type, selector, arg_type, arg_name; + + strcpy (setter_name, full_setter_name); + setter_name[length - 1] = '\0'; + ret_type = build_tree_list (NULL_TREE, void_type_node); + arg_type = build_tree_list (NULL_TREE, TREE_TYPE (x)); + arg_name = get_identifier ("_value"); + selector = objc_build_keyword_decl (get_identifier (setter_name), + arg_type, arg_name, NULL); + setter_decl = build_method_decl (INSTANCE_METHOD_DECL, + ret_type, selector, + build_tree_list (NULL_TREE, NULL_TREE), + false); + objc_add_method (objc_interface_context, setter_decl, false, false); + METHOD_PROPERTY_CONTEXT (setter_decl) = x; + } } } break; @@ -12304,8 +12861,8 @@ objc_type_valid_for_messaging (tree type, bool accept_classes) if (objc_is_object_id (type)) return true; - if (accept_classes && objc_is_class_id (type)) - return true; + if (objc_is_class_id (type)) + return accept_classes; if (TYPE_HAS_OBJC_INFO (type)) return true; diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index 9a9cacd668f..276b33f5ec3 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -100,8 +100,7 @@ typedef enum objc_property_assign_semantics { #define PROPERTY_IVAR_NAME(DECL) ((DECL)->decl_common.initial) /* PROPERTY_DYNAMIC can be 0 or 1. This is 1 if the PROPERTY_DECL - represents a @dynamic (or if it is a @property for which a @dynamic - declaration has been parsed); otherwise, it is set to 0. */ + represents a @dynamic; 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 @@ -144,7 +143,10 @@ typedef enum objc_property_assign_semantics { /* CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE, CATEGORY_INTERFACE_TYPE, CATEGORY_IMPLEMENTATION_TYPE, PROTOCOL_INTERFACE_TYPE */ +/* CLASS_NAME is the name of the class. */ #define CLASS_NAME(CLASS) ((CLASS)->type.name) +/* CLASS_SUPER_NAME is the name of the superclass, or, in the case of + categories, it is the name of the category itself. */ #define CLASS_SUPER_NAME(CLASS) (TYPE_CHECK (CLASS)->type.context) #define CLASS_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 0) #define CLASS_RAW_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1) |