diff options
Diffstat (limited to 'gcc/objc')
-rw-r--r-- | gcc/objc/objc-act.c | 295 |
1 files changed, 179 insertions, 116 deletions
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index c0d07ae..26cdedd 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -804,119 +804,74 @@ lookup_property (tree interface_type, tree property) return inter; } +/* This routine returns a PROPERTY_KIND for the front end RID code supplied. */ + +enum objc_property_attribute_kind +objc_prop_attr_kind_for_rid (enum rid prop_rid) +{ + switch (prop_rid) + { + default: return OBJC_PROPERTY_ATTR_UNKNOWN; + case RID_GETTER: return OBJC_PROPERTY_ATTR_GETTER; + case RID_SETTER: return OBJC_PROPERTY_ATTR_SETTER; + + case RID_READONLY: return OBJC_PROPERTY_ATTR_READONLY; + case RID_READWRITE: return OBJC_PROPERTY_ATTR_READWRITE; + + case RID_ASSIGN: return OBJC_PROPERTY_ATTR_ASSIGN; + case RID_RETAIN: return OBJC_PROPERTY_ATTR_RETAIN; + case RID_COPY: return OBJC_PROPERTY_ATTR_COPY; + + case RID_NONATOMIC: return OBJC_PROPERTY_ATTR_NONATOMIC; + + } +} + /* 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 property attributes that may have been specified in the Objective-C declaration. 'parsed_property_readonly' is 'true' if the attribute 'readonly' was specified, and 'false' if not; similarly for the - other bool parameters. 'parsed_property_getter_ident' is NULL_TREE + other bool parameters. 'property_getter_ident' is NULL_TREE if the attribute 'getter' was not specified, and is the identifier corresponding to the specified getter if it was; similarly for - 'parsed_property_setter_ident'. */ + 'property_setter_ident'. */ void objc_add_property_declaration (location_t location, tree decl, - bool parsed_property_readonly, bool parsed_property_readwrite, - bool parsed_property_assign, bool parsed_property_retain, - bool parsed_property_copy, bool parsed_property_nonatomic, - tree parsed_property_getter_ident, tree parsed_property_setter_ident) + vec<property_attribute_info *>& prop_attr_list) { - tree property_decl; - tree x; - /* 'property_readonly' and 'property_assign_semantics' are the final - attributes of the property after all parsed attributes have been - considered (eg, if we parsed no 'readonly' and no 'readwrite', ie - parsed_property_readonly = false and parsed_property_readwrite = - false, then property_readonly will be false because the default - is readwrite). */ - bool property_readonly = false; - objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN; - bool property_extension_in_class_extension = false; - if (flag_objc1_only) - error_at (input_location, "%<@property%> is not available in Objective-C 1.0"); - - if (parsed_property_readonly && parsed_property_readwrite) - { - error_at (location, "%<readonly%> attribute conflicts with %<readwrite%> attribute"); - /* In case of conflicting attributes (here and below), after - producing an error, we pick one of the attributes and keep - going. */ - property_readonly = false; - } - else - { - if (parsed_property_readonly) - property_readonly = true; - - if (parsed_property_readwrite) - property_readonly = false; - } - - if (parsed_property_readonly && parsed_property_setter_ident) - { - error_at (location, "%<readonly%> attribute conflicts with %<setter%> attribute"); - property_readonly = false; - } - - if (parsed_property_assign && parsed_property_retain) - { - error_at (location, "%<assign%> attribute conflicts with %<retain%> attribute"); - property_assign_semantics = OBJC_PROPERTY_RETAIN; - } - else if (parsed_property_assign && parsed_property_copy) - { - error_at (location, "%<assign%> attribute conflicts with %<copy%> attribute"); - property_assign_semantics = OBJC_PROPERTY_COPY; - } - else if (parsed_property_retain && parsed_property_copy) - { - error_at (location, "%<retain%> attribute conflicts with %<copy%> attribute"); - property_assign_semantics = OBJC_PROPERTY_COPY; - } - else - { - if (parsed_property_assign) - property_assign_semantics = OBJC_PROPERTY_ASSIGN; - - if (parsed_property_retain) - property_assign_semantics = OBJC_PROPERTY_RETAIN; - - if (parsed_property_copy) - property_assign_semantics = OBJC_PROPERTY_COPY; - } + /* FIXME: we probably ought to bail out at this point. */ + error_at (location, "%<@property%> is not available in Objective-C 1.0"); + /* We must be in an interface, category, or protocol. */ if (!objc_interface_context) { - error_at (location, "property declaration not in @interface or @protocol context"); + error_at (location, "property declaration not in %<@interface%>," + " %<@protocol%> or %<category%> context"); return; } - /* At this point we know that we are either in an interface, a - category, or a protocol. */ + /* Do some spot-checks for the most obvious invalid cases. */ + + gcc_checking_assert (decl && TREE_CODE (decl) == FIELD_DECL); - /* 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) + if (decl && !DECL_NAME (decl)) { - error_at (location, "invalid property declaration"); + error_at (location, "properties must be named"); return; } - /* Do some spot-checks for the most obvious invalid types. */ - + location_t decl_loc = DECL_SOURCE_LOCATION (decl); + decl_loc = make_location (decl_loc, location, decl_loc); if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) { - error_at (location, "property cannot be an array"); + error_at (decl_loc, "property cannot be an array"); return; } - /* 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)) + if (DECL_C_BIT_FIELD (decl)) { /* A @property is not an actual variable, but it is a way to describe a pair of accessor methods, so its type (which is @@ -925,10 +880,110 @@ objc_add_property_declaration (location_t location, tree decl, and arguments of functions cannot be bitfields). The underlying instance variable could be a bitfield, but that is a different matter. */ - error_at (location, "property cannot be a bit-field"); + error_at (decl_loc, "property cannot be a bit-field"); return; } -#endif + + /* The final results of parsing the (growing number) of property + attributes. */ + property_attribute_info *attrs[OBJC_PROPATTR_GROUP_MAX] = { nullptr }; + + tree property_getter_ident = NULL_TREE; + tree property_setter_ident = NULL_TREE; + for (unsigned pn = 0; pn < prop_attr_list.length (); ++pn) + { + if (prop_attr_list[pn]->parse_error) + continue; /* Ignore attributes known to be wrongly parsed. */ + + switch (int g = (int) prop_attr_list[pn]->group()) + { + case OBJC_PROPATTR_GROUP_UNKNOWN: + continue; + case OBJC_PROPATTR_GROUP_SETTER: + case OBJC_PROPATTR_GROUP_GETTER: + if (attrs[g]) + { + warning_at (prop_attr_list[pn]->prop_loc, OPT_Wattributes, + "multiple property %qE methods specified, the latest" + " one will be used", attrs[g]->name); + inform (attrs[g]->prop_loc, "previous specification"); + } + attrs[g] = prop_attr_list[pn]; + if (g == OBJC_PROPATTR_GROUP_SETTER) + property_setter_ident = attrs[g]->ident; + else + property_getter_ident = attrs[g]->ident; + continue; + default: + { + if (!attrs[g]) + ; + else if (attrs[g]->prop_kind != prop_attr_list[pn]->prop_kind) + { + error_at (prop_attr_list[pn]->prop_loc, + "%qE attribute conflicts with %qE attribute", + prop_attr_list[pn]->name, attrs[g]->name); + inform (attrs[g]->prop_loc, "%qE specified here", + attrs[g]->name ); + } + else + { + warning_at (prop_attr_list[pn]->prop_loc, OPT_Wattributes, + "duplicate %qE attribute", attrs[g]->name); + inform (attrs[g]->prop_loc, "first specified here"); + } + attrs[g] = prop_attr_list[pn]; + } + continue; + } + } + + /* The defaults for atomicity (atomic) and write-ability (readwrite) apply + even if the user provides no specified attributes. */ + bool property_nonatomic = false; + bool property_readonly = false; + + /* Set the values from any specified by the user; these are easy, only two + states. */ + if (attrs[OBJC_PROPATTR_GROUP_ATOMIC]) + property_nonatomic = attrs[OBJC_PROPATTR_GROUP_ATOMIC]->prop_kind + == OBJC_PROPERTY_ATTR_NONATOMIC; + + if (attrs[OBJC_PROPATTR_GROUP_READWRITE]) + property_readonly = attrs[OBJC_PROPATTR_GROUP_READWRITE]->prop_kind + == OBJC_PROPERTY_ATTR_READONLY; + + /* One can't set a readonly value; we issue an error, but force the property + to readwrite as well. */ + if (property_readonly && property_setter_ident) + { + error_at (attrs[OBJC_PROPATTR_GROUP_READWRITE]->prop_loc, "%<readonly%>" + " attribute conflicts with %<setter%> attribute"); + gcc_checking_assert (attrs[OBJC_PROPATTR_GROUP_SETTER]); + inform (attrs[OBJC_PROPATTR_GROUP_SETTER]->prop_loc, "%<setter%>" + " specified here"); + property_readonly = false; + } + + /* Assign semantics is a tri-state property, and also needs some further + checking against the object type. */ + objc_property_assign_semantics property_assign_semantics + = OBJC_PROPERTY_ASSIGN; + + if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]) + { + if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind + == OBJC_PROPERTY_ATTR_ASSIGN) + property_assign_semantics = OBJC_PROPERTY_ASSIGN; + else if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind + == OBJC_PROPERTY_ATTR_RETAIN) + property_assign_semantics = OBJC_PROPERTY_RETAIN; + else if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind + == OBJC_PROPERTY_ATTR_COPY) + property_assign_semantics = OBJC_PROPERTY_COPY; + else + gcc_unreachable (); + } /* TODO: Check that the property type is an Objective-C object or a "POD". */ @@ -950,69 +1005,77 @@ objc_add_property_declaration (location_t location, tree decl, for non-{Objective-C objects}, and to 'retain' for Objective-C objects. But that would break compatibility with other compilers. */ - if (!parsed_property_assign && !parsed_property_retain && !parsed_property_copy) + if (!attrs[OBJC_PROPATTR_GROUP_ASSIGN]) { /* Use 'false' so we do not warn for Class objects. */ if (objc_type_valid_for_messaging (TREE_TYPE (decl), false)) { - warning_at (location, - 0, - "object property %qD has no %<assign%>, %<retain%> or %<copy%> attribute; assuming %<assign%>", - decl); - inform (location, - "%<assign%> can be unsafe for Objective-C objects; please state explicitly if you need it"); + warning_at (decl_loc, 0, "object property %qD has no %<assign%>," + " %<retain%> or %<copy%> attribute; assuming" + " %<assign%>", decl); + inform (decl_loc, "%<assign%> can be unsafe for Objective-C" + " objects; please state explicitly if you need it"); } } } - if (property_assign_semantics == OBJC_PROPERTY_RETAIN - && !objc_type_valid_for_messaging (TREE_TYPE (decl), true)) - error_at (location, "%<retain%> attribute is only valid for Objective-C objects"); + /* Some attributes make no sense unless applied to an Objective-C object. */ + bool prop_objc_object_p + = objc_type_valid_for_messaging (TREE_TYPE (decl), true); + if (!prop_objc_object_p) + { + tree p_name = NULL_TREE; + if (property_assign_semantics == OBJC_PROPERTY_RETAIN + || property_assign_semantics == OBJC_PROPERTY_COPY) + p_name = attrs[OBJC_PROPATTR_GROUP_ASSIGN]->name; - if (property_assign_semantics == OBJC_PROPERTY_COPY - && !objc_type_valid_for_messaging (TREE_TYPE (decl), true)) - error_at (location, "%<copy%> attribute is only valid for Objective-C objects"); + if (p_name) + error_at (decl_loc, "%qE attribute is only valid for Objective-C" + " objects", p_name); + } /* 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 + property_setter_ident and property_getter_ident with the final setter and getter identifiers that will be used. */ - if (parsed_property_setter_ident) + if (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); + const char *parsed_setter = IDENTIFIER_POINTER (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); + property_setter_ident = get_identifier (final_setter); } else { if (!property_readonly) - parsed_property_setter_ident = get_identifier (objc_build_property_setter_name + 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); + if (!property_getter_ident) + property_getter_ident = DECL_NAME (decl); /* Check for duplicate property declarations. We first check the immediate context for a property with the same name. Any such declarations are an error, unless this is a class extension and we are extending a property from readonly to readwrite. */ + bool property_extension_in_class_extension = false; + tree x = NULL_TREE; for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) { if (PROPERTY_NAME (x) == DECL_NAME (decl)) { if (objc_in_class_extension - && property_readonly == 0 + && !property_readonly && PROPERTY_READONLY (x) == 1) { /* This is a class extension, and we are extending an @@ -1087,7 +1150,7 @@ objc_add_property_declaration (location_t location, tree decl, types, or it is compatible. */ location_t original_location = DECL_SOURCE_LOCATION (x); - if (PROPERTY_NONATOMIC (x) != parsed_property_nonatomic) + if (PROPERTY_NONATOMIC (x) != property_nonatomic) { warning_at (location, 0, "%<nonatomic%> attribute of property %qD conflicts with " @@ -1098,7 +1161,7 @@ objc_add_property_declaration (location_t location, tree decl, return; } - if (PROPERTY_GETTER_NAME (x) != parsed_property_getter_ident) + if (PROPERTY_GETTER_NAME (x) != property_getter_ident) { warning_at (location, 0, "%<getter%> attribute of property %qD conflicts with " @@ -1112,7 +1175,7 @@ objc_add_property_declaration (location_t location, tree decl, /* 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) + if (PROPERTY_SETTER_NAME (x) != property_setter_ident) { warning_at (location, 0, "%<setter%> attribute of property %qD conflicts with " @@ -1190,13 +1253,13 @@ objc_add_property_declaration (location_t location, tree decl, if (property_extension_in_class_extension) { PROPERTY_READONLY (x) = 0; - PROPERTY_SETTER_NAME (x) = parsed_property_setter_ident; + PROPERTY_SETTER_NAME (x) = property_setter_ident; return; } } /* Create a PROPERTY_DECL node. */ - property_decl = make_node (PROPERTY_DECL); + tree property_decl = make_node (PROPERTY_DECL); /* Copy the basic information from the original decl. */ TREE_TYPE (property_decl) = TREE_TYPE (decl); @@ -1205,10 +1268,10 @@ objc_add_property_declaration (location_t location, tree decl, /* Add property-specific information. */ PROPERTY_NAME (property_decl) = DECL_NAME (decl); - PROPERTY_GETTER_NAME (property_decl) = parsed_property_getter_ident; - PROPERTY_SETTER_NAME (property_decl) = parsed_property_setter_ident; + PROPERTY_GETTER_NAME (property_decl) = property_getter_ident; + PROPERTY_SETTER_NAME (property_decl) = property_setter_ident; PROPERTY_READONLY (property_decl) = property_readonly; - PROPERTY_NONATOMIC (property_decl) = parsed_property_nonatomic; + PROPERTY_NONATOMIC (property_decl) = property_nonatomic; PROPERTY_ASSIGN_SEMANTICS (property_decl) = property_assign_semantics; PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (property_decl) = 0; |