/* Implement classes and message passing for Objective C.
Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by Steve Naroff.
This file is part of GCC.
#include "tm.h"
#include "tree.h"
#include "rtl.h"
+#include "tm_p.h"
#include "expr.h"
#include "c-tree.h"
#include "c-common.h"
#include "flags.h"
+#include "langhooks.h"
#include "objc-act.h"
#include "input.h"
#include "except.h"
#include "diagnostic.h"
#include "cgraph.h"
-#define OBJC_VOID_AT_END build_tree_list (NULL_TREE, void_type_node)
-
/* This is the default way of generating a method name. */
/* I am not sure it is really correct.
Perhaps there's a danger that it will make name conflicts
static void build_class_template (void);
static void build_selector_template (void);
static void build_category_template (void);
-static tree lookup_method_in_hash_lists (tree);
+static tree lookup_method_in_hash_lists (tree, int);
static void build_super_template (void);
static tree build_category_initializer (tree, tree, tree, tree, tree, tree);
static tree build_protocol_initializer (tree, tree, tree, tree, tree);
static void generate_dispatch_tables (void);
static void generate_shared_structures (void);
static tree generate_protocol_list (tree);
-static void generate_forward_declaration_to_string_table (void);
static void build_protocol_reference (tree);
static tree build_keyword_selector (tree);
static void hash_add_attr (hash, tree);
static tree lookup_method (tree, tree);
static tree lookup_method_static (tree, tree, int);
+static void add_method_to_hash_list (hash *, tree);
static tree add_class (tree);
static void add_category (tree, tree);
+static inline tree lookup_category (tree, tree);
enum string_section
{
static void generate_category (tree);
static int is_objc_type_qualifier (tree);
static tree adjust_type_for_id_default (tree);
-static tree check_duplicates (hash, int);
+static tree check_duplicates (hash, int, int);
static tree receiver_is_class_object (tree, int, int);
static int check_methods (tree, tree, int);
static int conforms_to_protocol (tree, tree);
&& OBJC_TYPE_NAME (rhs) == objc_object_id))
return 1;
+ /* `Class' != `<class> *' && `<class> *' != `Class'! */
+ else if ((OBJC_TYPE_NAME (lhs) == objc_class_id && TYPED_OBJECT (rhs))
+ || (OBJC_TYPE_NAME (rhs) == objc_class_id && TYPED_OBJECT (lhs)))
+ return 0;
+
/* `<class> *' = `<class> *' */
else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs))
if (TREE_CODE (type) != RECORD_TYPE)
return;
- if (TYPE_NAME (type) && (type = is_class_name (TYPE_NAME (type)))
- && type != constant_string_type)
+ if (TYPE_NAME (type) && (type = is_class_name (TYPE_NAME (type))))
error ("statically allocated instance of Objective-C class `%s'",
- IDENTIFIER_POINTER (type));
+ IDENTIFIER_POINTER (type));
}
/* Implement static typing. At this point, we know we have an interface. */
/* Declare type of selector-objects that represent an operation name. */
- /* `struct objc_selector *' */
- selector_type
- = build_pointer_type (xref_tag (RECORD_TYPE,
- get_identifier (TAG_SELECTOR)));
+ if (flag_next_runtime)
+ /* `struct objc_selector *' */
+ selector_type
+ = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)));
+ else
+ /* `const struct objc_selector *' */
+ selector_type
+ = build_pointer_type
+ (build_qualified_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)),
+ TYPE_QUAL_CONST));
- /* Forward declare type, or else the prototype for msgSendSuper will
- complain. */
+ /* Declare receiver type used for dispatching messages to 'super'. */
/* `struct objc_super *' */
super_type = build_pointer_type (xref_tag (RECORD_TYPE,
get_identifier (TAG_SUPER)));
-
- /* id objc_msgSend (id, SEL, ...); */
-
- temp_type
- = build_function_type (id_type,
- tree_cons (NULL_TREE, id_type,
- tree_cons (NULL_TREE, selector_type,
- NULL_TREE)));
-
- if (! flag_next_runtime)
+ if (flag_next_runtime)
{
- umsg_decl = build_decl (FUNCTION_DECL,
- get_identifier (TAG_MSGSEND), temp_type);
- DECL_EXTERNAL (umsg_decl) = 1;
- TREE_PUBLIC (umsg_decl) = 1;
- DECL_INLINE (umsg_decl) = 1;
- DECL_ARTIFICIAL (umsg_decl) = 1;
+ /* NB: In order to call one of the ..._stret (struct-returning)
+ functions, the function *MUST* first be cast to a signature that
+ corresponds to the actual ObjC method being invoked. This is
+ what is done by the build_objc_method_call() routine below. */
- make_decl_rtl (umsg_decl, NULL);
- pushdecl (umsg_decl);
- }
- else
- {
+ /* id objc_msgSend (id, SEL, ...); */
+ /* id objc_msgSendNonNil (id, SEL, ...); */
+ /* id objc_msgSend_stret (id, SEL, ...); */
+ /* id objc_msgSendNonNil_stret (id, SEL, ...); */
+ temp_type
+ = build_function_type (id_type,
+ tree_cons (NULL_TREE, id_type,
+ tree_cons (NULL_TREE, selector_type,
+ NULL_TREE)));
umsg_decl = builtin_function (TAG_MSGSEND,
temp_type, 0, NOT_BUILT_IN,
NULL, NULL_TREE);
- /* id objc_msgSendNonNil (id, SEL, ...); */
umsg_nonnil_decl = builtin_function (TAG_MSGSEND_NONNIL,
temp_type, 0, NOT_BUILT_IN,
NULL, NULL_TREE);
- }
-
- /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
-
- temp_type
- = build_function_type (id_type,
- tree_cons (NULL_TREE, super_type,
- tree_cons (NULL_TREE, selector_type,
- NULL_TREE)));
-
- umsg_super_decl = builtin_function (TAG_MSGSENDSUPER,
- temp_type, 0, NOT_BUILT_IN,
- NULL, NULL_TREE);
-
- /* The NeXT runtime defines the following additional entry points,
- used for dispatching calls to methods returning structs:
-
- #if defined(__cplusplus)
- id objc_msgSend_stret(id self, SEL op, ...);
- id objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...);
- #else
- void objc_msgSend_stret(void * stretAddr, id self, SEL op, ...);
- void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super,
- SEL op, ...);
- #endif
-
- struct objc_return_struct objc_msgSendNonNil_stret(id self, SEL op, ...);
-
- These prototypes appear in <objc/objc-runtime.h>; however, they
- CANNOT BE USED DIRECTLY. In order to call one of the ..._stret
- functions, the function must first be cast to a signature that
- corresponds to the actual ObjC method being invoked. This is
- what is done by the build_objc_method_call() routine below. */
-
- if (flag_next_runtime)
- {
- tree objc_return_struct_type
- = xref_tag (RECORD_TYPE,
- get_identifier (TAG_RETURN_STRUCT));
-
- tree stret_temp_type
- = build_function_type (id_type,
- tree_cons (NULL_TREE, id_type,
- tree_cons (NULL_TREE, selector_type,
- NULL_TREE)));
-
umsg_stret_decl = builtin_function (TAG_MSGSEND_STRET,
- stret_temp_type, 0, NOT_BUILT_IN,
+ temp_type, 0, NOT_BUILT_IN,
NULL, NULL_TREE);
- stret_temp_type
- = build_function_type (objc_return_struct_type,
- tree_cons (NULL_TREE, id_type,
- tree_cons (NULL_TREE, selector_type,
- NULL_TREE)));
-
umsg_nonnil_stret_decl = builtin_function (TAG_MSGSEND_NONNIL_STRET,
- stret_temp_type, 0, NOT_BUILT_IN,
+ temp_type, 0, NOT_BUILT_IN,
NULL, NULL_TREE);
- stret_temp_type
+ /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
+ /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */
+ temp_type
= build_function_type (id_type,
tree_cons (NULL_TREE, super_type,
tree_cons (NULL_TREE, selector_type,
NULL_TREE)));
-
+ umsg_super_decl = builtin_function (TAG_MSGSENDSUPER,
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
umsg_super_stret_decl = builtin_function (TAG_MSGSENDSUPER_STRET,
- stret_temp_type, 0, NOT_BUILT_IN, 0,
+ temp_type, 0, NOT_BUILT_IN, 0,
NULL_TREE);
}
+ else
+ {
+ /* GNU runtime messenger entry points. */
+
+ /* typedef id (*IMP)(id, SEL, ...); */
+ tree IMP_type
+ = build_pointer_type
+ (build_function_type (id_type,
+ tree_cons (NULL_TREE, id_type,
+ tree_cons (NULL_TREE, selector_type,
+ NULL_TREE))));
+
+ /* IMP objc_msg_lookup (id, SEL); */
+ temp_type
+ = build_function_type (IMP_type,
+ tree_cons (NULL_TREE, id_type,
+ tree_cons (NULL_TREE, selector_type,
+ void_list_node)));
+ umsg_decl = builtin_function (TAG_MSGSEND,
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+
+ /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */
+ temp_type
+ = build_function_type (IMP_type,
+ tree_cons (NULL_TREE, super_type,
+ tree_cons (NULL_TREE, selector_type,
+ void_list_node)));
+ umsg_super_decl = builtin_function (TAG_MSGSENDSUPER,
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ }
/* id objc_getClass (const char *); */
temp_type = build_function_type (id_type,
tree_cons (NULL_TREE,
const_string_type_node,
- OBJC_VOID_AT_END));
+ void_list_node));
objc_get_class_decl
= builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN,
TREE_USED (UOBJC_SELECTOR_TABLE_decl) = 1;
}
- generate_forward_declaration_to_string_table ();
-
/* Forward declare constant_string_id and constant_string_type. */
if (!constant_string_class_name)
constant_string_class_name = default_constant_string_class_name;
{
tree initlist, constructor, constant_string_class;
int length;
+ tree fields;
string = fix_string_type (string);
}
add_class_reference (constant_string_id);
}
+ fields = TYPE_FIELDS (constant_string_type);
/* & ((NXConstantString) { NULL, string, length }) */
return error_mark_node;
}
initlist = build_tree_list
- (NULL_TREE,
+ (fields,
copy_node (build_unary_op (ADDR_EXPR, string_class_decl, 0)));
}
else
{
- initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
+ initlist = build_tree_list (fields, build_int_2 (0, 0));
}
+ fields = TREE_CHAIN (fields);
+
initlist
- = tree_cons (NULL_TREE, copy_node (build_unary_op (ADDR_EXPR, string, 1)),
+ = tree_cons (fields, copy_node (build_unary_op (ADDR_EXPR, string, 1)),
initlist);
- initlist = tree_cons (NULL_TREE, build_int_2 (length, 0), initlist);
+
+ fields = TREE_CHAIN (fields);
+
+ initlist = tree_cons (fields, build_int_2 (length, 0), initlist);
constructor = objc_build_constructor (constant_string_type,
nreverse (initlist));
get_identifier (TAG_EXECCLASS),
build_function_type (void_type_node,
tree_cons (NULL_TREE, ptr_type_node,
- OBJC_VOID_AT_END)));
+ void_list_node)));
DECL_EXTERNAL (execclass_decl) = 1;
DECL_ARTIFICIAL (execclass_decl) = 1;
start_function (void_list_node_1,
build_nt (CALL_EXPR, init_function_name,
tree_cons (NULL_TREE, NULL_TREE,
- OBJC_VOID_AT_END),
+ void_list_node),
NULL_TREE),
NULL_TREE);
store_parm_decls ();
}
}
-/* extern const char _OBJC_STRINGS[]; */
-
-static void
-generate_forward_declaration_to_string_table (void)
-{
- tree sc_spec, decl_specs, expr_decl;
-
- sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_EXTERN], NULL_TREE);
- decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
-
- expr_decl
- = build_nt (ARRAY_REF, get_identifier ("_OBJC_STRINGS"), NULL_TREE);
-
- UOBJC_STRINGS_decl = define_decl (expr_decl, decl_specs);
-}
-
/* Return the DECL of the string IDENT in the SECTION. */
static tree
block = begin_compound_stmt (0);
#else
block = c_begin_compound_stmt ();
- pushlevel (0);
+ push_scope ();
clear_last_expr ();
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
#endif
finish_compound_stmt (0, block);
#else
scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
- inner = poplevel (KEEP_MAYBE, 1, 0);
+ inner = pop_scope ();
SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmt))
= SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmt))
cond = build_unary_op (TRUTH_NOT_EXPR,
build_function_call (objc_setjmp_decl, func_params),
0);
- c_expand_start_cond (c_common_truthvalue_conversion (cond),
- 0, if_stmt);
+ c_expand_start_cond (lang_hooks.truthvalue_conversion (cond), 0, if_stmt);
objc_enter_block ();
}
val_stack_push (&catch_count_stack, 1);
if_stmt = c_begin_if_stmt ();
if_nesting_count++;
- c_expand_start_cond (c_common_truthvalue_conversion (boolean_false_node),
+ c_expand_start_cond (lang_hooks.truthvalue_conversion (boolean_false_node),
0, if_stmt);
objc_enter_block ();
cond = build_function_call (objc_exception_match_decl, func_params);
}
- c_expand_start_cond (c_common_truthvalue_conversion (cond),
- 0, if_stmt);
+ c_expand_start_cond (lang_hooks.truthvalue_conversion (cond), 0, if_stmt);
objc_enter_block ();
objc_declare_variable (RID_REGISTER, var_name,
build_pointer_type (var_type),
}
tree
-objc_build_finally_prologue ()
+objc_build_finally_prologue (void)
{
/* { // begin FINALLY scope
if (!_rethrowException) {
tree if_stmt = c_begin_if_stmt ();
if_nesting_count++;
- c_expand_start_cond (c_common_truthvalue_conversion
- (build_unary_op
- (TRUTH_NOT_EXPR,
- TREE_VALUE (objc_rethrow_exception), 0)),
+ c_expand_start_cond (lang_hooks.truthvalue_conversion
+ (build_unary_op (TRUTH_NOT_EXPR,
+ TREE_VALUE (objc_rethrow_exception),
+ 0)),
0, if_stmt);
objc_enter_block ();
objc_build_try_exit_fragment ();
if_nesting_count++;
c_expand_start_cond
- (c_common_truthvalue_conversion (TREE_VALUE (objc_rethrow_exception)),
+ (lang_hooks.truthvalue_conversion (TREE_VALUE (objc_rethrow_exception)),
0, if_stmt);
objc_enter_block ();
objc_build_throw_stmt (TREE_VALUE (objc_rethrow_exception));
finish_struct (objc_exception_data_template, field_decl_chain, NULL_TREE);
/* int _setjmp(...); */
- /* If the user includes <setjmp.h>, this shall be superceded by
+ /* If the user includes <setjmp.h>, this shall be superseded by
'int _setjmp(jmp_buf);' */
temp_type = build_function_type (integer_type_node, NULL_TREE);
objc_setjmp_decl
= build_function_type (id_type,
tree_cons (NULL_TREE,
build_pointer_type (objc_exception_data_template),
- OBJC_VOID_AT_END));
+ void_list_node));
objc_exception_extract_decl
= builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
/* void objc_exception_try_enter(struct _objc_exception_data *); */
= build_function_type (void_type_node,
tree_cons (NULL_TREE,
build_pointer_type (objc_exception_data_template),
- OBJC_VOID_AT_END));
+ void_list_node));
objc_exception_try_enter_decl
= builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
objc_exception_try_exit_decl
/* void objc_sync_exit(id); */
temp_type = build_function_type (void_type_node,
tree_cons (NULL_TREE, id_type,
- OBJC_VOID_AT_END));
+ void_list_node));
objc_exception_throw_decl
= builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
DECL_ATTRIBUTES (objc_exception_throw_decl)
temp_type = build_function_type (integer_type_node,
tree_cons (NULL_TREE, id_type,
tree_cons (NULL_TREE, id_type,
- OBJC_VOID_AT_END)));
+ void_list_node)));
objc_exception_match_decl
= builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
- if (!comptypes (t1, t2, false)
+ if (!comptypes (t1, t2)
|| !tree_int_cst_equal (TREE_VALUE (TREE_VALUE (rawintdecls)),
TREE_VALUE (TREE_VALUE (rawimpdecls))))
{
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
+#ifdef OBJCPLUS
+ /* struct objc_class *super_class; */
+#else
/* struct objc_class *class; */
+#endif
decl_specs = get_identifier (UTAG_CLASS);
decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs));
+#ifdef OBJCPLUS
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("super_class"));
+#else
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class"));
+#endif
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* Count only the fields occurring in T. */
static int
-ivar_list_length (t)
- tree t;
+ivar_list_length (tree t)
{
int count = 0;
return objc_build_constructor (type, nreverse (initlist));
}
+/* Retrieve category interface CAT_NAME (if any) associated with CLASS. */
+
+static inline tree
+lookup_category (tree class, tree cat_name)
+{
+ tree category = CLASS_CATEGORY_LIST (class);
+
+ while (category && CLASS_SUPER_NAME (category) != cat_name)
+ category = CLASS_CATEGORY_LIST (category);
+ return category;
+}
+
/* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */
static void
class_name_expr = add_objc_string (CLASS_NAME (cat), class_names);
- category = CLASS_CATEGORY_LIST (implementation_template);
-
- /* find the category interface from the class it is associated with */
- while (category)
- {
- if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category))
- break;
- category = CLASS_CATEGORY_LIST (category);
- }
+ category = lookup_category (implementation_template,
+ CLASS_SUPER_NAME (cat));
if (category && CLASS_PROTOCOL_LIST (category))
{
if (METHOD_ADD_ARGS (meth) == objc_ellipsis_node)
/* We have a `, ...' immediately following the selector,
- finalize the arglist...simulate get_parm_info (0). */
+ finalize the arglist...simulate get_parm_info (true). */
;
else if (METHOD_ADD_ARGS (meth))
{
chainon (arglist, add_arg_list);
}
else
- /* finalize the arglist...simulate get_parm_info (1) */
- chainon (arglist, OBJC_VOID_AT_END);
+ /* finalize the arglist...simulate get_parm_info (false) */
+ chainon (arglist, void_list_node);
return arglist;
}
static tree
-check_duplicates (hash hsh, int methods)
+check_duplicates (hash hsh, int methods, int is_class)
{
tree meth = NULL_TREE;
/* We have two or more methods with the same name but
different types. */
attr loop;
- char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+';
warning ("multiple %s named `%c%s' found",
- methods ? "methods" : "selectors", type,
+ methods ? "methods" : "selectors",
+ (is_class ? '+' : '-'),
IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
- warn_with_method (methods ? "using" : "found", type, meth);
+ warn_with_method (methods ? "using" : "found",
+ ((TREE_CODE (meth) == INSTANCE_METHOD_DECL)
+ ? '-'
+ : '+'),
+ meth);
for (loop = hsh->list; loop; loop = loop->next)
- warn_with_method ("also found", type, loop->value);
+ warn_with_method ("also found",
+ ((TREE_CODE (loop->value) == INSTANCE_METHOD_DECL)
+ ? '-'
+ : '+'),
+ loop->value);
}
}
return meth;
&& (exp = TREE_OPERAND (exp, 0))
&& TREE_CODE (exp) == FUNCTION_DECL
/* For some reason, we sometimes wind up with multiple FUNCTION_DECL
- prototypes for objc_get_class(). Thankfuly, they seem to share the
+ prototypes for objc_get_class(). Thankfully, they seem to share the
same function type. */
&& TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl)
&& !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS)
return finish_message_expr (receiver, sel_name, method_params);
}
+/* Look up method SEL_NAME that would be suitable for receiver
+ of type 'id' (if IS_CLASS is zero) or 'Class' (if IS_CLASS is
+ nonzero), and report on any duplicates. */
+
static tree
-lookup_method_in_hash_lists (tree sel_name)
+lookup_method_in_hash_lists (tree sel_name, int is_class)
{
- hash method_prototype = hash_lookup (nst_method_hash_list,
- sel_name);
+ hash method_prototype = NULL;
+
+ if (!is_class)
+ method_prototype = hash_lookup (nst_method_hash_list,
+ sel_name);
if (!method_prototype)
- method_prototype = hash_lookup (cls_method_hash_list,
- sel_name);
+ {
+ method_prototype = hash_lookup (cls_method_hash_list,
+ sel_name);
+ is_class = 1;
+ }
- return check_duplicates (method_prototype, 1);
+ return check_duplicates (method_prototype, 1, is_class);
}
/* The 'finish_message_expr' routine is called from within
is_class != NULL_TREE);
if (!method_prototype && !rprotos)
method_prototype
- = (is_class
- ? check_duplicates (hash_lookup (cls_method_hash_list, sel_name), 1)
- : lookup_method_in_hash_lists (sel_name));
+ = lookup_method_in_hash_lists (sel_name,
+ is_class != NULL_TREE);
}
else
{
if (flag_next_runtime)
{
-#ifdef STRUCT_VALUE
/* If we are returning a struct in memory, and the address
of that memory location is passed as a hidden first
argument, then change which messenger entry point this
expr will call. NB: Note that sender_cast remains
unchanged (it already has a struct return type). */
- if ((TREE_CODE (ret_type) == RECORD_TYPE
- || TREE_CODE (ret_type) == UNION_TYPE)
-#if defined (DEFAULT_PCC_STRUCT_RETURN) && DEFAULT_PCC_STRUCT_RETURN == 0
- && RETURN_IN_MEMORY (ret_type)
-#endif
- && STRUCT_VALUE == 0)
+ if (!targetm.calls.struct_value_rtx (0, 0)
+ && (TREE_CODE (ret_type) == RECORD_TYPE
+ || TREE_CODE (ret_type) == UNION_TYPE)
+ && targetm.calls.return_in_memory (ret_type, 0))
sender = (super_flag ? umsg_super_stret_decl :
flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl);
-#endif
+
method_params = tree_cons (NULL_TREE, lookup_object,
tree_cons (NULL_TREE, selector,
method_params));
expr = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0);
- TREE_TYPE (expr) = protocol_type;
+ /* ??? Ideally we'd build the reference with protocol_type directly,
+ if we have it, rather than converting it here. */
+ expr = convert (protocol_type, expr);
/* The @protocol() expression is being compiled into a pointer to a
statically allocated instance of the Protocol class. To become
return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE;
}
+/* Add the method to the hash list if it doesn't contain an identical
+ method already. */
+static void
+add_method_to_hash_list (hash *hash_list, tree method)
+{
+ hash hsh;
+
+ if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method))))
+ {
+ /* Install on a global chain. */
+ hash_enter (hash_list, method);
+ }
+ else
+ {
+ /* Check types against those; if different, add to a list. */
+ attr loop;
+ int already_there = comp_proto_with_proto (method, hsh->key);
+ for (loop = hsh->list; !already_there && loop; loop = loop->next)
+ already_there |= comp_proto_with_proto (method, loop->value);
+ if (!already_there)
+ hash_add_attr (hsh, method);
+ }
+}
+
tree
-add_method (tree class, tree method, int is_class)
+objc_add_method (tree class, tree method, int is_class)
{
tree mth;
- hash hsh;
if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), 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). */
+ /* 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). */
if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE
|| TREE_CODE (class) == CATEGORY_INTERFACE_TYPE)
&& !comp_proto_with_proto (method, mth))
is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
}
- if (!(hsh = hash_lookup (is_class
- ? cls_method_hash_list
- : nst_method_hash_list, METHOD_SEL_NAME (method))))
- {
- /* Install on a global chain. */
- hash_enter (is_class ? cls_method_hash_list : nst_method_hash_list, method);
- }
+ if (is_class)
+ add_method_to_hash_list (cls_method_hash_list, method);
else
{
- /* Check types against those; if different, add to a list. */
- attr loop;
- int already_there = comp_proto_with_proto (method, hsh->key);
- for (loop = hsh->list; !already_there && loop; loop = loop->next)
- already_there |= comp_proto_with_proto (method, loop->value);
- if (!already_there)
- hash_add_attr (hsh, method);
+ add_method_to_hash_list (nst_method_hash_list, method);
+
+ /* Instance methods in root classes (and categories thereof)
+ may acts as class methods as a last resort. */
+ if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE
+ || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
+ class = lookup_interface (CLASS_NAME (class));
+
+ if (TREE_CODE (class) != PROTOCOL_INTERFACE_TYPE
+ && !CLASS_SUPER_NAME (class))
+ add_method_to_hash_list (cls_method_hash_list, method);
}
+
return method;
}
add_category (tree class, tree category)
{
/* Put categories on list in reverse order. */
- tree cat = CLASS_CATEGORY_LIST (class);
+ tree cat = lookup_category (class, CLASS_SUPER_NAME (category));
- while (cat)
+ if (cat)
{
- if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category))
-#ifdef OBJCPLUS
- error ("duplicate interface declaration for category `%s(%s)'",
-#else
- warning ("duplicate interface declaration for category `%s(%s)'",
-#endif
- IDENTIFIER_POINTER (CLASS_NAME (class)),
- IDENTIFIER_POINTER (CLASS_SUPER_NAME (category)));
- cat = CLASS_CATEGORY_LIST (cat);
+ warning ("duplicate interface declaration for category `%s(%s)'",
+ IDENTIFIER_POINTER (CLASS_NAME (class)),
+ IDENTIFIER_POINTER (CLASS_SUPER_NAME (category)));
+ }
+ else
+ {
+ CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
+ CLASS_CATEGORY_LIST (class) = category;
}
-
- CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
- CLASS_CATEGORY_LIST (class) = category;
}
/* Called after parsing each instance variable declaration. Necessary to
int
is_private (tree decl)
{
- if (TREE_PRIVATE (decl)
- && ! is_ivar (CLASS_IVARS (implementation_template), DECL_NAME (decl)))
- {
- error ("instance variable `%s' is declared private",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- return 1;
- }
- else
- return 0;
+ return (TREE_PRIVATE (decl)
+ && ! is_ivar (CLASS_IVARS (implementation_template),
+ DECL_NAME (decl)));
}
/* We have an instance variable reference;, check to see if it is public. */
int
-is_public (tree expr, tree identifier)
+objc_is_public (tree expr, tree identifier)
{
tree basetype = TREE_TYPE (expr);
enum tree_code code = TREE_CODE (basetype);
== CATEGORY_IMPLEMENTATION_TYPE))
&& (CLASS_NAME (objc_implementation_context)
== OBJC_TYPE_NAME (basetype))))
- return ! is_private (decl);
+ {
+ int private = is_private (decl);
+
+ if (private)
+ error ("instance variable `%s' is declared private",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ return !private;
+ }
/* The 2.95.2 compiler sometimes allowed C functions to access
non-@public ivars. We will let this slide for now... */
else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
{
- tree category = CLASS_CATEGORY_LIST (implementation_template);
-
- /* Find the category interface from the class it is associated with. */
- while (category)
- {
- if (CLASS_SUPER_NAME (class) == CLASS_SUPER_NAME (category))
- break;
- category = CLASS_CATEGORY_LIST (category);
- }
+ tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class));
if (category)
{
}
\f
/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS. */
-
static void
encode_type (tree type, int curtype, int format)
{
enum tree_code code = TREE_CODE (type);
+ char c;
if (code == INTEGER_TYPE)
{
- if (integer_zerop (TYPE_MIN_VALUE (type)))
+ switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
{
- /* Unsigned integer types. */
-
- if (TYPE_MODE (type) == QImode)
- obstack_1grow (&util_obstack, 'C');
- else if (TYPE_MODE (type) == HImode)
- obstack_1grow (&util_obstack, 'S');
- else if (TYPE_MODE (type) == SImode)
- {
- if (type == long_unsigned_type_node)
- obstack_1grow (&util_obstack, 'L');
- else
- obstack_1grow (&util_obstack, 'I');
- }
- else if (TYPE_MODE (type) == DImode)
- obstack_1grow (&util_obstack, 'Q');
- }
-
- else
- /* Signed integer types. */
- {
- if (TYPE_MODE (type) == QImode)
- obstack_1grow (&util_obstack, 'c');
- else if (TYPE_MODE (type) == HImode)
- obstack_1grow (&util_obstack, 's');
- else if (TYPE_MODE (type) == SImode)
- {
- if (type == long_integer_type_node)
- obstack_1grow (&util_obstack, 'l');
- else
- obstack_1grow (&util_obstack, 'i');
- }
-
- else if (TYPE_MODE (type) == DImode)
- obstack_1grow (&util_obstack, 'q');
+ case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
+ case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
+ case 32:
+ if (type == long_unsigned_type_node
+ || type == long_integer_type_node)
+ c = TYPE_UNSIGNED (type) ? 'L' : 'l';
+ else
+ c = TYPE_UNSIGNED (type) ? 'I' : 'i';
+ break;
+ case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
+ default: abort ();
}
+ obstack_1grow (&util_obstack, c);
}
else if (code == REAL_TYPE)
{
/* Floating point types. */
-
- if (TYPE_MODE (type) == SFmode)
- obstack_1grow (&util_obstack, 'f');
- else if (TYPE_MODE (type) == DFmode
- || TYPE_MODE (type) == TFmode)
- obstack_1grow (&util_obstack, 'd');
+ switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
+ {
+ case 32: c = 'f'; break;
+ case 64:
+ case 128: c = 'd'; break;
+ default: abort ();
+ }
+ obstack_1grow (&util_obstack, c);
}
else if (code == VOID_TYPE)
build1 (INDIRECT_REF, NULL_TREE, self_id)),
unused_list));
- decl_specs = build_tree_list (NULL_TREE,
- xref_tag (RECORD_TYPE,
- get_identifier (TAG_SELECTOR)));
+ decl_specs = build_tree_list (NULL_TREE, TREE_TYPE (selector_type));
push_parm_decl (build_tree_list
(build_tree_list (decl_specs,
build1 (INDIRECT_REF, NULL_TREE, ucmd_id)),
UOBJC_SUPER_decl = NULL_TREE;
/* Must be called BEFORE start_function. */
- pushlevel (0);
+ push_scope ();
+ declare_parm_level ();
/* Generate prototype declarations for arguments..."new-style". */
synth_self_and_ucmd_args ();
/* install return type */
TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto));
- return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function1_template,
- false);
+ return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function1_template);
}
/* Return 1 if TYPE1 is equivalent to TYPE2. */
METHOD_SEL_NAME (method),
TREE_CODE (method) == CLASS_METHOD_DECL);
- if (proto && ! comp_method_with_proto (method, proto))
+ if (proto)
{
- char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+');
+ if (!comp_method_with_proto (method, proto))
+ {
+ char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+');
- warn_with_method ("conflicting types for", type, method);
- warn_with_method ("previous declaration of", type, proto);
+ warn_with_method ("conflicting types for", type, method);
+ warn_with_method ("previous declaration of", type, proto);
+ }
+ }
+ else
+ {
+ /* We have a method @implementation even though we did not
+ see a corresponding @interface declaration (which is allowed
+ by Objective-C rules). Go ahead and place the method in
+ the @interface anyway, so that message dispatch lookups
+ will see it. */
+ tree interface = implementation_template;
+
+ if (TREE_CODE (objc_implementation_context)
+ == CATEGORY_IMPLEMENTATION_TYPE)
+ interface = lookup_category
+ (interface,
+ CLASS_SUPER_NAME (objc_implementation_context));
+
+ if (interface)
+ objc_add_method (interface, copy_node (method),
+ TREE_CODE (method) == CLASS_METHOD_DECL);
}
}
}
if (METHOD_ADD_ARGS (objc_method_context) == objc_ellipsis_node)
/* We have a `, ...' immediately following the selector. */
- parmlist = get_parm_info (0);
+ parmlist = get_parm_info (/*ellipsis=*/true);
else
- parmlist = get_parm_info (1); /* place a `void_at_end' */
+ parmlist = get_parm_info (/*ellipsis=*/false);
#ifndef OBJCPLUS
/* Set self_decl from the first argument...this global is used by
self_decl = TREE_PURPOSE (parmlist);
#endif /* !OBJCPLUS */
- poplevel (0, 0, 0);
+ pop_scope ();
really_start_method (objc_method_context, parmlist);
store_parm_decls ();
}
super_expr_list = build_tree_list (NULL_TREE, super_expr);
/* Set class to begin searching. */
+#ifdef OBJCPLUS
+ super_expr = build_component_ref (UOBJC_SUPER_decl,
+ get_identifier ("super_class"));
+#else
super_expr = build_component_ref (UOBJC_SUPER_decl,
get_identifier ("class"));
+#endif
if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
{
else if (code == POINTER_TYPE)
{
strcpy (tmpbuf, "*");
- if (TREE_READONLY (decl) || TYPE_VOLATILE (decl))
+ if (TYPE_READONLY (decl) || TYPE_VOLATILE (decl))
{
- if (TREE_READONLY (decl))
+ if (TYPE_READONLY (decl))
strcat (tmpbuf, " const");
if (TYPE_VOLATILE (decl))
strcat (tmpbuf, " volatile");
else
{
/* Type qualifiers. */
- if (TREE_READONLY (declspecs))
+ if (TYPE_READONLY (declspecs))
strcat (buf, "const ");
if (TYPE_VOLATILE (declspecs))
strcat (buf, "volatile ");
strcat (buf, gen_declarator (declarator, declbuf, ""));
}
if (width)
- sprintf (buf + strlen (buf), ": %lu", TREE_INT_CST_LOW (width));
+ sprintf (buf + strlen (buf), ": " HOST_WIDE_INT_PRINT_UNSIGNED,
+ TREE_INT_CST_LOW (width));
}
else
objc_implementation_context = NULL_TREE;
}
- generate_forward_declaration_to_string_table ();
-
/* Process the static instances here because initialization of objc_symtab
depends on them. */
if (objc_static_instances)
for (slot = 0; slot < SIZEHASHTABLE; slot++)
{
for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
- check_duplicates (hsh, 0);
+ check_duplicates (hsh, 0, 1);
for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
- check_duplicates (hsh, 0);
+ check_duplicates (hsh, 0, 1);
}
}
}
}
\f
-/* The Fix-and-Countinue functionality available in Mac OS X 10.3 and
+/* The Fix-and-Continue functionality available in Mac OS X 10.3 and
later requires that ObjC translation units participating in F&C be
specially marked. The following routine accomplishes this. */
else if (objc_method_context && (decl = is_ivar (objc_ivar_chain, id)))
{
if (is_private (decl))
- return error_mark_node;
+ return 0;
else
return build_ivar_reference (id);
}