#endif
#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "c-family/c-pragma.h"
#include "c-family/c-format.h"
#include "flags.h"
static unsigned int should_call_super_dealloc = 0;
-/* When building Objective-C++, we need in_late_binary_op. */
-#ifdef OBJCPLUS
-bool in_late_binary_op = false;
-#endif /* OBJCPLUS */
-
/* When building Objective-C++, we are not linking against the C front-end
and so need to replicate the C tree-construction functions in some way. */
#ifdef OBJCPLUS
static tree lookup_interface (tree);
static tree objc_add_static_instance (tree, tree);
-static tree start_class (enum tree_code, tree, tree, tree);
+static tree start_class (enum tree_code, tree, tree, tree, tree);
static tree continue_class (tree);
static void finish_class (tree);
static void start_method_def (tree);
#else
static void objc_start_function (tree, tree, tree, struct c_arg_info *);
#endif
-static tree start_protocol (enum tree_code, tree, tree);
+static tree start_protocol (enum tree_code, tree, tree, tree);
static tree build_method_decl (enum tree_code, tree, tree, tree, bool);
static tree objc_add_method (tree, tree, int, bool);
static tree add_instance_variable (tree, objc_ivar_visibility_kind, tree);
static tree add_objc_string (tree, enum string_section);
static void build_selector_table_decl (void);
-/* Protocol additions. */
+/* Protocols. */
-static tree lookup_protocol (tree);
-static tree lookup_and_install_protocols (tree);
+static tree lookup_protocol (tree, bool, bool);
+static tree lookup_and_install_protocols (tree, bool);
/* Type encoding. */
static int objc_collecting_ivars = 0;
+/* Flag that is set to 'true' while we are processing a class
+ extension. Since a class extension just "reopens" the main
+ @interface, this can be used to determine if we are in the main
+ @interface, or in a class extension. */
+static bool objc_in_class_extension = false;
+
#define BUFSIZE 1024
static char *errbuf; /* Buffer for error diagnostics */
-/* Data imported from tree.c. */
-
-extern enum debug_info_type write_symbols;
-
-/* Data imported from toplev.c. */
+/* An array of all the local variables in the current function that
+ need to be marked as volatile. */
+VEC(tree,gc) *local_variables_to_volatilize = NULL;
-extern const char *dump_base_name;
\f
static int flag_typed_selectors;
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. */
for (i = 31; i >= 0; i--)
if (!aggregate_in_mem[i])
break;
- printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n\n", i);
-
- /* The first member of the structure is always 0 because we don't handle
- structures with 0 members */
- printf ("static int struct_forward_array[] = {\n 0");
-
- for (j = 1; j <= i; j++)
- printf (", %d", aggregate_in_mem[j]);
- printf ("\n};\n");
+ printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n", i);
}
exit (0);
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);
}
if (print_struct_values && !flag_compare_debug)
generate_struct_by_value_array ();
+#ifndef OBJCPLUS
+ if (flag_objc_exceptions && !flag_objc_sjlj_exceptions)
+ using_eh_for_cleanups ();
+#endif
+
return true;
}
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;
objc_start_class_interface (tree klass, tree super_class,
tree protos, tree attributes)
{
- if (attributes)
- {
- if (flag_objc1_only)
- error_at (input_location, "class attributes are not available in Objective-C 1.0");
- else
- warning_at (input_location, OPT_Wattributes,
- "class attributes are not available in this version"
- " of the compiler, (ignored)");
- }
+ if (flag_objc1_only && attributes)
+ error_at (input_location, "class attributes are not available in Objective-C 1.0");
+
objc_interface_context
= objc_ivar_context
- = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos);
+ = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos, attributes);
objc_ivar_visibility = OBJC_IVAR_VIS_PROTECTED;
}
"category attributes are not available in this version"
" of the compiler, (ignored)");
}
+ if (categ == NULL_TREE)
+ {
+ if (flag_objc1_only)
+ error_at (input_location, "class extensions are not available in Objective-C 1.0");
+ else
+ {
+ /* Iterate over all the classes and categories implemented
+ up to now in this compilation unit. */
+ struct imp_entry *t;
+
+ for (t = imp_list; t; t = t->next)
+ {
+ /* If we find a class @implementation with the same name
+ as the one we are extending, produce an error. */
+ if (TREE_CODE (t->imp_context) == CLASS_IMPLEMENTATION_TYPE
+ && IDENTIFIER_POINTER (CLASS_NAME (t->imp_context)) == IDENTIFIER_POINTER (klass))
+ error_at (input_location,
+ "class extension for class %qE declared after its %<@implementation%>",
+ klass);
+ }
+ }
+ }
objc_interface_context
- = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos);
+ = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos, NULL_TREE);
objc_ivar_chain
= continue_class (objc_interface_context);
}
void
objc_start_protocol (tree name, tree protos, tree attributes)
{
- if (attributes)
- {
- if (flag_objc1_only)
- error_at (input_location, "protocol attributes are not available in Objective-C 1.0");
- else
- warning_at (input_location, OPT_Wattributes,
- "protocol attributes are not available in this version"
- " of the compiler, (ignored)");
- }
+ if (flag_objc1_only && attributes)
+ error_at (input_location, "protocol attributes are not available in Objective-C 1.0");
+
objc_interface_context
- = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos);
+ = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos, attributes);
objc_method_optional_flag = false;
}
finish_class (objc_interface_context);
objc_interface_context = NULL_TREE;
objc_method_optional_flag = false;
+ objc_in_class_extension = false;
}
void
{
objc_implementation_context
= objc_ivar_context
- = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE);
+ = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE,
+ NULL_TREE);
objc_ivar_visibility = OBJC_IVAR_VIS_PROTECTED;
}
objc_start_category_implementation (tree klass, tree categ)
{
objc_implementation_context
- = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE);
+ = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE,
+ NULL_TREE);
objc_ivar_chain
= continue_class (objc_implementation_context);
}
objc_set_method_opt (bool optional)
{
if (flag_objc1_only)
- error_at (input_location, "@optional/@required are not available in Objective-C 1.0");
+ {
+ if (optional)
+ error_at (input_location, "%<@optional%> is not available in Objective-C 1.0");
+ else
+ error_at (input_location, "%<@required%> is not available in Objective-C 1.0");
+ }
objc_method_optional_flag = optional;
if (!objc_interface_context
|| TREE_CODE (objc_interface_context) != PROTOCOL_INTERFACE_TYPE)
{
- error ("@optional/@required is allowed in @protocol context only.");
+ if (optional)
+ error ("%<@optional%> is allowed in @protocol context only");
+ else
+ error ("%<@required%> is allowed in @protocol context only");
objc_method_optional_flag = false;
}
}
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_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;
}
/* At this point we know that we are either in an interface, a
category, or a protocol. */
- /* 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. */
- if (DECL_INITIAL (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)
+ {
+ error_at (location, "invalid property declaration");
+ return;
+ }
+
+ /* Do some spot-checks for the most obvious invalid types. */
+
+ if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
{
- error_at (location, "property can not have an initial value");
+ error_at (location, "property can not be an array");
return;
}
- /* TODO: Check that the property type is an Objective-C object or a "POD". */
+ /* 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))
+ {
+ /* 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". */
/* Implement -Wproperty-assign-default (which is enabled by default). */
if (warn_property_assign_default
/* Check for duplicate property declarations. We first check the
immediate context for a property with the same name. Any such
- declarations are an error. */
+ declarations are an error, unless this is a class extension and
+ we are extending a property from readonly to readwrite. */
for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
{
if (PROPERTY_NAME (x) == DECL_NAME (decl))
{
- location_t original_location = DECL_SOURCE_LOCATION (x);
-
- error_at (location, "redeclaration of property %qD", decl);
-
- if (original_location != UNKNOWN_LOCATION)
- inform (original_location, "originally specified here");
- return;
- }
+ if (objc_in_class_extension
+ && property_readonly == 0
+ && PROPERTY_READONLY (x) == 1)
+ {
+ /* This is a class extension, and we are extending an
+ existing readonly property to a readwrite one.
+ That's fine. :-) */
+ property_extension_in_class_extension = true;
+ break;
+ }
+ else
+ {
+ location_t original_location = DECL_SOURCE_LOCATION (x);
+
+ error_at (location, "redeclaration of property %qD", decl);
+
+ if (original_location != UNKNOWN_LOCATION)
+ inform (original_location, "originally specified here");
+ return;
+ }
+ }
}
- /* 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. */
+ /* If x is not NULL_TREE, we must be in a class extension and we're
+ extending a readonly property. In that case, no point in
+ searching for another declaration. */
+ if (x == NULL_TREE)
+ {
+ /* 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;
+ /* 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. */
- /* 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))
+ /* 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))
{
- x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context),
- DECL_NAME (decl));
+ 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 ();
}
- 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)
{
- error_at (location, "'nonatomic' attribute of property %qD conflicts with previous declaration", decl);
+ 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");
if (PROPERTY_GETTER_NAME (x) != parsed_property_getter_ident)
{
- error_at (location, "'getter' attribute of property %qD conflicts with previous declaration", decl);
+ 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");
{
if (PROPERTY_SETTER_NAME (x) != parsed_property_setter_ident)
{
- error_at (location, "'setter' attribute of property %qD conflicts with previous declaration", decl);
+ 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");
if (PROPERTY_ASSIGN_SEMANTICS (x) != property_assign_semantics)
{
- error_at (location, "assign semantics attributes of property %qD conflict with previous declaration", decl);
+ 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");
/* It's ok to have a readonly property that becomes a readwrite, but not vice versa. */
if (PROPERTY_READONLY (x) == 0 && property_readonly == 1)
{
- error_at (location, "'readonly' attribute of property %qD conflicts with previous declaration", decl);
+ 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;
}
- if (property_readonly)
- {
- /* If the property is readonly, it is Ok if the property
- type is a specialization of the previously declared one.
- Eg, the superclass returns 'NSArray' while the subclass
- returns 'NSMutableArray'. */
-
- /* TODO: Check that the types are the same, or more specialized. */
- ;
+ /* 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;
}
- else
- {
- /* Else, the types must match exactly. */
- /* TODO: Check that property types are identical. */
- ;
+ /* If we are in a class extension and we're extending a readonly
+ property in the main @interface, we'll just update the
+ existing property with the readwrite flag and potentially the
+ new setter name. */
+ if (property_extension_in_class_extension)
+ {
+ PROPERTY_READONLY (x) = 0;
+ PROPERTY_SETTER_NAME (x) = parsed_property_setter_ident;
+ return;
}
}
PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
PROPERTY_DYNAMIC (property_decl) = 0;
+ /* Remember the fact that the property was found in the @optional
+ section in a @protocol, or not. */
+ if (objc_method_optional_flag)
+ PROPERTY_OPTIONAL (property_decl) = 1;
+ else
+ PROPERTY_OPTIONAL (property_decl) = 0;
+
/* Note that PROPERTY_GETTER_NAME is always set for all
PROPERTY_DECLs, and PROPERTY_SETTER_NAME is always set for all
PROPERTY_DECLs where PROPERTY_READONLY == 0. Any time we deal
in the implementation, and failing that, the protocol list)
provided for a 'setter' or 'getter' for 'component' with default
names (ie, if 'component' is "name", then search for "name" and
- "setName:"). If any is found, then create an artificial property
- that uses them. Return NULL_TREE if 'getter' or 'setter' could not
- be found. */
+ "setName:"). It is also possible to specify a different
+ 'getter_name' (this is used for @optional readonly properties). If
+ any is found, then create an artificial property that uses them.
+ Return NULL_TREE if 'getter' or 'setter' could not be found. */
static tree
maybe_make_artificial_property_decl (tree interface, tree implementation,
- tree protocol_list, tree component, bool is_class)
+ tree protocol_list, tree component, bool is_class,
+ tree getter_name)
{
- tree getter_name = component;
tree setter_name = get_identifier (objc_build_property_setter_name (component));
tree getter = NULL_TREE;
tree setter = NULL_TREE;
+ if (getter_name == NULL_TREE)
+ getter_name = component;
+
/* First, check the @interface and all superclasses. */
if (interface)
{
DECL_SOURCE_LOCATION (property_decl) = input_location;
TREE_DEPRECATED (property_decl) = 0;
DECL_ARTIFICIAL (property_decl) = 1;
-
+
/* Add property-specific information. Note that one of
PROPERTY_GETTER_NAME or PROPERTY_SETTER_NAME may refer to a
non-existing method; this will generate an error when the
PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0;
PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
PROPERTY_DYNAMIC (property_decl) = 0;
+ PROPERTY_OPTIONAL (property_decl) = 0;
if (!getter)
PROPERTY_HAS_NO_GETTER (property_decl) = 1;
properties. */
if (!IS_CLASS (rtype))
x = lookup_property_in_protocol_list (rprotos, property_ident);
-
+
if (x == NULL_TREE)
{
/* Ok, no property. Maybe it was an
NULL_TREE,
rprotos,
property_ident,
- IS_CLASS (rtype));
+ IS_CLASS (rtype),
+ NULL_TREE);
+ }
+ else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+ {
+ /* This is a special, complicated case. If the
+ property is optional, and is read-only, then the
+ property is always used for reading, but an
+ eventual existing non-property setter can be used
+ for writing. We create an artificial property
+ decl copying the getter from the optional
+ property, and looking up the setter in the
+ interface. */
+ x = maybe_make_artificial_property_decl (NULL_TREE,
+ NULL_TREE,
+ rprotos,
+ property_ident,
+ false,
+ PROPERTY_GETTER_NAME (x));
}
}
}
|| TREE_CODE (t) == COMPONENT_REF)
t = TREE_OPERAND (t, 0);
- if (t == UOBJC_SUPER_decl)
- {
- /* TODO: Check if this is correct also for 'super' in categories. */
- interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template));
- }
+ if (t == UOBJC_SUPER_decl)
+ 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)
{
if (t == self_decl)
implementation = objc_implementation_context;
- /* TODO: Protocols. */
-
x = maybe_make_artificial_property_decl
(interface_type, implementation, NULL_TREE,
property_ident,
- (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL));
+ (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL),
+ NULL_TREE);
+ }
+ else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+ {
+ tree implementation = NULL_TREE;
+
+ if (t == self_decl)
+ implementation = objc_implementation_context;
+
+ x = maybe_make_artificial_property_decl (interface_type,
+ implementation,
+ NULL_TREE,
+ property_ident,
+ false,
+ PROPERTY_GETTER_NAME (x));
}
}
}
implementation,
protocol_list,
property_ident,
- IS_CLASS (rtype));
+ IS_CLASS (rtype),
+ NULL_TREE);
}
+ else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+ {
+ tree implementation = NULL_TREE;
+
+ if (objc_implementation_context
+ && CLASS_NAME (objc_implementation_context)
+ == OBJC_TYPE_NAME (interface_type))
+ implementation = objc_implementation_context;
+
+ x = maybe_make_artificial_property_decl (interface_type,
+ implementation,
+ protocol_list,
+ property_ident,
+ false,
+ PROPERTY_GETTER_NAME (x));
+ }
}
}
}
- /* TODO: Fix compiling super.accessor. */
-
if (x)
{
tree expression;
tree getter_call;
+ tree deprecated_method_prototype = NULL_TREE;
/* We have an additional nasty problem here; if this
PROPERTY_REF needs to become a 'getter', then the conversion
if (PROPERTY_HAS_NO_GETTER (x))
getter_call = NULL_TREE;
else
- getter_call = objc_finish_message_expr (object,
- PROPERTY_GETTER_NAME (x),
- NULL_TREE);
-
- if (TREE_DEPRECATED (x))
- warn_deprecated_use (x, NULL_TREE);
-
- expression = build3 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call);
+ getter_call = objc_finish_message_expr
+ (object, PROPERTY_GETTER_NAME (x), NULL_TREE,
+ /* Disable the immediate deprecation warning if the getter
+ is deprecated, but record the fact that the getter is
+ deprecated by setting PROPERTY_REF_DEPRECATED_GETTER to
+ the method prototype. */
+ &deprecated_method_prototype);
+
+ expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
+ deprecated_method_prototype);
SET_EXPR_LOCATION (expression, input_location);
TREE_SIDE_EFFECTS (expression) = 1;
error_at (input_location, "could not find interface for class %qE", class_name);
return error_mark_node;
}
+ else
+ {
+ if (TREE_DEPRECATED (rtype))
+ warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", class_name);
+ }
x = maybe_make_artificial_property_decl (rtype, NULL_TREE, NULL_TREE,
property_ident,
- true);
+ true, NULL_TREE);
if (x)
{
tree expression;
tree getter_call;
+ tree deprecated_method_prototype = NULL_TREE;
if (PROPERTY_HAS_NO_GETTER (x))
getter_call = NULL_TREE;
else
- getter_call = objc_finish_message_expr (object,
- PROPERTY_GETTER_NAME (x),
- NULL_TREE);
- if (TREE_DEPRECATED (x))
- warn_deprecated_use (x, NULL_TREE);
+ getter_call = objc_finish_message_expr
+ (object, PROPERTY_GETTER_NAME (x), NULL_TREE,
+ &deprecated_method_prototype);
- expression = build3 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call);
+ expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
+ deprecated_method_prototype);
SET_EXPR_LOCATION (expression, input_location);
TREE_SIDE_EFFECTS (expression) = 1;
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, NULL);
+ 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
{
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)
fields = base;
}
- /* NB: Calling finish_struct() may cause type TYPE_LANG_SPECIFIC fields
- in all variants of this RECORD_TYPE to be clobbered, but it is therein
- that we store protocol conformance info (e.g., 'NSObject <MyProtocol>').
- Hence, we must squirrel away the ObjC-specific information before calling
+ /* NB: Calling finish_struct() may cause type TYPE_OBJC_INFO
+ information in all variants of this RECORD_TYPE to be destroyed
+ (this is because the C frontend manipulates TYPE_LANG_SPECIFIC
+ for something else and then will change all variants to use the
+ same resulting TYPE_LANG_SPECIFIC, ignoring the fact that we use
+ it for ObjC protocols and that such propagation will make all
+ variants use the same objc_info), but it is therein that we store
+ protocol conformance info (e.g., 'NSObject <MyProtocol>').
+ Hence, we must save the ObjC-specific information before calling
finish_struct(), and then reinstate it afterwards. */
- for (t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t))
+ for (t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t))
{
- if (!TYPE_HAS_OBJC_INFO (t))
- {
- INIT_TYPE_OBJC_INFO (t);
- TYPE_OBJC_INTERFACE (t) = klass;
- }
+ INIT_TYPE_OBJC_INFO (t);
VEC_safe_push (tree, heap, objc_info, TYPE_OBJC_INFO (t));
}
- /* Point the struct at its related Objective-C class. */
- INIT_TYPE_OBJC_INFO (s);
- TYPE_OBJC_INTERFACE (s) = klass;
-
s = objc_finish_struct (s, fields);
- for (i = 0, t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t), i++)
+ for (i = 0, t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t), i++)
{
+ /* We now want to restore the different TYPE_OBJC_INFO, but we
+ have the additional problem that the C frontend doesn't just
+ copy TYPE_LANG_SPECIFIC from one variant to the other; it
+ actually makes all of them the *same* TYPE_LANG_SPECIFIC. As
+ we need a different TYPE_OBJC_INFO for each (and
+ TYPE_OBJC_INFO is a field in TYPE_LANG_SPECIFIC), we need to
+ make a copy of each TYPE_LANG_SPECIFIC before we modify
+ TYPE_OBJC_INFO. */
+ if (TYPE_LANG_SPECIFIC (t))
+ {
+ /* Create a copy of TYPE_LANG_SPECIFIC. */
+ struct lang_type *old_lang_type = TYPE_LANG_SPECIFIC (t);
+ ALLOC_OBJC_TYPE_LANG_SPECIFIC (t);
+ memcpy (TYPE_LANG_SPECIFIC (t), old_lang_type,
+ SIZEOF_OBJC_TYPE_LANG_SPECIFIC);
+ }
+ else
+ {
+ /* Just create a new one. */
+ ALLOC_OBJC_TYPE_LANG_SPECIFIC (t);
+ }
+ /* Replace TYPE_OBJC_INFO with the saved one. This restores any
+ protocol information that may have been associated with the
+ type. */
TYPE_OBJC_INFO (t) = VEC_index (tree, objc_info, i);
- /* Replace the IDENTIFIER_NODE with an actual @interface. */
+ /* Replace the IDENTIFIER_NODE with an actual @interface now
+ that we have it. */
TYPE_OBJC_INTERFACE (t) = klass;
}
VEC_free (tree, heap, objc_info);
return s;
}
-/* Build a type differing from TYPE only in that TYPE_VOLATILE is set.
- Unlike tree.c:build_qualified_type(), preserve TYPE_LANG_SPECIFIC in the
- process. */
-static tree
-objc_build_volatilized_type (tree type)
-{
- tree t;
-
- /* Check if we have not constructed the desired variant already. */
- for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
- {
- /* The type qualifiers must (obviously) match up. */
- if (!TYPE_VOLATILE (t)
- || (TYPE_READONLY (t) != TYPE_READONLY (type))
- || (TYPE_RESTRICT (t) != TYPE_RESTRICT (type)))
- continue;
-
- /* For pointer types, the pointees (and hence their TYPE_LANG_SPECIFIC
- info, if any) must match up. */
- if (POINTER_TYPE_P (t)
- && (TREE_TYPE (t) != TREE_TYPE (type)))
- continue;
-
- /* Only match up the types which were previously volatilized in similar fashion and not
- because they were declared as such. */
- if (!lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (t)))
- continue;
-
- /* Everything matches up! */
- return t;
- }
-
- /* Ok, we could not re-use any of the pre-existing variants. Create
- a new one. */
- t = build_variant_type_copy (type);
- TYPE_VOLATILE (t) = 1;
-
- TYPE_ATTRIBUTES (t) = merge_attributes (TYPE_ATTRIBUTES (type),
- tree_cons (get_identifier ("objc_volatilized"),
- NULL_TREE,
- NULL_TREE));
- if (TREE_CODE (t) == ARRAY_TYPE)
- TREE_TYPE (t) = objc_build_volatilized_type (TREE_TYPE (t));
-
- /* Set up the canonical type information. */
- if (TYPE_STRUCTURAL_EQUALITY_P (type))
- SET_TYPE_STRUCTURAL_EQUALITY (t);
- else if (TYPE_CANONICAL (type) != type)
- TYPE_CANONICAL (t) = objc_build_volatilized_type (TYPE_CANONICAL (type));
- else
- TYPE_CANONICAL (t) = t;
-
- return t;
-}
-
/* Mark DECL as being 'volatile' for purposes of Darwin
_setjmp()/_longjmp() exception handling. Called from
objc_mark_locals_volatile(). */
&& (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL))
{
- tree t = TREE_TYPE (decl);
+ if (local_variables_to_volatilize == NULL)
+ local_variables_to_volatilize = VEC_alloc (tree, gc, 8);
- t = objc_build_volatilized_type (t);
+ VEC_safe_push (tree, gc, local_variables_to_volatilize, decl);
+ }
+}
- TREE_TYPE (decl) = t;
- TREE_THIS_VOLATILE (decl) = 1;
- TREE_SIDE_EFFECTS (decl) = 1;
- DECL_REGISTER (decl) = 0;
+/* Called when parsing of a function completes; if any local variables
+ in the function were marked as variables to volatilize, change them
+ to volatile. We do this at the end of the function when the
+ warnings about discarding 'volatile' have already been produced.
+ We are making the variables as volatile just to force the compiler
+ to preserve them between setjmp/longjmp, but we don't want warnings
+ for them as they aren't really volatile. */
+void
+objc_finish_function (void)
+{
+ /* If there are any local variables to volatilize, volatilize them. */
+ if (local_variables_to_volatilize)
+ {
+ int i;
+ tree decl;
+ FOR_EACH_VEC_ELT (tree, local_variables_to_volatilize, i, decl)
+ {
+ tree t = TREE_TYPE (decl);
+
+ t = build_qualified_type (t, TYPE_QUALS (t) | TYPE_QUAL_VOLATILE);
+ TREE_TYPE (decl) = t;
+ TREE_THIS_VOLATILE (decl) = 1;
+ TREE_SIDE_EFFECTS (decl) = 1;
+ DECL_REGISTER (decl) = 0;
#ifndef OBJCPLUS
- C_DECL_REGISTER (decl) = 0;
+ C_DECL_REGISTER (decl) = 0;
#endif
+ }
+
+ /* Now we delete the vector. This sets it to NULL as well. */
+ VEC_free (tree, gc, local_variables_to_volatilize);
}
}
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);
-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)
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
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);
}
ObjC-specific. */
switch (argno)
{
+ case -5:
case -4:
return false;
return false;
}
-/* Check if LTYP and RTYP have the same type qualifiers. If either type
- lives in the volatilized hash table, ignore the 'volatile' bit when
- making the comparison. */
-
-bool
-objc_type_quals_match (tree ltyp, tree rtyp)
-{
- int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp);
-
- if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (ltyp)))
- lquals &= ~TYPE_QUAL_VOLATILE;
-
- if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (rtyp)))
- rquals &= ~TYPE_QUAL_VOLATILE;
-
- return (lquals == rquals);
-}
-
#ifndef OBJCPLUS
/* Determine if CHILD is derived from PARENT. The routine assumes that
both parameters are RECORD_TYPEs, and is non-reflexive. */
error ("redeclaration of Objective-C class %qs", IDENTIFIER_POINTER (id));
}
-/* Return a non-volatalized version of TYPE. */
-
-tree
-objc_non_volatilized_type (tree type)
-{
- if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (type)))
- type = build_qualified_type (type, (TYPE_QUALS (type) & ~TYPE_QUAL_VOLATILE));
- return type;
-}
-
-/* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may
- either name an Objective-C class, or refer to the special 'id' or 'Class'
- types. If INTERFACE is not a valid ObjC type, just return it unchanged. */
+/* Construct a PROTOCOLS-qualified variant of INTERFACE, where
+ INTERFACE may either name an Objective-C class, or refer to the
+ special 'id' or 'Class' types. If INTERFACE is not a valid ObjC
+ type, just return it unchanged. This function is often called when
+ PROTOCOLS is NULL_TREE, in which case we simply look up the
+ appropriate INTERFACE. */
tree
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)
/* Look up protocols and install in lang specific list. */
DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type));
- TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols (protocols);
+ TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols
+ (protocols, /* definition_required */ false);
/* For RECORD_TYPEs, point to the @interface; for 'id' and 'Class',
return the pointer to the new pointee variant. */
tree pp = TREE_VALUE (p);
if (TREE_CODE (pp) == IDENTIFIER_NODE)
- pp = lookup_protocol (pp);
+ pp = lookup_protocol (pp, /* warn if deprecated */ false,
+ /* definition_required */ false);
if (pp == proto)
fatal_error ("protocol %qE has circular dependency",
}
}
-/* Look up PROTOCOLS, and return a list of those that are found.
- If none are found, return NULL. */
-
+/* Look up PROTOCOLS, and return a list of those that are found. If
+ none are found, return NULL. Note that this function will emit a
+ warning if a protocol is found and is deprecated. If
+ 'definition_required', then warn if the protocol is found but is
+ not defined (ie, if we only saw a forward-declaration of the
+ protocol (as in "@protocol NSObject;") not a real definition with
+ the list of methods). */
static tree
-lookup_and_install_protocols (tree protocols)
+lookup_and_install_protocols (tree protocols, bool definition_required)
{
tree proto;
tree return_value = NULL_TREE;
for (proto = protocols; proto; proto = TREE_CHAIN (proto))
{
tree ident = TREE_VALUE (proto);
- tree p = lookup_protocol (ident);
+ tree p = lookup_protocol (ident, /* warn_if_deprecated */ true,
+ definition_required);
if (p)
return_value = chainon (return_value,
/* Get a class reference, creating it if necessary. Also create the
reference variable. */
-
tree
objc_get_class_reference (tree ident)
{
record = xref_tag (RECORD_TYPE, ident);
INIT_TYPE_OBJC_INFO (record);
+ /* In the case of a @class declaration, we store the ident
+ in the TYPE_OBJC_INTERFACE. If later an @interface is
+ found, we'll replace the ident with the interface. */
TYPE_OBJC_INTERFACE (record) = ident;
hash_class_name_enter (cls_name_hash_list, ident, NULL_TREE);
}
tree result = NULL_TREE, outer;
int strong_cast_p = 0, outer_gc_p = 0, indirect_p = 0;
+ /* This function is currently only used with the next runtime with
+ garbage collection enabled (-fobjc-gc). */
+ gcc_assert (flag_next_runtime);
+
/* See if we have any lhs casts, and strip them out. NB: The lvalue casts
will have been transformed to the form '*(type *)&expr'. */
if (TREE_CODE (lhs) == INDIRECT_REF)
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;
-}
\f
/* 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
tree
objc_eh_runtime_type (tree type)
{
- return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
+ /* Use 'ErrorMarkNode' as class name when error_mark_node is found
+ to prevent an ICE. Note that we know that the compiler will
+ terminate with an error and this 'ErrorMarkNode' class name will
+ never be actually used. */
+ if (type == error_mark_node)
+ return add_objc_string (get_identifier ("ErrorMarkNode"), class_names);
+ else
+ return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
}
tree
objc_eh_personality (void)
{
if (!flag_objc_sjlj_exceptions && !objc_eh_personality_decl)
- objc_eh_personality_decl = build_personality_function ("gnu_objc");
+ objc_eh_personality_decl = build_personality_function
+ (flag_next_runtime
+ ? "objc"
+ : "gnu_objc");
return objc_eh_personality_decl;
}
-#endif
+#endif
+
+void
+objc_maybe_warn_exceptions (location_t loc)
+{
+ /* -fobjc-exceptions is required to enable Objective-C exceptions.
+ For example, on Darwin, ObjC exceptions require a sufficiently
+ recent version of the runtime, so the user must ask for them
+ explicitly. On other platforms, at the moment -fobjc-exceptions
+ triggers -fexceptions which again is required for exceptions to
+ work. */
+ if (!flag_objc_exceptions)
+ {
+ /* Warn only once per compilation unit. */
+ static bool warned = false;
+
+ if (!warned)
+ {
+ error_at (loc, "%<-fobjc-exceptions%> is required to enable Objective-C exception syntax");
+ warned = true;
+ }
+ }
+}
/* Build __builtin_eh_pointer, or the moral equivalent. In the case
of Darwin, we'll arrange for it to be initialized (and associated
t = build_fold_addr_expr_loc (input_location, t);
#ifdef OBJCPLUS
/* Convert _setjmp argument to type that is expected. */
- if (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl)))
+ if (prototype_p (TREE_TYPE (objc_setjmp_decl)))
t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t);
else
t = convert (ptr_type_node, t);
c->end_try_locus = input_location;
cur_try_context = c;
- /* -fobjc-exceptions is required to enable Objective-C exceptions.
- For example, on Darwin, ObjC exceptions require a sufficiently
- recent version of the runtime, so the user must ask for them
- explicitly. On other platforms, at the moment -fobjc-exceptions
- triggers -fexceptions which again is required for exceptions to
- work.
- */
- if (!flag_objc_exceptions)
- {
- error_at (try_locus, "%<-fobjc-exceptions%> is required to enable Objective-C exception syntax");
- }
-
+ /* Collect the list of local variables. We'll mark them as volatile
+ at the end of compilation of this function to prevent them being
+ clobbered by setjmp/longjmp. */
if (flag_objc_sjlj_exceptions)
objc_mark_locals_volatile (NULL);
}
/* Called just after parsing "@catch (parm)". Open a binding level,
enter DECL into the binding level, and initialize it. Leave the
- binding level open while the body of the compound statement is parsed. */
+ binding level open while the body of the compound statement is
+ parsed. If DECL is NULL_TREE, then we are compiling "@catch(...)"
+ which we compile as "@catch(id tmp_variable)". */
void
objc_begin_catch_clause (tree decl)
/* Begin a new scope that the entire catch clause will live in. */
compound = c_begin_compound_stmt (true);
- /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL. */
- decl = build_decl (input_location,
- VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
- lang_hooks.decls.pushdecl (decl);
+ /* Create the appropriate declaration for the argument. */
+ if (decl == error_mark_node)
+ type = error_mark_node;
+ else
+ {
+ if (decl == NULL_TREE)
+ {
+ /* If @catch(...) was specified, create a temporary variable of
+ type 'id' and use it. */
+ decl = objc_create_temporary_var (objc_object_type, "__objc_generic_catch_var");
+ DECL_SOURCE_LOCATION (decl) = input_location;
+ }
+ else
+ {
+ /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL. */
+ decl = build_decl (input_location,
+ VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+ }
+ lang_hooks.decls.pushdecl (decl);
- /* Since a decl is required here by syntax, don't warn if its unused. */
- /* ??? As opposed to __attribute__((unused))? Anyway, this appears to
- be what the previous objc implementation did. */
- TREE_USED (decl) = 1;
- DECL_READ_P (decl) = 1;
+ /* Mark the declaration as used so you never any warnings whether
+ you use the exception argument or not. TODO: Implement a
+ -Wunused-exception-parameter flag, which would cause warnings
+ if exception parameter is not used. */
+ TREE_USED (decl) = 1;
+ DECL_READ_P (decl) = 1;
- /* Verify that the type of the catch is valid. It must be a pointer
- to an Objective-C class, or "id" (which is catch-all). */
- type = TREE_TYPE (decl);
+ type = TREE_TYPE (decl);
+ }
- if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
- type = NULL;
- else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type)))
+ /* Verify that the type of the catch is valid. It must be a pointer
+ to an Objective-C class, or "id" (which is catch-all). */
+ if (type == error_mark_node)
+ {
+ ;/* Just keep going. */
+ }
+ else if (!objc_type_valid_for_messaging (type, false))
{
error ("@catch parameter is not a known Objective-C class type");
type = error_mark_node;
}
- else if (cur_try_context->catch_list)
+ else if (TYPE_HAS_OBJC_INFO (TREE_TYPE (type))
+ && TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (type)))
+ {
+ error ("@catch parameter can not be protocol-qualified");
+ type = error_mark_node;
+ }
+ else if (objc_is_object_id (TREE_TYPE (type)))
+ type = NULL;
+ else
{
- /* Examine previous @catch clauses and see if we've already
- caught the type in question. */
- tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
- for (; !tsi_end_p (i); tsi_next (&i))
+ /* If 'type' was built using typedefs, we need to get rid of
+ them and get a simple pointer to the class. */
+ bool is_typedef = false;
+ tree x = TYPE_MAIN_VARIANT (type);
+
+ /* Skip from the pointer to the pointee. */
+ if (TREE_CODE (x) == POINTER_TYPE)
+ x = TREE_TYPE (x);
+
+ /* Traverse typedef aliases */
+ while (TREE_CODE (x) == RECORD_TYPE && OBJC_TYPE_NAME (x)
+ && TREE_CODE (OBJC_TYPE_NAME (x)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x)))
+ {
+ is_typedef = true;
+ x = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x));
+ }
+
+ /* If it was a typedef, build a pointer to the final, original
+ class. */
+ if (is_typedef)
+ type = build_pointer_type (x);
+
+ if (cur_try_context->catch_list)
{
- tree stmt = tsi_stmt (i);
- t = CATCH_TYPES (stmt);
- if (t == error_mark_node)
- continue;
- if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+ /* Examine previous @catch clauses and see if we've already
+ caught the type in question. */
+ tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
+ for (; !tsi_end_p (i); tsi_next (&i))
{
- warning (0, "exception of type %<%T%> will be caught",
- TREE_TYPE (type));
- warning_at (EXPR_LOCATION (stmt), 0, " by earlier handler for %<%T%>",
- TREE_TYPE (t ? t : objc_object_type));
- break;
+ tree stmt = tsi_stmt (i);
+ t = CATCH_TYPES (stmt);
+ if (t == error_mark_node)
+ continue;
+ if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+ {
+ warning (0, "exception of type %<%T%> will be caught",
+ TREE_TYPE (type));
+ warning_at (EXPR_LOCATION (stmt), 0, " by earlier handler for %<%T%>",
+ TREE_TYPE (t ? t : objc_object_type));
+ break;
+ }
}
}
}
{
tree args;
- if (!flag_objc_exceptions)
- {
- error_at (loc, "%<-fobjc-exceptions%> is required to enable Objective-C exception syntax");
- }
+ objc_maybe_warn_exceptions (loc);
if (throw_expr == NULL)
{
|| cur_try_context->current_catch == NULL)
{
error_at (loc, "%<@throw%> (rethrow) used outside of a @catch block");
- return NULL_TREE;
+ return error_mark_node;
}
/* Otherwise the object is still sitting in the EXC_PTR_EXPR
value that we get from the runtime. */
throw_expr = objc_build_exc_ptr ();
}
+ else if (throw_expr != error_mark_node)
+ {
+ if (!objc_type_valid_for_messaging (TREE_TYPE (throw_expr), true))
+ {
+ error_at (loc, "%<@throw%> argument is not an object");
+ return error_mark_node;
+ }
+ }
/* A throw is just a call to the runtime throw function with the
object as a parameter. */
}
tree
-objc_build_synchronized (location_t start_locus, tree mutex, tree body)
+objc_build_synchronized (location_t start_locus, tree object_expr, tree body)
{
- tree args, call;
-
- /* First lock the mutex. */
- mutex = save_expr (mutex);
- args = tree_cons (NULL, mutex, NULL);
- call = build_function_call (input_location,
- objc_sync_enter_decl, args);
- SET_EXPR_LOCATION (call, start_locus);
- add_stmt (call);
+ /* object_expr should never be NULL; but in case it is, convert it to
+ error_mark_node. */
+ if (object_expr == NULL)
+ object_expr = error_mark_node;
- /* Build the mutex unlock. */
- args = tree_cons (NULL, mutex, NULL);
- call = build_function_call (input_location,
- objc_sync_exit_decl, args);
- SET_EXPR_LOCATION (call, input_location);
-
- /* Put the that and the body in a TRY_FINALLY. */
- objc_begin_try_stmt (start_locus, body);
- objc_build_finally_clause (input_location, call);
- return objc_finish_try_stmt ();
+ /* Validate object_expr. If not valid, set it to error_mark_node. */
+ if (object_expr != error_mark_node)
+ {
+ if (!objc_type_valid_for_messaging (TREE_TYPE (object_expr), true))
+ {
+ error_at (start_locus, "%<@synchronized%> argument is not an object");
+ object_expr = error_mark_node;
+ }
+ }
+
+ if (object_expr == error_mark_node)
+ {
+ /* If we found an error, we simply ignore the '@synchronized'.
+ Compile the body so we can keep going with minimal
+ casualties. */
+ return add_stmt (body);
+ }
+ else
+ {
+ tree call;
+ tree args;
+
+ /* objc_sync_enter (object_expr); */
+ object_expr = save_expr (object_expr);
+ args = tree_cons (NULL, object_expr, NULL);
+ call = build_function_call (input_location,
+ objc_sync_enter_decl, args);
+ SET_EXPR_LOCATION (call, start_locus);
+ add_stmt (call);
+
+ /* Build "objc_sync_exit (object_expr);" but do not add it yet;
+ it goes inside the @finalize() clause. */
+ args = tree_cons (NULL, object_expr, NULL);
+ call = build_function_call (input_location,
+ objc_sync_exit_decl, args);
+ SET_EXPR_LOCATION (call, input_location);
+
+ /* @try { body; } */
+ objc_begin_try_stmt (start_locus, body);
+
+ /* @finally { objc_sync_exit (object_expr); } */
+ objc_build_finally_clause (input_location, call);
+
+ /* End of try statement. */
+ return objc_finish_try_stmt ();
+ }
}
\f
can emit stabs for this struct type. */
if (flag_debug_only_used_symbols && TYPE_STUB_DECL (record))
TREE_USED (TYPE_STUB_DECL (record)) = 1;
+
+ /* Copy the attributes from the class to the type. */
+ if (TREE_DEPRECATED (klass))
+ TREE_DEPRECATED (record) = 1;
}
}
\f
/* If a type size is not known, bail out. */
if (sz < 0)
{
- error ("type %q+D does not have a known size",
- type);
+ error_at (DECL_SOURCE_LOCATION (method_decl),
+ "type %qT does not have a known size",
+ type);
/* Pretend that the encoding succeeded; the compilation will
fail nevertheless. */
goto finish_encoding;
method_params);
#endif
- return objc_finish_message_expr (receiver, sel_name, method_params);
+ return objc_finish_message_expr (receiver, sel_name, method_params, NULL);
}
/* Look up method SEL_NAME that would be suitable for receiver
/* The 'objc_finish_message_expr' routine is called from within
'objc_build_message_expr' for non-template functions. In the case of
C++ template functions, it is called from 'build_expr_from_tree'
- (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded. */
-
+ (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded.
+
+ If the DEPRECATED_METHOD_PROTOTYPE argument is NULL, then we warn
+ if the method being used is deprecated. If it is not NULL, instead
+ of deprecating, we set *DEPRECATED_METHOD_PROTOTYPE to the method
+ prototype that was used and is deprecated. This is useful for
+ getter calls that are always generated when compiling dot-syntax
+ expressions, even if they may not be used. In that case, we don't
+ want the warning immediately; we produce it (if needed) at gimplify
+ stage when we are sure that the deprecated getter is being
+ used. */
tree
-objc_finish_message_expr (tree receiver, tree sel_name, tree method_params)
+objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
+ tree *deprecated_method_prototype)
{
tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype;
tree selector, retval, class_tree;
is often used precisely to turn off warnings associated with
the object being of a particular class. */
if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE)
- warn_deprecated_use (method_prototype, NULL_TREE);
+ {
+ if (deprecated_method_prototype)
+ *deprecated_method_prototype = method_prototype;
+ else
+ warn_deprecated_use (method_prototype, NULL_TREE);
+ }
}
objc_build_protocol_expr (tree protoname)
{
tree expr;
- tree p = lookup_protocol (protoname);
+ tree p = lookup_protocol (protoname, /* warn if deprecated */ true,
+ /* definition_required */ false);
if (!p)
{
static tree
objc_add_method (tree klass, tree method, int is_class, bool is_optional)
{
- tree mth;
+ tree existing_method = NULL_TREE;
+
+ /* The first thing we do is look up the method in the list of
+ methods already defined in the interface (or implementation). */
+ if (is_class)
+ existing_method = lookup_method (CLASS_CLS_METHODS (klass), method);
+ else
+ existing_method = lookup_method (CLASS_NST_METHODS (klass), method);
+
+ /* In the case of protocols, we have a second list of methods to
+ consider, the list of optional ones. */
+ if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE)
+ {
+ /* @required methods are added to the protocol's normal list.
+ @optional methods are added to the protocol's OPTIONAL lists.
+ Note that adding the methods to the optional lists 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. */
+
+ /* First of all, if the method to add is @optional, and we found
+ it already existing as @required, emit an error. */
+ if (is_optional && existing_method)
+ {
+ error ("method %<%c%E%> declared %<@optional%> and %<@required%> at the same time",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (existing_method));
+ inform (DECL_SOURCE_LOCATION (existing_method),
+ "previous declaration of %<%c%E%> as %<@required%>",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (existing_method));
+ }
+
+ /* Now check the list of @optional methods if we didn't find the
+ method in the @required list. */
+ if (!existing_method)
+ {
+ if (is_class)
+ existing_method = lookup_method (PROTOCOL_OPTIONAL_CLS_METHODS (klass), method);
+ else
+ existing_method = lookup_method (PROTOCOL_OPTIONAL_NST_METHODS (klass), method);
+
+ if (!is_optional && existing_method)
+ {
+ error ("method %<%c%E%> declared %<@optional%> and %<@required%> at the same time",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (existing_method));
+ inform (DECL_SOURCE_LOCATION (existing_method),
+ "previous declaration of %<%c%E%> as %<@optional%>",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (existing_method));
+ }
+ }
+ }
- /* @optional methods are added to protocol's OPTIONAL list */
- if (is_optional)
+ /* If the method didn't exist already, add it. */
+ if (!existing_method)
{
- gcc_assert (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE);
- if (!(mth = lookup_method (is_class
- ? PROTOCOL_OPTIONAL_CLS_METHODS (klass)
- : PROTOCOL_OPTIONAL_NST_METHODS (klass),
- method)))
+ if (is_optional)
{
if (is_class)
{
+ /* Put the method on the list in reverse order. */
TREE_CHAIN (method) = PROTOCOL_OPTIONAL_CLS_METHODS (klass);
PROTOCOL_OPTIONAL_CLS_METHODS (klass) = method;
}
PROTOCOL_OPTIONAL_NST_METHODS (klass) = method;
}
}
- }
- else if (!(mth = lookup_method (is_class
- ? CLASS_CLS_METHODS (klass)
- : CLASS_NST_METHODS (klass), method)))
- {
- /* put method on list in reverse order */
- if (is_class)
- {
- DECL_CHAIN (method) = CLASS_CLS_METHODS (klass);
- CLASS_CLS_METHODS (klass) = method;
- }
else
{
- DECL_CHAIN (method) = CLASS_NST_METHODS (klass);
- CLASS_NST_METHODS (klass) = method;
+ if (is_class)
+ {
+ DECL_CHAIN (method) = CLASS_CLS_METHODS (klass);
+ CLASS_CLS_METHODS (klass) = method;
+ }
+ else
+ {
+ DECL_CHAIN (method) = CLASS_NST_METHODS (klass);
+ CLASS_NST_METHODS (klass) = method;
+ }
}
}
else
{
- /* When processing an @interface for a class or category, give hard
- errors on methods with identical selectors but differing argument
- and/or return types. We do not do this for @implementations, because
- C/C++ will do it for us (i.e., there will be duplicate function
- definition errors). */
+ /* The method was already defined. Check that the types match
+ for an @interface for a class or category, or for a
+ @protocol. Give hard errors on methods with identical
+ selectors but differing argument and/or return types. We do
+ not do this for @implementations, because C/C++ will do it
+ for us (i.e., there will be duplicate function definition
+ errors). */
if ((TREE_CODE (klass) == CLASS_INTERFACE_TYPE
- || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE)
- && !comp_proto_with_proto (method, mth, 1))
- error ("duplicate declaration of method %<%c%E%>",
- is_class ? '+' : '-',
- METHOD_SEL_NAME (mth));
+ || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE
+ /* Starting with GCC 4.6, we emit the same error for
+ protocols too. The situation is identical to
+ @interfaces as there is no possible meaningful reason
+ for defining the same method with different signatures
+ in the very same @protocol. If that was allowed,
+ whenever the protocol is used (both at compile and run
+ time) there wouldn't be any meaningful way to decide
+ which of the two method signatures should be used. */
+ || TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE)
+ && !comp_proto_with_proto (method, existing_method, 1))
+ {
+ error ("duplicate declaration of method %<%c%E%> with conflicting types",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (existing_method));
+ inform (DECL_SOURCE_LOCATION (existing_method),
+ "previous declaration of %<%c%E%>",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (existing_method));
+ }
}
if (is_class)
{
/* 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;
/* 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
{
/* 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)
}
}
\f
-/* Make sure that the class CLASS_NAME is defined
- CODE says which kind of thing CLASS_NAME ought to be.
- It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
- CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE. */
-
+/* Make sure that the class CLASS_NAME is defined CODE says which kind
+ of thing CLASS_NAME ought to be. It can be CLASS_INTERFACE_TYPE,
+ CLASS_IMPLEMENTATION_TYPE, CATEGORY_INTERFACE_TYPE, or
+ CATEGORY_IMPLEMENTATION_TYPE. For a CATEGORY_INTERFACE_TYPE,
+ SUPER_NAME is the name of the category. For a class extension,
+ CODE is CATEGORY_INTERFACE_TYPE and SUPER_NAME is NULL_TREE. */
static tree
start_class (enum tree_code code, tree class_name, tree super_name,
- tree protocol_list)
+ tree protocol_list, tree attributes)
{
- tree klass, decl;
+ tree klass = NULL_TREE;
+ tree decl;
#ifdef OBJCPLUS
- if (current_namespace != global_namespace) {
- error ("Objective-C declarations may only appear in global scope");
- }
+ if (current_namespace != global_namespace)
+ {
+ error ("Objective-C declarations may only appear in global scope");
+ }
#endif /* OBJCPLUS */
if (objc_implementation_context)
objc_implementation_context = NULL_TREE;
}
- klass = make_node (code);
- TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
+ /* If this is a class extension, we'll be "reopening" the existing
+ CLASS_INTERFACE_TYPE, so in that case there is no need to create
+ a new node. */
+ if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
+ {
+ klass = make_node (code);
+ TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
+ }
/* Check for existence of the super class, if one was specified. Note
that we must have seen an @interface, not just a @class. If we
&& super_name)
{
tree super = objc_is_class_name (super_name);
+ tree super_interface = NULL_TREE;
- if (!super || !lookup_interface (super))
+ if (super)
+ super_interface = lookup_interface (super);
+
+ if (!super_interface)
{
error ("cannot find interface declaration for %qE, superclass of %qE",
super ? super : super_name,
super_name = NULL_TREE;
}
else
- super_name = super;
+ {
+ if (TREE_DEPRECATED (super_interface))
+ warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
+ super);
+ super_name = super;
+ }
}
- CLASS_NAME (klass) = class_name;
- CLASS_SUPER_NAME (klass) = super_name;
- CLASS_CLS_METHODS (klass) = NULL_TREE;
+ if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
+ {
+ CLASS_NAME (klass) = class_name;
+ CLASS_SUPER_NAME (klass) = super_name;
+ CLASS_CLS_METHODS (klass) = NULL_TREE;
+ }
if (! objc_is_class_name (class_name)
&& (decl = lookup_name (class_name)))
{
error ("reimplementation of class %qE",
class_name);
- return error_mark_node;
+ /* TODO: error message saying where it was previously
+ implemented. */
+ break;
}
- implemented_classes = tree_cons (NULL_TREE, class_name,
- implemented_classes);
+ if (chain == NULL_TREE)
+ implemented_classes = tree_cons (NULL_TREE, class_name,
+ implemented_classes);
}
/* Reset for multiple classes per file. */
if (protocol_list)
CLASS_PROTOCOL_LIST (klass)
- = lookup_and_install_protocols (protocol_list);
+ = lookup_and_install_protocols (protocol_list, /* definition_required */ true);
+
+ /* Determine if 'deprecated', the only attribute we recognize
+ for classes, was used. Ignore all other attributes for now,
+ but store them in the klass. */
+ if (attributes)
+ {
+ tree attribute;
+ for (attribute = attributes; attribute; attribute = TREE_CHAIN (attribute))
+ {
+ tree name = TREE_PURPOSE (attribute);
+
+ if (is_attribute_p ("deprecated", name))
+ TREE_DEPRECATED (klass) = 1;
+ else
+ warning (OPT_Wattributes, "%qE attribute directive ignored", name);
+ }
+ TYPE_ATTRIBUTES (klass) = attributes;
+ }
break;
case CATEGORY_INTERFACE_TYPE:
exit (FATAL_EXIT_CODE);
}
else
- add_category (class_category_is_assoc_with, klass);
-
- if (protocol_list)
- CLASS_PROTOCOL_LIST (klass)
- = lookup_and_install_protocols (protocol_list);
+ {
+ if (TREE_DEPRECATED (class_category_is_assoc_with))
+ warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
+ class_name);
+
+ if (super_name == NULL_TREE)
+ {
+ /* This is a class extension. Get the original
+ interface, and continue working on it. */
+ objc_in_class_extension = true;
+ klass = class_category_is_assoc_with;
+
+ if (protocol_list)
+ {
+ /* Append protocols to the original protocol
+ list. */
+ CLASS_PROTOCOL_LIST (klass)
+ = chainon (CLASS_PROTOCOL_LIST (klass),
+ lookup_and_install_protocols
+ (protocol_list,
+ /* definition_required */ true));
+ }
+ }
+ else
+ {
+ add_category (class_category_is_assoc_with, klass);
+
+ if (protocol_list)
+ CLASS_PROTOCOL_LIST (klass)
+ = lookup_and_install_protocols
+ (protocol_list, /* definition_required */ true);
+ }
+ }
}
break;
-
+
case CATEGORY_IMPLEMENTATION_TYPE:
/* Reset for multiple classes per file. */
method_slot = 0;
}
case CLASS_INTERFACE_TYPE:
{
+ if (objc_in_class_extension)
+ return NULL_TREE;
#ifdef OBJCPLUS
push_lang_context (lang_name_c);
#endif /* OBJCPLUS */
/* 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;
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
/* 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;
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
{
/* 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);
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)
{
/* 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");
+ }
+
+ /* 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;
+ }
- /* TODO: Check that the types of the instance variable and of the
- property match. */
+ 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
/* 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);
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)
{
}
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
getter_decl = build_method_decl (INSTANCE_METHOD_DECL,
rettype, PROPERTY_GETTER_NAME (x),
NULL_TREE, false);
- objc_add_method (objc_interface_context, getter_decl, false, false);
+ if (PROPERTY_OPTIONAL (x))
+ objc_add_method (objc_interface_context, getter_decl, false, true);
+ else
+ objc_add_method (objc_interface_context, getter_decl, false, false);
+ TREE_DEPRECATED (getter_decl) = TREE_DEPRECATED (x);
METHOD_PROPERTY_CONTEXT (getter_decl) = x;
}
ret_type, selector,
build_tree_list (NULL_TREE, NULL_TREE),
false);
- objc_add_method (objc_interface_context, setter_decl, false, false);
+ if (PROPERTY_OPTIONAL (x))
+ objc_add_method (objc_interface_context, setter_decl, false, true);
+ else
+ objc_add_method (objc_interface_context, setter_decl, false, false);
+ TREE_DEPRECATED (setter_decl) = TREE_DEPRECATED (x);
METHOD_PROPERTY_CONTEXT (setter_decl) = x;
}
}
return protocol_chain;
}
+/* Check that a protocol is defined, and, recursively, that all
+ protocols that this protocol conforms to are defined too. */
+static void
+check_that_protocol_is_defined (tree protocol)
+{
+ if (!PROTOCOL_DEFINED (protocol))
+ warning (0, "definition of protocol %qE not found",
+ PROTOCOL_NAME (protocol));
+
+ /* If the protocol itself conforms to other protocols, check them
+ too, recursively. */
+ if (PROTOCOL_LIST (protocol))
+ {
+ tree p;
+
+ for (p = PROTOCOL_LIST (protocol); p; p = TREE_CHAIN (p))
+ check_that_protocol_is_defined (TREE_VALUE (p));
+ }
+}
+
+/* Looks up a protocol. If 'warn_if_deprecated' is true, a warning is
+ emitted if the protocol is deprecated. If 'definition_required' is
+ true, a warning is emitted if a full @protocol definition has not
+ been seen. */
static tree
-lookup_protocol (tree ident)
+lookup_protocol (tree ident, bool warn_if_deprecated, bool definition_required)
{
tree chain;
for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
if (ident == PROTOCOL_NAME (chain))
- return chain;
+ {
+ if (warn_if_deprecated && TREE_DEPRECATED (chain))
+ {
+ /* It would be nice to use warn_deprecated_use() here, but
+ we are using TREE_CHAIN (which is supposed to be the
+ TYPE_STUB_DECL for a TYPE) for something different. */
+ warning (OPT_Wdeprecated_declarations, "protocol %qE is deprecated",
+ PROTOCOL_NAME (chain));
+ }
+
+ if (definition_required)
+ check_that_protocol_is_defined (chain);
+
+ return chain;
+ }
return NULL_TREE;
}
they are already declared or defined, the function has no effect. */
void
-objc_declare_protocols (tree names)
+objc_declare_protocols (tree names, tree attributes)
{
tree list;
+ bool deprecated = false;
#ifdef OBJCPLUS
if (current_namespace != global_namespace) {
}
#endif /* OBJCPLUS */
+ /* Determine if 'deprecated', the only attribute we recognize for
+ protocols, was used. Ignore all other attributes. */
+ if (attributes)
+ {
+ tree attribute;
+ for (attribute = attributes; attribute; attribute = TREE_CHAIN (attribute))
+ {
+ tree name = TREE_PURPOSE (attribute);
+
+ if (is_attribute_p ("deprecated", name))
+ deprecated = true;
+ else
+ warning (OPT_Wattributes, "%qE attribute directive ignored", name);
+ }
+ }
+
for (list = names; list; list = TREE_CHAIN (list))
{
tree name = TREE_VALUE (list);
- if (lookup_protocol (name) == NULL_TREE)
+ if (lookup_protocol (name, /* warn if deprecated */ false,
+ /* definition_required */ false) == NULL_TREE)
{
tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
add_protocol (protocol);
PROTOCOL_DEFINED (protocol) = 0;
PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
+
+ if (attributes)
+ {
+ TYPE_ATTRIBUTES (protocol) = attributes;
+ if (deprecated)
+ TREE_DEPRECATED (protocol) = 1;
+ }
}
}
}
static tree
-start_protocol (enum tree_code code, tree name, tree list)
+start_protocol (enum tree_code code, tree name, tree list, tree attributes)
{
tree protocol;
+ bool deprecated = false;
#ifdef OBJCPLUS
if (current_namespace != global_namespace) {
}
#endif /* OBJCPLUS */
- protocol = lookup_protocol (name);
+ /* Determine if 'deprecated', the only attribute we recognize for
+ protocols, was used. Ignore all other attributes. */
+ if (attributes)
+ {
+ tree attribute;
+ for (attribute = attributes; attribute; attribute = TREE_CHAIN (attribute))
+ {
+ tree name = TREE_PURPOSE (attribute);
+
+ if (is_attribute_p ("deprecated", name))
+ deprecated = true;
+ else
+ warning (OPT_Wattributes, "%qE attribute directive ignored", name);
+ }
+ }
+
+ protocol = lookup_protocol (name, /* warn_if_deprecated */ false,
+ /* definition_required */ false);
if (!protocol)
{
TYPE_LANG_SLOT_1 (protocol) = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
PROTOCOL_NAME (protocol) = name;
- PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+ PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list, /* definition_required */ false);
add_protocol (protocol);
PROTOCOL_DEFINED (protocol) = 1;
PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
else if (! PROTOCOL_DEFINED (protocol))
{
PROTOCOL_DEFINED (protocol) = 1;
- PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+ PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list, /* definition_required */ false);
check_protocol_recursively (protocol, list);
}
warning (0, "duplicate declaration for protocol %qE",
name);
}
+
+ if (attributes)
+ {
+ TYPE_ATTRIBUTES (protocol) = attributes;
+ if (deprecated)
+ TREE_DEPRECATED (protocol) = 1;
+ }
+
return protocol;
}
really_start_method (objc_method_context, parm_info);
}
-/* Return 1 if TYPE1 is equivalent to TYPE2
- for purposes of method overloading. */
-
+/* Return 1 if TYPE1 is equivalent to TYPE2 for purposes of method
+ overloading. */
static int
objc_types_are_equivalent (tree type1, tree type2)
{
if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
return 0;
+ /* Compare the protocol lists. */
type1 = (TYPE_HAS_OBJC_INFO (type1)
? TYPE_OBJC_PROTOCOL_LIST (type1)
: NULL_TREE);
? TYPE_OBJC_PROTOCOL_LIST (type2)
: NULL_TREE);
- if (list_length (type1) == list_length (type2))
+ /* If there are no protocols (most common case), the types are
+ identical. */
+ if (type1 == NULL_TREE && type2 == NULL_TREE)
+ return 1;
+
+ /* If one has protocols, and the other one hasn't, they are not
+ identical. */
+ if ((type1 == NULL_TREE && type2 != NULL_TREE)
+ || (type1 != NULL_TREE && type2 == NULL_TREE))
+ return 0;
+ else
{
- for (; type2; type2 = TREE_CHAIN (type2))
- if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2)))
+ /* Else, both have protocols, and we need to do the full
+ comparison. It is possible that either type1 or type2
+ contain some duplicate protocols in the list, so we can't
+ even just compare list_length as a first check. */
+ tree t;
+
+ for (t = type2; t; t = TREE_CHAIN (t))
+ if (!lookup_protocol_in_reflist (type1, TREE_VALUE (t)))
+ return 0;
+
+ for (t = type1; t; t = TREE_CHAIN (t))
+ if (!lookup_protocol_in_reflist (type2, TREE_VALUE (t)))
return 0;
+
return 1;
}
- return 0;
}
/* Return 1 if TYPE1 has the same size and alignment as TYPE2. */
{
char *demangled, *cp;
+ /* First of all, if the name is too short it can't be an Objective-C
+ mangled method name. */
+ if (mangled[0] == '\0' || mangled[1] == '\0' || mangled[2] == '\0')
+ return NULL;
+
+ /* If the name looks like an already demangled one, return it
+ unchanged. This should only happen on Darwin, where method names
+ are mangled differently into a pretty-print form (such as
+ '+[NSObject class]', see darwin.h). In that case, demangling is
+ a no-op, but we need to return the demangled name if it was an
+ ObjC one, and return NULL if not. We should be safe as no C/C++
+ function can start with "-[" or "+[". */
+ if ((mangled[0] == '-' || mangled[0] == '+')
+ && (mangled[1] == '['))
+ return mangled;
+
if (mangled[0] == '_' &&
(mangled[1] == 'i' || mangled[1] == 'c') &&
mangled[2] == '_')
return;
}
+ if (PROPERTY_REF_DEPRECATED_GETTER (*expr_p))
+ {
+ /* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype
+ that is deprecated. */
+ warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
+ NULL_TREE);
+ }
+
call_exp = getter;
#ifdef OBJCPLUS
/* In C++, a getter which returns an aggregate value results in a
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;
if (!objc_type_valid_for_messaging (TREE_TYPE (object_expression), true))
{
- error ("iterating variable in fast enumeration is not an object");
+ error_at (location, "iterating variable in fast enumeration is not an object");
return;
}
if (!objc_type_valid_for_messaging (TREE_TYPE (collection_expression), true))
{
- error ("collection in fast enumeration is not an object");
+ error_at (location, "collection in fast enumeration is not an object");
return;
}
/* type object; */
/* Done by c-parser.c. */
+ /* Disable warnings that 'object' is unused. For example the code
+
+ for (id object in collection)
+ i++;
+
+ which can be used to count how many objects there are in the
+ collection is fine and should generate no warnings even if
+ 'object' is technically unused. */
+ TREE_USED (object_expression) = 1;
+ if (DECL_P (object_expression))
+ DECL_READ_P (object_expression) = 1;
+
/* id __objc_foreach_collection */
objc_foreach_collection_decl = objc_create_temporary_var (objc_object_type, "__objc_foreach_collection");
t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_collection_decl, collection_expression);
SET_EXPR_LOCATION (t, location);
append_to_statement_list (t, &BIND_EXPR_BODY (bind));
+ /* We have used 'collection_expression'. */
+ mark_exp_read (collection_expression);
/* __objc_foreach_enum_state.state = 0; */
t = build2 (MODIFY_EXPR, void_type_node, objc_build_component_ref (objc_foreach_enum_state_decl,
tree_cons /* __objc_foreach_items */
(NULL_TREE, objc_foreach_items_decl,
tree_cons /* 16 */
- (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+ (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
#else
/* In C, we need to decay the __objc_foreach_items array that we are passing. */
{
tree_cons /* __objc_foreach_items */
(NULL_TREE, default_function_array_conversion (location, array).value,
tree_cons /* 16 */
- (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+ (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
}
#endif
t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_batchsize_decl,
tree_cons /* __objc_foreach_items */
(NULL_TREE, objc_foreach_items_decl,
tree_cons /* 16 */
- (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+ (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
#else
/* In C, we need to decay the __objc_foreach_items array that we are passing. */
{
tree_cons /* __objc_foreach_items */
(NULL_TREE, default_function_array_conversion (location, array).value,
tree_cons /* 16 */
- (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+ (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
}
#endif
t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_batchsize_decl,