#include "toplev.h"
#include "ggc.h"
#include "debug.h"
-#include "target.h"
+#include "c-family/c-target.h"
#include "diagnostic-core.h"
#include "intl.h"
#include "cgraph.h"
static void objc_synthesize_getter (tree, tree, tree);
static void objc_synthesize_setter (tree, tree, tree);
static char *objc_build_property_setter_name (tree);
-static int match_proto_with_proto (tree, tree, int);
static tree lookup_property (tree, tree);
static tree lookup_property_in_list (tree, tree);
static tree lookup_property_in_protocol_list (tree, tree);
/* Forward-declare '@interface Protocol'. */
type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME);
- objc_declare_class (tree_cons (NULL_TREE, type, NULL_TREE));
+ objc_declare_class (type);
objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, type));
/* Declare receiver type used for dispatching messages to 'super'. */
if (!constant_string_class_name)
constant_string_class_name = runtime.default_constant_string_class_name;
constant_string_id = get_identifier (constant_string_class_name);
- objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE));
+ objc_declare_class (constant_string_id);
/* Pre-build the following entities - for speed/convenience. */
self_id = get_identifier ("self");
}
void
-objc_declare_class (tree ident_list)
+objc_declare_class (tree identifier)
{
- tree list;
#ifdef OBJCPLUS
if (current_namespace != global_namespace) {
error ("Objective-C declarations may only appear in global scope");
}
#endif /* OBJCPLUS */
- for (list = ident_list; list; list = TREE_CHAIN (list))
+ if (! objc_is_class_name (identifier))
{
- tree ident = TREE_VALUE (list);
-
- if (! objc_is_class_name (ident))
+ tree record = lookup_name (identifier), type = record;
+
+ if (record)
{
- tree record = lookup_name (ident), type = record;
-
- if (record)
+ if (TREE_CODE (record) == TYPE_DECL)
+ type = DECL_ORIGINAL_TYPE (record)
+ ? DECL_ORIGINAL_TYPE (record)
+ : TREE_TYPE (record);
+
+ if (!TYPE_HAS_OBJC_INFO (type)
+ || !TYPE_OBJC_INTERFACE (type))
{
- if (TREE_CODE (record) == TYPE_DECL)
- type = DECL_ORIGINAL_TYPE (record)
- ? DECL_ORIGINAL_TYPE (record)
- : TREE_TYPE (record);
-
- if (!TYPE_HAS_OBJC_INFO (type)
- || !TYPE_OBJC_INTERFACE (type))
- {
- error ("%qE redeclared as different kind of symbol",
- ident);
- error ("previous declaration of %q+D",
- record);
- }
+ error ("%qE redeclared as different kind of symbol",
+ identifier);
+ error ("previous declaration of %q+D",
+ record);
}
-
- 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);
}
+
+ record = xref_tag (RECORD_TYPE, identifier);
+ 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) = identifier;
+ hash_class_name_enter (cls_name_hash_list, identifier, NULL_TREE);
}
}
{
hash target;
- if (ident && TREE_CODE (ident) == IDENTIFIER_NODE
- && identifier_global_value (ident))
- ident = identifier_global_value (ident);
+ if (ident && TREE_CODE (ident) == IDENTIFIER_NODE)
+ {
+ tree t = identifier_global_value (ident);
+ if (t)
+ ident = t;
+ }
+
while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident))
ident = OBJC_TYPE_NAME (DECL_ORIGINAL_TYPE (ident));
tree
objc_is_id (tree type)
{
- if (type && TREE_CODE (type) == IDENTIFIER_NODE
- && identifier_global_value (type))
- type = identifier_global_value (type);
+ if (type && TREE_CODE (type) == IDENTIFIER_NODE)
+ {
+ tree t = identifier_global_value (type);
+ if (t)
+ type = t;
+ }
if (type && TREE_CODE (type) == TYPE_DECL)
type = TREE_TYPE (type);
/* Copy the attributes from the class to the type. */
if (TREE_DEPRECATED (klass))
TREE_DEPRECATED (record) = 1;
-
- if (CLASS_HAS_EXCEPTION_ATTR (klass))
- CLASS_HAS_EXCEPTION_ATTR (record) = 1;
}
}
chain = CLASS_CLS_METHODS (impent->imp_context);
while (chain)
{
- cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
+ cgraph_mark_needed_node (
+ cgraph_get_create_node (METHOD_DEFINITION (chain)));
chain = DECL_CHAIN (chain);
}
chain = CLASS_NST_METHODS (impent->imp_context);
while (chain)
{
- cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
+ cgraph_mark_needed_node (
+ cgraph_get_create_node (METHOD_DEFINITION (chain)));
chain = DECL_CHAIN (chain);
}
}
strcat (buf, ":");
}
- return get_identifier (buf);
+ return get_identifier_with_length (buf, len);
}
/* Used for declarations and definitions. */
return opcode == INSTANCE_METHOD_DECL || opcode == CLASS_METHOD_DECL;
}
-/* Used by `build_objc_method_call' and `comp_proto_with_proto'. Return
- an argument list for method METH. CONTEXT is either METHOD_DEF or
- METHOD_REF, saying whether we are trying to define a method or call
- one. SUPERFLAG says this is for a send to super; this makes a
- difference for the NeXT calling sequence in which the lookup and
- the method call are done together. If METH is null, user-defined
- arguments (i.e., beyond self and _cmd) shall be represented by `...'. */
+/* Used by `build_objc_method_call'. Return an argument list for
+ method METH. CONTEXT is either METHOD_DEF or METHOD_REF, saying
+ whether we are trying to define a method or call one. SUPERFLAG
+ says this is for a send to super; this makes a difference for the
+ NeXT calling sequence in which the lookup and the method call are
+ done together. If METH is null, user-defined arguments (i.e.,
+ beyond self and _cmd) shall be represented by `...'. */
tree
get_arg_type_list (tree meth, int context, int superflag)
(*(<abstract_decl>(*)())_msgSuper)(receiver, selTransTbl[n], ...); */
tree
-objc_build_message_expr (tree mess)
+objc_build_message_expr (tree receiver, tree message_args)
{
- tree receiver = TREE_PURPOSE (mess);
tree sel_name;
#ifdef OBJCPLUS
- tree args = TREE_PURPOSE (TREE_VALUE (mess));
+ tree args = TREE_PURPOSE (message_args);
#else
- tree args = TREE_VALUE (mess);
+ tree args = message_args;
#endif
tree method_params = NULL_TREE;
/* Build the parameter list to give to the method. */
if (TREE_CODE (args) == TREE_LIST)
#ifdef OBJCPLUS
- method_params = chainon (args, TREE_VALUE (TREE_VALUE (mess)));
+ method_params = chainon (args, TREE_VALUE (message_args));
#else
{
tree chain = args, prev = NULL_TREE;
}
}
+#ifndef OBJCPLUS
+/* A flexible array member is a C99 extension where you can use
+ "type[]" at the end of a struct to mean a variable-length array.
+
+ In Objective-C, instance variables are fundamentally members of a
+ struct, but the struct can always be extended by subclassing; hence
+ we need to detect and forbid all instance variables declared using
+ flexible array members.
+
+ No check for this is needed in Objective-C++, since C++ does not
+ have flexible array members. */
+
+/* Determine whether TYPE is a structure with a flexible array member,
+ a union containing such a structure (possibly recursively) or an
+ array of such structures or unions. These are all invalid as
+ instance variable. */
+static bool
+flexible_array_type_p (tree type)
+{
+ tree x;
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ x = TYPE_FIELDS (type);
+ if (x == NULL_TREE)
+ return false;
+ while (DECL_CHAIN (x) != NULL_TREE)
+ x = DECL_CHAIN (x);
+ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+ && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+ && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+ return true;
+ return false;
+ case UNION_TYPE:
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+ {
+ if (flexible_array_type_p (TREE_TYPE (x)))
+ return true;
+ }
+ return false;
+ /* Note that we also check for arrays of something that uses a flexible array member. */
+ case ARRAY_TYPE:
+ if (flexible_array_type_p (TREE_TYPE (type)))
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+#endif
+
+/* Produce a printable version of an ivar name. This is only used
+ inside add_instance_variable. */
+static const char *
+printable_ivar_name (tree field_decl)
+{
+ if (DECL_NAME (field_decl))
+ return identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (field_decl)));
+ else
+ return _("<unnamed>");
+}
+
/* Called after parsing each instance variable declaration. Necessary to
preserve typedefs and implement public/private...
tree field_decl)
{
tree field_type = TREE_TYPE (field_decl);
- const char *ivar_name = DECL_NAME (field_decl)
- ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (field_decl)))
- : _("<unnamed>");
#ifdef OBJCPLUS
if (TREE_CODE (field_type) == REFERENCE_TYPE)
{
error ("illegal reference type specified for instance variable %qs",
- ivar_name);
+ printable_ivar_name (field_decl));
/* Return class as is without adding this ivar. */
return klass;
}
|| TYPE_SIZE (field_type) == error_mark_node)
/* 'type[0]' is allowed, but 'type[]' is not! */
{
- error ("instance variable %qs has unknown size", ivar_name);
+ error ("instance variable %qs has unknown size",
+ printable_ivar_name (field_decl));
/* Return class as is without adding this ivar. */
return klass;
}
+#ifndef OBJCPLUS
+ /* Also, in C reject a struct with a flexible array member. Ie,
+
+ struct A { int x; int[] y; };
+
+ @interface X
+ {
+ struct A instance_variable;
+ }
+ @end
+
+ is not valid because if the class is subclassed, we wouldn't be able
+ to calculate the offset of the next instance variable. */
+ if (flexible_array_type_p (field_type))
+ {
+ error ("instance variable %qs uses flexible array member",
+ printable_ivar_name (field_decl));
+ /* Return class as is without adding this ivar. */
+ return klass;
+ }
+#endif
+
#ifdef OBJCPLUS
/* Check if the ivar being added has a non-POD C++ type. If so, we will
need to either (1) warn the user about it or (2) generate suitable
error ("type %qE has virtual member functions", type_name);
error ("illegal aggregate type %qE specified "
"for instance variable %qs",
- type_name, ivar_name);
+ type_name, printable_ivar_name (field_decl));
/* Return class as is without adding this ivar. */
return klass;
}
they are already declared or defined, the function has no effect. */
void
-objc_declare_protocols (tree names, tree attributes)
+objc_declare_protocol (tree name, tree attributes)
{
- tree list;
bool deprecated = false;
#ifdef OBJCPLUS
}
}
- for (list = names; list; list = TREE_CHAIN (list))
+ if (lookup_protocol (name, /* warn if deprecated */ false,
+ /* definition_required */ false) == NULL_TREE)
{
- tree name = TREE_VALUE (list);
-
- if (lookup_protocol (name, /* warn if deprecated */ false,
- /* definition_required */ false) == NULL_TREE)
+ tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
+
+ TYPE_LANG_SLOT_1 (protocol)
+ = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
+ PROTOCOL_NAME (protocol) = name;
+ PROTOCOL_LIST (protocol) = NULL_TREE;
+ add_protocol (protocol);
+ PROTOCOL_DEFINED (protocol) = 0;
+ PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
+
+ if (attributes)
{
- tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
-
- TYPE_LANG_SLOT_1 (protocol)
- = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
- PROTOCOL_NAME (protocol) = name;
- PROTOCOL_LIST (protocol) = NULL_TREE;
- 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;
- }
+ /* TODO: Do we need to store the attributes here ? */
+ TYPE_ATTRIBUTES (protocol) = attributes;
+ if (deprecated)
+ TREE_DEPRECATED (protocol) = 1;
}
}
}
static int
comp_proto_with_proto (tree proto1, tree proto2, int strict)
{
+ tree type1, type2;
+
/* The following test is needed in case there are hashing
collisions. */
if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2))
return 0;
- return match_proto_with_proto (proto1, proto2, strict);
-}
-
-static int
-match_proto_with_proto (tree proto1, tree proto2, int strict)
-{
- tree type1, type2;
-
/* Compare return types. */
type1 = TREE_VALUE (TREE_TYPE (proto1));
type2 = TREE_VALUE (TREE_TYPE (proto2));
return 0;
/* Compare argument types. */
- for (type1 = get_arg_type_list (proto1, METHOD_REF, 0),
- type2 = get_arg_type_list (proto2, METHOD_REF, 0);
- type1 && type2;
- type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2))
- {
- if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2))
- && (strict
- || !objc_types_share_size_and_alignment (TREE_VALUE (type1),
- TREE_VALUE (type2))))
- return 0;
- }
- return (!type1 && !type2);
+ /* The first argument (objc_object_type) is always the same, no need
+ to compare. */
+
+ /* The second argument (objc_selector_type) is always the same, no
+ need to compare. */
+
+ /* Compare the other arguments. */
+ {
+ tree arg1, arg2;
+
+ /* Compare METHOD_SEL_ARGS. */
+ for (arg1 = METHOD_SEL_ARGS (proto1), arg2 = METHOD_SEL_ARGS (proto2);
+ arg1 && arg2;
+ arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2))
+ {
+ type1 = TREE_VALUE (TREE_TYPE (arg1));
+ type2 = TREE_VALUE (TREE_TYPE (arg2));
+
+ /* FIXME: Do we need to decay argument types to compare them ? */
+ type1 = objc_decay_parm_type (type1);
+ type2 = objc_decay_parm_type (type2);
+
+ if (!objc_types_are_equivalent (type1, type2)
+ && (strict || !objc_types_share_size_and_alignment (type1, type2)))
+ return 0;
+ }
+
+ /* The loop ends when arg1 or arg2 are NULL. Make sure they are
+ both NULL. */
+ if (arg1 != arg2)
+ return 0;
+
+ /* Compare METHOD_ADD_ARGS. */
+ if ((METHOD_ADD_ARGS (proto1) && !METHOD_ADD_ARGS (proto2))
+ || (METHOD_ADD_ARGS (proto2) && !METHOD_ADD_ARGS (proto1)))
+ return 0;
+
+ if (METHOD_ADD_ARGS (proto1))
+ {
+ for (arg1 = TREE_CHAIN (METHOD_ADD_ARGS (proto1)), arg2 = TREE_CHAIN (METHOD_ADD_ARGS (proto2));
+ arg1 && arg2;
+ arg1 = TREE_CHAIN (arg1), arg2 = TREE_CHAIN (arg2))
+ {
+ type1 = TREE_TYPE (TREE_VALUE (arg1));
+ type2 = TREE_TYPE (TREE_VALUE (arg2));
+
+ /* FIXME: Do we need to decay argument types to compare them ? */
+ type1 = objc_decay_parm_type (type1);
+ type2 = objc_decay_parm_type (type2);
+
+ if (!objc_types_are_equivalent (type1, type2)
+ && (strict || !objc_types_share_size_and_alignment (type1, type2)))
+ return 0;
+ }
+ }
+
+ /* The loop ends when arg1 or arg2 are NULL. Make sure they are
+ both NULL. */
+ if (arg1 != arg2)
+ return 0;
+
+ /* Compare METHOD_ADD_ARGS_ELLIPSIS_P. */
+ if (METHOD_ADD_ARGS_ELLIPSIS_P (proto1) != METHOD_ADD_ARGS_ELLIPSIS_P (proto2))
+ return 0;
+ }
+
+ /* Success. */
+ return 1;
}
/* This routine returns true if TYPE is a valid objc object type,
if (an_int_cst == NULL)
{
/* We are trying to encode an incomplete array. An incomplete
- array is forbidden as part of an instance variable. */
- if (generating_instance_variables)
- {
- /* TODO: Detect this error earlier. */
- error ("instance variable has unknown size");
- return;
- }
+ array is forbidden as part of an instance variable; but it
+ may occur if the instance variable is a pointer to such an
+ array. */
- /* So the only case in which an incomplete array could occur is
- if we are encoding the arguments or return value of a method.
- In that case, an incomplete array argument or return value
- (eg, -(void)display: (char[])string) is treated like a
- pointer because that is how the compiler does the function
- call. A special, more complicated case, is when the
- incomplete array is the last member of a struct (eg, if we
- are encoding "struct { unsigned long int a;double b[];}"),
- which is again part of a method argument/return value. In
- that case, we really need to communicate to the runtime that
- there is an incomplete array (not a pointer!) there. So, we
- detect that special case and encode it as a zero-length
- array.
+ /* So the only case in which an incomplete array could occur
+ (without being pointed to) is if we are encoding the
+ arguments or return value of a method. In that case, an
+ incomplete array argument or return value (eg,
+ -(void)display: (char[])string) is treated like a pointer
+ because that is how the compiler does the function call. A
+ special, more complicated case, is when the incomplete array
+ is the last member of a struct (eg, if we are encoding
+ "struct { unsigned long int a;double b[];}"), which is again
+ part of a method argument/return value. In that case, we
+ really need to communicate to the runtime that there is an
+ incomplete array (not a pointer!) there. So, we detect that
+ special case and encode it as a zero-length array.
Try to detect that we are part of a struct. We do this by
searching for '=' in the type encoding for the current type.
kPropertyGetter = 'G',
kPropertySetter = 'S',
kPropertyInstanceVariable = 'V',
- kPropertyType = 't',
+ kPropertyType = 'T',
kPropertyWeak = 'W',
- kPropertyStrong = 'S',
+ kPropertyStrong = 'P',
kPropertyNonAtomic = 'N'
- };
-
- FIXME: Update the implementation to match. */
+ }; */
tree
objc_v2_encode_prop_attr (tree property)
{
const char *string;
tree type = TREE_TYPE (property);
- obstack_1grow (&util_obstack, 't');
+
+ obstack_1grow (&util_obstack, 'T');
encode_type (type, obstack_object_size (&util_obstack),
OBJC_ENCODE_INLINE_DEFS);
+
if (PROPERTY_READONLY (property))
- obstack_grow (&util_obstack, ",r", 2);
+ obstack_grow (&util_obstack, ",R", 2);
+
+ switch (PROPERTY_ASSIGN_SEMANTICS (property))
+ {
+ case OBJC_PROPERTY_COPY:
+ obstack_grow (&util_obstack, ",C", 2);
+ break;
+ case OBJC_PROPERTY_RETAIN:
+ obstack_grow (&util_obstack, ",&", 2);
+ break;
+ case OBJC_PROPERTY_ASSIGN:
+ default:
+ break;
+ }
+
+ if (PROPERTY_DYNAMIC (property))
+ obstack_grow (&util_obstack, ",D", 2);
- if (PROPERTY_ASSIGN_SEMANTICS (property) == OBJC_PROPERTY_COPY)
- obstack_grow (&util_obstack, ",c", 2);
+ if (PROPERTY_NONATOMIC (property))
+ obstack_grow (&util_obstack, ",N", 2);
- if (PROPERTY_GETTER_NAME (property))
+ /* Here we want to encode the getter name, but only if it's not the
+ standard one. */
+ if (PROPERTY_GETTER_NAME (property) != PROPERTY_NAME (property))
{
- obstack_grow (&util_obstack, ",g", 2);
+ obstack_grow (&util_obstack, ",G", 2);
string = IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property));
obstack_grow (&util_obstack, string, strlen (string));
}
- if (PROPERTY_SETTER_NAME (property))
+
+ if (!PROPERTY_READONLY (property))
{
- obstack_grow (&util_obstack, ",s", 2);
- string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property));
- obstack_grow (&util_obstack, string, strlen (string));
+ /* Here we want to encode the setter name, but only if it's not
+ the standard one. */
+ tree standard_setter = get_identifier (objc_build_property_setter_name (PROPERTY_NAME (property)));
+ if (PROPERTY_SETTER_NAME (property) != standard_setter)
+ {
+ obstack_grow (&util_obstack, ",S", 2);
+ string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property));
+ obstack_grow (&util_obstack, string, strlen (string));
+ }
}
- if (PROPERTY_IVAR_NAME (property))
+
+ /* TODO: Encode strong ('P'), weak ('W') for garbage collection. */
+
+ if (!PROPERTY_DYNAMIC (property))
{
- obstack_grow (&util_obstack, ",i", 2);
- string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property));
+ obstack_grow (&util_obstack, ",V", 2);
+ if (PROPERTY_IVAR_NAME (property))
+ string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property));
+ else
+ string = IDENTIFIER_POINTER (PROPERTY_NAME (property));
obstack_grow (&util_obstack, string, strlen (string));
}
-
- obstack_1grow (&util_obstack, 0); /* null terminate string */
+
+ /* NULL-terminate string. */
+ obstack_1grow (&util_obstack, 0);
string = XOBFINISH (&util_obstack, char *);
obstack_free (&util_obstack, util_firstobj);
return get_identifier (string);
}
+void
+objc_common_init_ts (void)
+{
+ c_common_init_ts ();
+
+ MARK_TS_DECL_NON_COMMON (CLASS_METHOD_DECL);
+ MARK_TS_DECL_NON_COMMON (INSTANCE_METHOD_DECL);
+ MARK_TS_DECL_NON_COMMON (KEYWORD_DECL);
+ MARK_TS_DECL_NON_COMMON (PROPERTY_DECL);
+
+ MARK_TS_COMMON (CLASS_INTERFACE_TYPE);
+ MARK_TS_COMMON (PROTOCOL_INTERFACE_TYPE);
+ MARK_TS_COMMON (CLASS_IMPLEMENTATION_TYPE);
+
+ MARK_TS_TYPED (MESSAGE_SEND_EXPR);
+ MARK_TS_TYPED (PROPERTY_REF);
+}
+
#include "gt-objc-objc-act.h"