/* 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 "target.h"
#include "diagnostic.h"
#include "cgraph.h"
+#include "tree-iterator.h"
+#include "libfuncs.h"
/* This is the default way of generating a method name. */
/* I am not sure it is really correct.
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
\f
-\f
/* Set up for use of obstacks. */
#include "obstack.h"
/* This obstack is used to accumulate the encoding of a data type. */
static struct obstack util_obstack;
-/* This points to the beginning of obstack contents,
- so we can free the whole contents. */
-char *util_firstobj;
-/* for encode_method_def */
-#include "rtl.h"
+/* This points to the beginning of obstack contents, so we can free
+ the whole contents. */
+char *util_firstobj;
/* The version identifies which language generation and runtime
the module (file) was compiled for, and is recorded in the
/* Used by compile_file. */
-static void init_objc PARAMS ((void));
-static void finish_objc PARAMS ((void));
+static void init_objc (void);
+static void finish_objc (void);
/* Code generation. */
-static void synth_module_prologue PARAMS ((void));
-static tree objc_build_constructor PARAMS ((tree, tree));
-static rtx build_module_descriptor PARAMS ((void));
-static tree init_module_descriptor PARAMS ((tree));
-static tree build_objc_method_call PARAMS ((int, tree, tree,
- tree, tree, tree));
-static void generate_strings PARAMS ((void));
-static tree get_proto_encoding PARAMS ((tree));
-static void build_selector_translation_table PARAMS ((void));
-
-static tree objc_add_static_instance PARAMS ((tree, tree));
-
-static tree build_ivar_template PARAMS ((void));
-static tree build_method_template PARAMS ((void));
-static tree build_private_template PARAMS ((tree));
-static void build_class_template PARAMS ((void));
-static void build_selector_template PARAMS ((void));
-static void build_category_template PARAMS ((void));
-static tree build_super_template PARAMS ((void));
-static tree build_category_initializer PARAMS ((tree, tree, tree,
- tree, tree, tree));
-static tree build_protocol_initializer PARAMS ((tree, tree, tree,
- tree, tree));
-
-static void synth_forward_declarations PARAMS ((void));
-static void generate_ivar_lists PARAMS ((void));
-static void generate_dispatch_tables PARAMS ((void));
-static void generate_shared_structures PARAMS ((void));
-static tree generate_protocol_list PARAMS ((tree));
-static void generate_forward_declaration_to_string_table PARAMS ((void));
-static void build_protocol_reference PARAMS ((tree));
-
-static tree build_keyword_selector PARAMS ((tree));
-static tree synth_id_with_class_suffix PARAMS ((const char *, tree));
-
-static void generate_static_references PARAMS ((void));
-static int check_methods_accessible PARAMS ((tree, tree,
- int));
-static void encode_aggregate_within PARAMS ((tree, int, int,
- int, int));
-static const char *objc_demangle PARAMS ((const char *));
-static void objc_expand_function_end PARAMS ((void));
+static void synth_module_prologue (void);
+static tree objc_build_constructor (tree, tree);
+static rtx build_module_descriptor (void);
+static tree init_module_descriptor (tree);
+static tree build_objc_method_call (int, tree, tree, tree, tree);
+static void generate_strings (void);
+static tree get_proto_encoding (tree);
+static void build_selector_translation_table (void);
+static tree lookup_interface (tree);
+static tree objc_add_static_instance (tree, tree);
+
+static void build_objc_exception_stuff (void);
+static void build_next_objc_exception_stuff (void);
+
+static tree build_ivar_template (void);
+static tree build_method_template (void);
+static tree build_private_template (tree);
+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, 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 synth_forward_declarations (void);
+static int ivar_list_length (tree);
+static tree get_class_ivars (tree, int);
+static void generate_ivar_lists (void);
+static void generate_dispatch_tables (void);
+static void generate_shared_structures (void);
+static tree generate_protocol_list (tree);
+static void build_protocol_reference (tree);
+
+static tree build_keyword_selector (tree);
+static tree synth_id_with_class_suffix (const char *, tree);
+
+static void generate_static_references (void);
+static int check_methods_accessible (tree, tree, int);
+static void encode_aggregate_within (tree, int, int, int, int);
+static const char *objc_demangle (const char *);
+static void objc_expand_function_end (void);
/* Hash tables to manage the global pool of method prototypes. */
hash *nst_method_hash_list = 0;
hash *cls_method_hash_list = 0;
-static size_t hash_func PARAMS ((tree));
-static void hash_init PARAMS ((void));
-static void hash_enter PARAMS ((hash *, tree));
-static hash hash_lookup PARAMS ((hash *, tree));
-static void hash_add_attr PARAMS ((hash, tree));
-static tree lookup_method PARAMS ((tree, tree));
-static tree lookup_instance_method_static PARAMS ((tree, tree));
-static tree lookup_class_method_static PARAMS ((tree, tree));
-static tree add_class PARAMS ((tree));
-static void add_category PARAMS ((tree, tree));
+static size_t hash_func (tree);
+static void hash_init (void);
+static void hash_enter (hash *, tree);
+static hash hash_lookup (hash *, 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
{
meth_var_types /* method and variable type descriptors */
};
-static tree add_objc_string PARAMS ((tree,
- enum string_section));
-static tree get_objc_string_decl PARAMS ((tree,
- enum string_section));
-static tree build_objc_string_decl PARAMS ((enum string_section));
-static tree build_selector_reference_decl PARAMS ((void));
+static tree add_objc_string (tree, enum string_section);
+static tree get_objc_string_decl (tree, enum string_section);
+static tree build_objc_string_decl (enum string_section);
+static tree build_selector_reference_decl (void);
/* Protocol additions. */
-static tree add_protocol PARAMS ((tree));
-static tree lookup_protocol PARAMS ((tree));
-static void check_protocol_recursively PARAMS ((tree, tree));
-static tree lookup_and_install_protocols PARAMS ((tree));
+static tree add_protocol (tree);
+static tree lookup_protocol (tree);
+static void check_protocol_recursively (tree, tree);
+static tree lookup_and_install_protocols (tree);
/* Type encoding. */
-static void encode_type_qualifiers PARAMS ((tree));
-static void encode_pointer PARAMS ((tree, int, int));
-static void encode_array PARAMS ((tree, int, int));
-static void encode_aggregate PARAMS ((tree, int, int));
-static void encode_bitfield PARAMS ((int));
-static void encode_type PARAMS ((tree, int, int));
-static void encode_field_decl PARAMS ((tree, int, int));
-
-static void really_start_method PARAMS ((tree, tree));
-static int comp_method_with_proto PARAMS ((tree, tree));
-static int comp_proto_with_proto PARAMS ((tree, tree));
-static tree get_arg_type_list PARAMS ((tree, int, int));
-static tree objc_expr_last PARAMS ((tree));
+static void encode_type_qualifiers (tree);
+static void encode_pointer (tree, int, int);
+static void encode_array (tree, int, int);
+static void encode_aggregate (tree, int, int);
+static void encode_next_bitfield (int);
+static void encode_gnu_bitfield (int, tree, int);
+static void encode_type (tree, int, int);
+static void encode_field_decl (tree, int, int);
+
+static void really_start_method (tree, tree);
+static int comp_method_with_proto (tree, tree);
+static int objc_types_are_equivalent (tree, tree);
+static int comp_proto_with_proto (tree, tree);
+static tree get_arg_type_list (tree, int, int);
+static tree objc_expr_last (tree);
+static void synth_self_and_ucmd_args (void);
/* Utilities for debugging and error diagnostics. */
-static void warn_with_method PARAMS ((const char *, int, tree));
-static void error_with_ivar PARAMS ((const char *, tree, tree));
-static char *gen_method_decl PARAMS ((tree, char *));
-static char *gen_declaration PARAMS ((tree, char *));
-static void gen_declaration_1 PARAMS ((tree, char *));
-static char *gen_declarator PARAMS ((tree, char *,
- const char *));
-static int is_complex_decl PARAMS ((tree));
-static void adorn_decl PARAMS ((tree, char *));
-static void dump_interface PARAMS ((FILE *, tree));
+static void warn_with_method (const char *, int, tree);
+static void error_with_ivar (const char *, tree, tree);
+static char *gen_method_decl (tree, char *);
+static char *gen_declaration (tree, char *);
+static void gen_declaration_1 (tree, char *);
+static char *gen_declarator (tree, char *, const char *);
+static int is_complex_decl (tree);
+static void adorn_decl (tree, char *);
+static void dump_interface (FILE *, tree);
/* Everything else. */
-static tree define_decl PARAMS ((tree, tree));
-static tree lookup_method_in_protocol_list PARAMS ((tree, tree, int));
-static tree lookup_protocol_in_reflist PARAMS ((tree, tree));
-static tree create_builtin_decl PARAMS ((enum tree_code,
- tree, const char *));
-static void setup_string_decl PARAMS ((void));
-static void build_string_class_template PARAMS ((void));
-static tree my_build_string PARAMS ((int, const char *));
-static void build_objc_symtab_template PARAMS ((void));
-static tree init_def_list PARAMS ((tree));
-static tree init_objc_symtab PARAMS ((tree));
-static void forward_declare_categories PARAMS ((void));
-static void generate_objc_symtab_decl PARAMS ((void));
-static tree build_selector PARAMS ((tree));
-static tree build_typed_selector_reference PARAMS ((tree, tree));
-static tree build_selector_reference PARAMS ((tree));
-static tree build_class_reference_decl PARAMS ((void));
-static void add_class_reference PARAMS ((tree));
-static tree build_protocol_template PARAMS ((void));
-static tree build_descriptor_table_initializer PARAMS ((tree, tree));
-static tree build_method_prototype_list_template PARAMS ((tree, int));
-static tree build_method_prototype_template PARAMS ((void));
-static int forwarding_offset PARAMS ((tree));
-static tree encode_method_prototype PARAMS ((tree, tree));
-static tree generate_descriptor_table PARAMS ((tree, const char *,
- int, tree, tree));
-static void generate_method_descriptors PARAMS ((tree));
-static tree build_tmp_function_decl PARAMS ((void));
-static void hack_method_prototype PARAMS ((tree, tree));
-static void generate_protocol_references PARAMS ((tree));
-static void generate_protocols PARAMS ((void));
-static void check_ivars PARAMS ((tree, tree));
-static tree build_ivar_list_template PARAMS ((tree, int));
-static tree build_method_list_template PARAMS ((tree, int));
-static tree build_ivar_list_initializer PARAMS ((tree, tree));
-static tree generate_ivars_list PARAMS ((tree, const char *,
- int, tree));
-static tree build_dispatch_table_initializer PARAMS ((tree, tree));
-static tree generate_dispatch_table PARAMS ((tree, const char *,
- int, tree));
-static tree build_shared_structure_initializer PARAMS ((tree, tree, tree, tree,
- tree, int, tree, tree,
- tree));
-static void generate_category PARAMS ((tree));
-static int is_objc_type_qualifier PARAMS ((tree));
-static tree adjust_type_for_id_default PARAMS ((tree));
-static tree check_duplicates PARAMS ((hash));
-static tree receiver_is_class_object PARAMS ((tree));
-static int check_methods PARAMS ((tree, tree, int));
-static int conforms_to_protocol PARAMS ((tree, tree));
-static void check_protocol PARAMS ((tree, const char *,
- const char *));
-static void check_protocols PARAMS ((tree, const char *,
- const char *));
-static tree encode_method_def PARAMS ((tree));
-static void gen_declspecs PARAMS ((tree, char *, int));
-static void generate_classref_translation_entry PARAMS ((tree));
-static void handle_class_ref PARAMS ((tree));
-static void generate_struct_by_value_array PARAMS ((void))
+static tree define_decl (tree, tree);
+static tree lookup_method_in_protocol_list (tree, tree, int);
+static tree lookup_protocol_in_reflist (tree, tree);
+static tree create_builtin_decl (enum tree_code, tree, const char *);
+static void setup_string_decl (void);
+static int check_string_class_template (void);
+static tree my_build_string (int, const char *);
+static void build_objc_symtab_template (void);
+static tree init_def_list (tree);
+static tree init_objc_symtab (tree);
+static tree build_metadata_decl (const char *, tree);
+static void forward_declare_categories (void);
+static void generate_objc_symtab_decl (void);
+static tree build_selector (tree);
+static tree build_typed_selector_reference (tree, tree);
+static tree build_selector_reference (tree);
+static tree build_class_reference_decl (void);
+static void add_class_reference (tree);
+static tree build_protocol_template (void);
+static tree build_descriptor_table_initializer (tree, tree);
+static tree build_method_prototype_list_template (tree, int);
+static tree build_method_prototype_template (void);
+static tree objc_method_parm_type (tree);
+static int objc_encoded_type_size (tree);
+static tree encode_method_prototype (tree);
+static tree generate_descriptor_table (tree, const char *, int, tree, tree);
+static void generate_method_descriptors (tree);
+static void generate_protocol_references (tree);
+static void generate_protocols (void);
+static void check_ivars (tree, tree);
+static tree build_ivar_list_template (tree, int);
+static tree build_method_list_template (tree, int);
+static tree build_ivar_list_initializer (tree, tree);
+static tree generate_ivars_list (tree, const char *, int, tree);
+static tree build_dispatch_table_initializer (tree, tree);
+static tree generate_dispatch_table (tree, const char *, int, tree);
+static tree build_shared_structure_initializer (tree, tree, tree, tree,
+ tree, int, tree, tree, tree);
+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, int);
+static tree receiver_is_class_object (tree, int, int);
+static int check_methods (tree, tree, int);
+static int conforms_to_protocol (tree, tree);
+static void check_protocol (tree, const char *, const char *);
+static void check_protocols (tree, const char *, const char *);
+static void gen_declspecs (tree, char *, int);
+static void generate_classref_translation_entry (tree);
+static void handle_class_ref (tree);
+static void generate_struct_by_value_array (void)
ATTRIBUTE_NORETURN;
-static void encode_complete_bitfield PARAMS ((int, tree, int));
-static void mark_referenced_methods PARAMS ((void));
+static void mark_referenced_methods (void);
+static void generate_objc_image_info (void);
/*** Private Interface (data) ***/
/* Note that the string object global name is only needed for the
NeXT runtime. */
-#define STRING_OBJECT_GLOBAL_NAME "_NSConstantStringClassReference"
+#define STRING_OBJECT_GLOBAL_FORMAT "_%sClassReference"
#define PROTOCOL_OBJECT_CLASS_NAME "Protocol"
static const char *TAG_GETMETACLASS;
static const char *TAG_MSGSEND;
static const char *TAG_MSGSENDSUPER;
+/* The NeXT Objective-C messenger may have two extra entry points, for use
+ when returning a structure. */
+static const char *TAG_MSGSEND_STRET;
+static const char *TAG_MSGSENDSUPER_STRET;
static const char *TAG_EXECCLASS;
static const char *default_constant_string_class_name;
+/* Runtime metadata flags. */
+#define CLS_FACTORY 0x0001L
+#define CLS_META 0x0002L
+
+#define OBJC_MODIFIER_STATIC 0x00000001
+#define OBJC_MODIFIER_FINAL 0x00000002
+#define OBJC_MODIFIER_PUBLIC 0x00000004
+#define OBJC_MODIFIER_PRIVATE 0x00000008
+#define OBJC_MODIFIER_PROTECTED 0x00000010
+#define OBJC_MODIFIER_NATIVE 0x00000020
+#define OBJC_MODIFIER_SYNCHRONIZED 0x00000040
+#define OBJC_MODIFIER_ABSTRACT 0x00000080
+#define OBJC_MODIFIER_VOLATILE 0x00000100
+#define OBJC_MODIFIER_TRANSIENT 0x00000200
+#define OBJC_MODIFIER_NONE_SPECIFIED 0x80000000
+
+#define TAG_MSGSEND_NONNIL "objc_msgSendNonNil"
+#define TAG_MSGSEND_NONNIL_STRET "objc_msgSendNonNil_stret"
+#define TAG_EXCEPTIONEXTRACT "objc_exception_extract"
+#define TAG_EXCEPTIONTRYENTER "objc_exception_try_enter"
+#define TAG_EXCEPTIONTRYEXIT "objc_exception_try_exit"
+#define TAG_EXCEPTIONMATCH "objc_exception_match"
+#define TAG_EXCEPTIONTHROW "objc_exception_throw"
+#define TAG_SYNCENTER "objc_sync_enter"
+#define TAG_SYNCEXIT "objc_sync_exit"
+#define TAG_SETJMP "_setjmp"
+#define TAG_RETURN_STRUCT "objc_return_struct"
+
+#define UTAG_EXCDATA "_objc_exception_data"
+
/* The OCTI_... enumeration itself is in objc/objc-act.h. */
tree objc_global_trees[OCTI_MAX];
-static void handle_impent PARAMS ((struct imp_entry *));
+static void handle_impent (struct imp_entry *);
struct imp_entry *imp_list = 0;
int imp_count = 0; /* `@implementation' */
int cat_count = 0; /* `@category' */
-static int method_slot = 0; /* Used by start_method_def, */
+/* Use to generate method labels. */
+static int method_slot = 0;
#define BUFSIZE 1024
the transition point between the two possibilities. */
static void
-generate_struct_by_value_array ()
+generate_struct_by_value_array (void)
{
tree type;
tree field_decl, field_decl_chain;
chainon (field_decl_chain, field_decl);
}
finish_struct (type, field_decl_chain, NULL_TREE);
-
- aggregate_in_mem[i] = aggregate_value_p (type);
+
+ aggregate_in_mem[i] = aggregate_value_p (type, 0);
if (!aggregate_in_mem[i])
found = 1;
}
-
+
/* We found some structures that are returned in registers instead of memory
so output the necessary data. */
if (found)
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");
}
-
+
exit (0);
}
bool
-objc_init ()
+objc_init (void)
{
if (c_objc_common_init () == false)
return false;
TAG_GETMETACLASS = "objc_getMetaClass";
TAG_MSGSEND = "objc_msgSend";
TAG_MSGSENDSUPER = "objc_msgSendSuper";
+ TAG_MSGSEND_STRET = "objc_msgSend_stret";
+ TAG_MSGSENDSUPER_STRET = "objc_msgSendSuper_stret";
TAG_EXECCLASS = "__objc_execClass";
default_constant_string_class_name = "NSConstantString";
}
TAG_GETMETACLASS = "objc_get_meta_class";
TAG_MSGSEND = "objc_msg_lookup";
TAG_MSGSENDSUPER = "objc_msg_lookup_super";
+ /* GNU runtime does not provide special functions to support
+ structure-returning methods. */
TAG_EXECCLASS = "__objc_exec_class";
default_constant_string_class_name = "NXConstantString";
flag_typed_selectors = 1;
}
void
-finish_file ()
+objc_finish_file (void)
{
mark_referenced_methods ();
- c_objc_common_finish_file ();
/* Finalize Objective-C runtime data. No need to generate tables
and code if only checking syntax. */
}
\f
static tree
-define_decl (declarator, declspecs)
- tree declarator;
- tree declspecs;
+define_decl (tree declarator, tree declspecs)
{
tree decl = start_decl (declarator, declspecs, 0, NULL_TREE);
finish_decl (decl, NULL_TREE, NULL_TREE);
return decl;
}
-/* Return 1 if LHS and RHS are compatible types for assignment or
- various other operations. Return 0 if they are incompatible, and
- return -1 if we choose to not decide. When the operation is
- REFLEXIVE, check for compatibility in either direction.
-
- For statically typed objects, an assignment of the form `a' = `b'
- is permitted if:
-
- `a' is of type "id",
- `a' and `b' are the same class type, or
- `a' and `b' are of class types A and B such that B is a descendant of A. */
-
+/* Return the first occurrence of a method declaration corresponding
+ to sel_name in rproto_list. Search rproto_list recursively.
+ If is_class is 0, search for instance methods, otherwise for class
+ methods. */
static tree
-lookup_method_in_protocol_list (rproto_list, sel_name, class_meth)
- tree rproto_list;
- tree sel_name;
- int class_meth;
+lookup_method_in_protocol_list (tree rproto_list, tree sel_name,
+ int is_class)
{
tree rproto, p;
tree fnd = 0;
if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
{
- if ((fnd = lookup_method (class_meth
+ 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, class_meth);
+ sel_name, is_class);
}
else
{
}
static tree
-lookup_protocol_in_reflist (rproto_list, lproto)
- tree rproto_list;
- tree lproto;
+lookup_protocol_in_reflist (tree rproto_list, tree lproto)
{
tree rproto, p;
return 0;
}
+/* Return 1 if IDENT is an ObjC/ObjC++ reserved keyword in the context of
+ an '@'. */
+
+int
+objc_is_reserved_word (tree ident)
+{
+ unsigned char code = C_RID_CODE (ident);
+
+ return (OBJC_IS_AT_KEYWORD (code)
+#ifdef OBJCPLUS
+ || code == RID_CLASS || code == RID_PUBLIC
+ || code == RID_PROTECTED || code == RID_PRIVATE
+ || code == RID_TRY || code == RID_THROW || code == RID_CATCH
+#endif
+ );
+}
+
+/* Return true if TYPE is 'id'. */
+
+static bool
+objc_is_object_id (tree type)
+{
+ return OBJC_TYPE_NAME (type) == objc_object_id;
+}
+
+static bool
+objc_is_class_id (tree type)
+{
+ return OBJC_TYPE_NAME (type) == objc_class_id;
+}
+
/* Return 1 if LHS and RHS are compatible types for assignment or
various other operations. Return 0 if they are incompatible, and
return -1 if we choose to not decide (because the types are really
*/
int
-objc_comptypes (lhs, rhs, reflexive)
- tree lhs;
- tree rhs;
- int reflexive;
+objc_comptypes (tree lhs, tree rhs, int reflexive)
{
/* New clause for protocols. */
if (rhs_is_proto)
{
rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
+
if (!reflexive)
{
/* An assignment between objects of type 'id
<Protocol>'; make sure the protocol on the lhs is
supported by the object on the rhs. */
- for (lproto = lproto_list; lproto;
+ for (lproto = lproto_list; lproto;
lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = lookup_protocol_in_reflist (rproto_list, p);
if (!rproto)
- warning
+ warning
("object does not conform to the `%s' protocol",
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
of type 'id <Protocol>'. Check that either the
protocol on the lhs is supported by the object on
the rhs, or viceversa. */
-
+
/* Check if the protocol on the lhs is supported by the
object on the rhs. */
- for (lproto = lproto_list; lproto;
+ for (lproto = lproto_list; lproto;
lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = lookup_protocol_in_reflist (rproto_list, p);
-
+
if (!rproto)
{
/* Check failed - check if the protocol on the rhs
is supported by the object on the lhs. */
- for (rproto = rproto_list; rproto;
+ for (rproto = rproto_list; rproto;
rproto = TREE_CHAIN (rproto))
{
p = TREE_VALUE (rproto);
/* <Protocol> = <class> * */
else if (TYPED_OBJECT (TREE_TYPE (rhs)))
{
- tree rname = TYPE_NAME (TREE_TYPE (rhs));
+ tree rname = OBJC_TYPE_NAME (TREE_TYPE (rhs));
tree rinter;
/* Make sure the protocol is supported by the object on
if (!rproto)
warning ("class `%s' does not implement the `%s' protocol",
- IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
+ IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (rhs))),
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
return 1;
}
/* <Protocol> = id */
- else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id)
+ else if (objc_is_object_id (TREE_TYPE (rhs)))
{
return 1;
}
/* <Protocol> = Class */
- else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id)
+ else if (objc_is_class_id (TREE_TYPE (rhs)))
{
return 0;
}
{
if (reflexive)
{
- tree rname = TYPE_NAME (TREE_TYPE (lhs));
+ tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs));
tree rinter;
tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
+
/* Make sure the protocol is supported by the object on
the lhs. */
- for (rproto = rproto_list; rproto;
+ for (rproto = rproto_list; rproto;
rproto = TREE_CHAIN (rproto))
{
tree p = TREE_VALUE (rproto);
lhs. */
if (!lproto)
{
- lproto_list = TYPE_PROTOCOL_LIST
+ lproto_list = TYPE_PROTOCOL_LIST
(TREE_TYPE (lhs));
- lproto = lookup_protocol_in_reflist
+ lproto = lookup_protocol_in_reflist
(lproto_list, p);
}
p);
cat = CLASS_CATEGORY_LIST (cat);
}
-
- rinter = lookup_interface (CLASS_SUPER_NAME
+
+ rinter = lookup_interface (CLASS_SUPER_NAME
(rinter));
}
-
+
if (!lproto)
warning ("class `%s' does not implement the `%s' protocol",
- IDENTIFIER_POINTER (TYPE_NAME
+ IDENTIFIER_POINTER (OBJC_TYPE_NAME
(TREE_TYPE (lhs))),
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
return 0;
}
/* id = <Protocol> */
- else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id)
+ else if (objc_is_object_id (TREE_TYPE (lhs)))
{
return 1;
}
/* Class = <Protocol> */
- else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id)
+ else if (objc_is_class_id (TREE_TYPE (lhs)))
{
return 0;
}
}
/* `id' = `<class> *' `<class> *' = `id': always allow it.
- Please note that
+ Please note that
'Object *o = [[Object alloc] init]; falls
in the case <class> * = `id'.
*/
- if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs))
- || (TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs)))
+ if ((objc_is_object_id (lhs) && TYPED_OBJECT (rhs))
+ || (objc_is_object_id (rhs) && TYPED_OBJECT (lhs)))
return 1;
/* `id' = `Class', `Class' = `id' */
- else if ((TYPE_NAME (lhs) == objc_object_id
- && TYPE_NAME (rhs) == objc_class_id)
- || (TYPE_NAME (lhs) == objc_class_id
- && TYPE_NAME (rhs) == objc_object_id))
+ else if ((objc_is_object_id (lhs) && objc_is_class_id (rhs))
+ || (objc_is_class_id (lhs) && objc_is_object_id (rhs)))
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))
{
- tree lname = TYPE_NAME (lhs);
- tree rname = TYPE_NAME (rhs);
+ tree lname = OBJC_TYPE_NAME (lhs);
+ tree rname = OBJC_TYPE_NAME (rhs);
tree inter;
if (lname == rname)
return -1;
}
-/* Called from c-decl.c before all calls to rest_of_decl_compilation. */
+/* Called from finish_decl. */
void
-objc_check_decl (decl)
- tree decl;
+objc_check_decl (tree decl)
{
tree type = TREE_TYPE (decl);
- if (TREE_CODE (type) == RECORD_TYPE
- && TREE_STATIC_TEMPLATE (type)
- && type != constant_string_type)
- error_with_decl (decl, "`%s' cannot be statically allocated");
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return;
+ if (OBJC_TYPE_NAME (type) && (type = objc_is_class_name (OBJC_TYPE_NAME (type))))
+ error ("statically allocated instance of Objective-C class `%s'",
+ IDENTIFIER_POINTER (type));
}
/* Implement static typing. At this point, we know we have an interface. */
tree
-get_static_reference (interface, protocols)
- tree interface;
- tree protocols;
+get_static_reference (tree interface, tree protocols)
{
tree type = xref_tag (RECORD_TYPE, interface);
if (protocols)
{
- tree t, m = TYPE_MAIN_VARIANT (type);
-
- t = copy_node (type);
-
- /* Add this type to the chain of variants of TYPE. */
- TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
- TYPE_NEXT_VARIANT (m) = t;
-
+ type = build_variant_type_copy (type);
+
/* Look up protocols and install in lang specific list. Note
that the protocol list can have a different lifetime than T! */
- SET_TYPE_PROTOCOL_LIST (t, lookup_and_install_protocols (protocols));
-
- /* This forces a new pointer type to be created later
- (in build_pointer_type)...so that the new template
- we just created will actually be used...what a hack! */
- if (TYPE_POINTER_TO (t))
- TYPE_POINTER_TO (t) = NULL_TREE;
-
- type = t;
+ SET_TYPE_PROTOCOL_LIST (type, lookup_and_install_protocols (protocols));
}
return type;
}
+/* Return a declaration corresponding to a protocol list qualified 'id'. */
tree
-get_object_reference (protocols)
- tree protocols;
+get_protocol_reference (tree protocols)
{
tree type_decl = lookup_name (objc_id_id);
tree type;
if (type_decl && TREE_CODE (type_decl) == TYPE_DECL)
{
type = TREE_TYPE (type_decl);
- if (TYPE_MAIN_VARIANT (type) != id_type)
+ if (TYPE_MAIN_VARIANT (type) != objc_id_type)
warning ("unexpected type for `id' (%s)",
gen_declaration (type, errbuf));
}
if (protocols)
{
- tree t, m = TYPE_MAIN_VARIANT (type);
-
- t = copy_node (type);
-
- /* Add this type to the chain of variants of TYPE. */
- TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
- TYPE_NEXT_VARIANT (m) = t;
+ type = build_variant_type_copy (type);
/* Look up protocols...and install in lang specific list */
- SET_TYPE_PROTOCOL_LIST (t, lookup_and_install_protocols (protocols));
-
- /* This forces a new pointer type to be created later
- (in build_pointer_type)...so that the new template
- we just created will actually be used...what a hack! */
- if (TYPE_POINTER_TO (t))
- TYPE_POINTER_TO (t) = NULL_TREE;
-
- type = t;
+ SET_TYPE_PROTOCOL_LIST (type, lookup_and_install_protocols (protocols));
}
return type;
}
PROTO, the protocol to check, and LIST, a list of protocol it
conforms to. */
-static void
-check_protocol_recursively (proto, list)
- tree proto;
- tree list;
+static void
+check_protocol_recursively (tree proto, tree list)
{
tree p;
if (pp == proto)
fatal_error ("protocol `%s' has circular dependency",
- IDENTIFIER_POINTER (PROTOCOL_NAME (pp)));
+ IDENTIFIER_POINTER (PROTOCOL_NAME (pp)));
if (pp)
check_protocol_recursively (proto, PROTOCOL_LIST (pp));
}
}
+/* Look up PROTOCOLS, and return a list of those that are found.
+ If none are found, return NULL. */
+
static tree
-lookup_and_install_protocols (protocols)
- tree protocols;
+lookup_and_install_protocols (tree protocols)
{
tree proto;
- tree prev = NULL;
- tree return_value = protocols;
+ tree return_value = NULL_TREE;
for (proto = protocols; proto; proto = TREE_CHAIN (proto))
{
tree p = lookup_protocol (ident);
if (!p)
- {
- error ("cannot find protocol declaration for `%s'",
- IDENTIFIER_POINTER (ident));
- if (prev)
- TREE_CHAIN (prev) = TREE_CHAIN (proto);
- else
- return_value = TREE_CHAIN (proto);
- }
+ error ("cannot find protocol declaration for `%s'",
+ IDENTIFIER_POINTER (ident));
else
- {
- /* Replace identifier with actual protocol node. */
- TREE_VALUE (proto) = p;
- prev = proto;
- }
+ return_value = chainon (return_value,
+ build_tree_list (NULL_TREE, p));
}
return return_value;
TYPE is its data type. */
static tree
-create_builtin_decl (code, type, name)
- enum tree_code code;
- tree type;
- const char *name;
+create_builtin_decl (enum tree_code code, tree type, const char *name)
{
tree decl = build_decl (code, get_identifier (name), type);
if (code == VAR_DECL)
{
TREE_STATIC (decl) = 1;
- make_decl_rtl (decl, 0);
+ make_decl_rtl (decl);
pushdecl (decl);
+ DECL_ARTIFICIAL (decl) = 1;
}
- DECL_ARTIFICIAL (decl) = 1;
return decl;
}
/* Find the decl for the constant string class. */
static void
-setup_string_decl ()
+setup_string_decl (void)
{
if (!string_class_decl)
{
if (!constant_string_global_id)
- constant_string_global_id = get_identifier (STRING_OBJECT_GLOBAL_NAME);
+ {
+ char *name;
+ size_t length;
+ /* %s in format will provide room for terminating null */
+ length = strlen (STRING_OBJECT_GLOBAL_FORMAT)
+ + strlen (constant_string_class_name);
+ name = xmalloc (length);
+ sprintf (name, STRING_OBJECT_GLOBAL_FORMAT,
+ constant_string_class_name);
+ constant_string_global_id = get_identifier (name);
+ }
string_class_decl = lookup_name (constant_string_global_id);
}
}
Model:
- type_spec--------->sc_spec
- (tree_list) (tree_list)
- | |
- | |
- identifier_node identifier_node */
+ type_spec--------->sc_spec
+ (tree_list) (tree_list)
+ | |
+ | |
+ identifier_node identifier_node */
static void
-synth_module_prologue ()
+synth_module_prologue (void)
{
tree temp_type;
- tree super_p;
/* Defined in `objc.h' */
objc_object_id = get_identifier (TAG_OBJECT);
objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id);
- id_type = build_pointer_type (objc_object_reference);
+ objc_id_type = build_pointer_type (objc_object_reference);
objc_id_id = get_identifier (TYPE_ID);
objc_class_id = get_identifier (TAG_CLASS);
objc_class_type = build_pointer_type (xref_tag (RECORD_TYPE, objc_class_id));
- protocol_type = build_pointer_type (xref_tag (RECORD_TYPE,
- get_identifier (PROTOCOL_OBJECT_CLASS_NAME)));
+ temp_type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME);
+ objc_declare_class (tree_cons (NULL_TREE, temp_type, NULL_TREE));
+ objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, temp_type));
/* 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)));
-
- /* Forward declare type, or else the prototype for msgSendSuper will
- complain. */
-
- super_p = build_pointer_type (xref_tag (RECORD_TYPE,
- get_identifier (TAG_SUPER)));
-
+ if (flag_next_runtime)
+ /* `struct objc_selector *' */
+ objc_selector_type
+ = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)));
+ else
+ /* `const struct objc_selector *' */
+ objc_selector_type
+ = build_pointer_type
+ (build_qualified_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)),
+ TYPE_QUAL_CONST));
- /* id objc_msgSend (id, SEL, ...); */
+ /* Declare receiver type used for dispatching messages to 'super'. */
- temp_type
- = build_function_type (id_type,
- tree_cons (NULL_TREE, id_type,
- tree_cons (NULL_TREE, selector_type,
- NULL_TREE)));
+ /* `struct objc_super *' */
+ objc_super_type = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SUPER)));
- 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;
-
- make_decl_rtl (umsg_decl, NULL);
- pushdecl (umsg_decl);
+ /* 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. */
+
+ /* 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 (objc_id_type,
+ tree_cons (NULL_TREE, objc_id_type,
+ tree_cons (NULL_TREE,
+ objc_selector_type,
+ NULL_TREE)));
+ umsg_decl = builtin_function (TAG_MSGSEND,
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ umsg_nonnil_decl = builtin_function (TAG_MSGSEND_NONNIL,
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ umsg_stret_decl = builtin_function (TAG_MSGSEND_STRET,
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ umsg_nonnil_stret_decl = builtin_function (TAG_MSGSEND_NONNIL_STRET,
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+
+ /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
+ /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */
+ temp_type
+ = build_function_type (objc_id_type,
+ tree_cons (NULL_TREE, objc_super_type,
+ tree_cons (NULL_TREE,
+ objc_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,
+ temp_type, 0, NOT_BUILT_IN, 0,
+ NULL_TREE);
}
else
- umsg_decl = builtin_function (TAG_MSGSEND, 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_p,
- tree_cons (NULL_TREE, selector_type,
- NULL_TREE)));
-
- umsg_super_decl = builtin_function (TAG_MSGSENDSUPER,
- temp_type, 0, NOT_BUILT_IN,
- NULL, NULL_TREE);
+ {
+ /* GNU runtime messenger entry points. */
+
+ /* typedef id (*IMP)(id, SEL, ...); */
+ tree IMP_type
+ = build_pointer_type
+ (build_function_type (objc_id_type,
+ tree_cons (NULL_TREE, objc_id_type,
+ tree_cons (NULL_TREE,
+ objc_selector_type,
+ NULL_TREE))));
+
+ /* IMP objc_msg_lookup (id, SEL); */
+ temp_type
+ = build_function_type (IMP_type,
+ tree_cons (NULL_TREE, objc_id_type,
+ tree_cons (NULL_TREE,
+ objc_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, objc_super_type,
+ tree_cons (NULL_TREE,
+ objc_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,
- tree_cons (NULL_TREE, void_type_node,
- NULL_TREE)));
+ temp_type = build_function_type (objc_id_type,
+ tree_cons (NULL_TREE,
+ const_string_type_node,
+ void_list_node));
objc_get_class_decl
= builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN,
/* id objc_getMetaClass (const char *); */
objc_get_meta_class_decl
- = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN,
- NULL, NULL_TREE);
+ = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
+
+ build_super_template ();
+ build_objc_exception_stuff ();
+ if (flag_next_runtime)
+ build_next_objc_exception_stuff ();
/* static SEL _OBJC_SELECTOR_TABLE[]; */
debug_hooks = save_hooks;
}
else
- temp_type = build_array_type (selector_type, NULL_TREE);
+ temp_type = build_array_type (objc_selector_type, NULL_TREE);
layout_type (temp_type);
UOBJC_SELECTOR_TABLE_decl
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;
constant_string_id = get_identifier (constant_string_class_name);
- constant_string_type = xref_tag (RECORD_TYPE, constant_string_id);
+ objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE));
+
+ /* Pre-build the following entities - for speed/convenience. */
+ self_id = get_identifier ("self");
+ ucmd_id = get_identifier ("_cmd");
+#ifndef OBJCPLUS
+ /* The C++ front-end does not appear to grok __attribute__((__unused__)). */
+ unused_list = build_tree_list (get_identifier ("__unused__"), NULL_TREE);
+#endif
}
-/* Predefine the following data type:
+/* Ensure that the ivar list for NSConstantString/NXConstantString
+ (or whatever was specified via `-fconstant-string-class')
+ contains fields at least as large as the following three, so that
+ the runtime can stomp on them with confidence:
- struct STRING_OBJECT_CLASS_NAME
+ struct STRING_OBJECT_CLASS_NAME
{
Object isa;
char *cString;
unsigned int length;
}; */
-static void
-build_string_class_template ()
+static int
+check_string_class_template (void)
{
- tree field_decl, field_decl_chain;
+ tree field_decl = TYPE_FIELDS (constant_string_type);
- field_decl = create_builtin_decl (FIELD_DECL, id_type, "isa");
- field_decl_chain = field_decl;
+#define AT_LEAST_AS_LARGE_AS(F, T) \
+ (F && TREE_CODE (F) == FIELD_DECL \
+ && (TREE_INT_CST_LOW (DECL_SIZE (F)) \
+ >= TREE_INT_CST_LOW (TYPE_SIZE (T))))
- field_decl = create_builtin_decl (FIELD_DECL,
- build_pointer_type (char_type_node),
- "cString");
- chainon (field_decl_chain, field_decl);
+ if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node))
+ return 0;
- field_decl = create_builtin_decl (FIELD_DECL, unsigned_type_node, "length");
- chainon (field_decl_chain, field_decl);
+ field_decl = TREE_CHAIN (field_decl);
+ if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node))
+ return 0;
- finish_struct (constant_string_type, field_decl_chain, NULL_TREE);
+ field_decl = TREE_CHAIN (field_decl);
+ return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node);
+
+#undef AT_LEAST_AS_LARGE_AS
}
+/* Avoid calling `check_string_class_template ()' more than once. */
+static GTY(()) int string_layout_checked;
+
/* Custom build_string which sets TREE_TYPE! */
static tree
-my_build_string (len, str)
- int len;
- const char *str;
+my_build_string (int len, const char *str)
{
return fix_string_type (build_string (len, str));
}
-/* Build a static instance of NXConstantString which points at the
- string constant STRING.
- We place the string object in the __string_objects section of the
- __OBJC segment. The Objective-C runtime will initialize the isa
- pointers of the string objects to point at the NXConstantString
- class object. */
+/* Given a chain of STRING_CST's, build a static instance of
+ NXConstantString which points at the concatenation of those
+ strings. We place the string object in the __string_objects
+ section of the __OBJC segment. The Objective-C runtime will
+ initialize the isa pointers of the string objects to point at the
+ NXConstantString class object. */
tree
-build_objc_string_object (string)
- tree string;
+objc_build_string_object (tree string)
{
- tree initlist, constructor;
+ tree initlist, constructor, constant_string_class;
int length;
+ tree fields;
- if (lookup_interface (constant_string_id) == NULL_TREE)
+ string = fix_string_type (string);
+
+ constant_string_class = lookup_interface (constant_string_id);
+ if (!constant_string_class
+ || !(constant_string_type
+ = CLASS_STATIC_TEMPLATE (constant_string_class)))
{
error ("cannot find interface declaration for `%s'",
IDENTIFIER_POINTER (constant_string_id));
return error_mark_node;
}
- add_class_reference (constant_string_id);
-
+ /* Call to 'combine_strings' has been moved above. */
+ TREE_SET_CODE (string, STRING_CST);
length = TREE_STRING_LENGTH (string) - 1;
- /* We could not properly create NXConstantString in synth_module_prologue,
- because that's called before debugging is initialized. Do it now. */
- if (TYPE_FIELDS (constant_string_type) == NULL_TREE)
- build_string_class_template ();
+ if (!string_layout_checked)
+ {
+ /* The NSConstantString/NXConstantString ivar layout is now
+ known. */
+ if (!check_string_class_template ())
+ {
+ error ("interface `%s' does not have valid constant string layout",
+ IDENTIFIER_POINTER (constant_string_id));
+ return error_mark_node;
+ }
+ 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_cst (NULL_TREE, 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_cst (NULL_TREE, length), initlist);
constructor = objc_build_constructor (constant_string_type,
nreverse (initlist));
= objc_add_static_instance (constructor, constant_string_type);
}
- return (build_unary_op (ADDR_EXPR, constructor, 1));
+ constructor = build_unary_op (ADDR_EXPR, constructor, 1);
+ TREE_CONSTANT (constructor) = true;
+ return constructor;
}
/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */
static GTY(()) int num_static_inst;
+
static tree
-objc_add_static_instance (constructor, class_decl)
- tree constructor, class_decl;
+objc_add_static_instance (tree constructor, tree class_decl)
{
tree *chain, decl;
char buf[256];
if (!*chain)
{
*chain = tree_cons (NULL_TREE, class_decl, NULL_TREE);
- add_objc_string (TYPE_NAME (class_decl), class_names);
+ add_objc_string (OBJC_TYPE_NAME (class_decl), class_names);
}
sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++);
Postpone till end of input. */
DECL_DEFER_OUTPUT (decl) = 1;
pushdecl_top_level (decl);
- rest_of_decl_compilation (decl, 0, 1, 0);
+ rest_of_decl_compilation (decl, 1, 0);
/* Add the DECL to the head of this CLASS' list. */
TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain));
with type TYPE and elements ELTS. */
static tree
-objc_build_constructor (type, elts)
- tree type, elts;
+objc_build_constructor (tree type, tree elts)
{
tree constructor, f, e;
TREE_STATIC (constructor) = 1;
TREE_READONLY (constructor) = 1;
+#ifdef OBJCPLUS
+ /* zlaski 2001-Apr-02: mark this as a call to a constructor, as required by
+ build_unary_op (wasn't true in 2.7.2.1 days) */
+ TREE_HAS_CONSTRUCTOR (constructor) = 1;
+#endif
return constructor;
}
\f
}; */
static void
-build_objc_symtab_template ()
+build_objc_symtab_template (void)
{
- tree field_decl, field_decl_chain, index;
+ tree field_decl, field_decl_chain;
objc_symtab_template
= start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB));
/* SEL *refs; */
field_decl = create_builtin_decl (FIELD_DECL,
- build_pointer_type (selector_type),
+ build_pointer_type (objc_selector_type),
"refs");
chainon (field_decl_chain, field_decl);
"cat_def_cnt");
chainon (field_decl_chain, field_decl);
- /* void *defs[cls_def_cnt + cat_def_cnt]; */
-
- if (!flag_next_runtime)
- index = build_index_type (build_int_2 (imp_count + cat_count, 0));
- else
- index = build_index_type (build_int_2 (imp_count + cat_count - 1,
- imp_count == 0 && cat_count == 0
- ? -1 : 0));
- field_decl = create_builtin_decl (FIELD_DECL,
- build_array_type (ptr_type_node, index),
- "defs");
- chainon (field_decl_chain, field_decl);
+ if (imp_count || cat_count || !flag_next_runtime)
+ {
+ /* void *defs[imp_count + cat_count (+ 1)]; */
+ /* NB: The index is one less than the size of the array. */
+ int index = imp_count + cat_count
+ + (flag_next_runtime? -1: 0);
+ field_decl = create_builtin_decl
+ (FIELD_DECL,
+ build_array_type
+ (ptr_type_node,
+ build_index_type (build_int_cst (NULL_TREE, index))),
+ "defs");
+ chainon (field_decl_chain, field_decl);
+ }
finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE);
}
This is a CONSTRUCTOR. */
static tree
-init_def_list (type)
- tree type;
+init_def_list (tree type)
{
tree expr, initlist = NULL_TREE;
struct imp_entry *impent;
if (static_instances_decl)
expr = build_unary_op (ADDR_EXPR, static_instances_decl, 0);
else
- expr = build_int_2 (0, 0);
+ expr = build_int_cst (NULL_TREE, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
}
/* Construct the initial value for all of _objc_symtab. */
static tree
-init_objc_symtab (type)
- tree type;
+init_objc_symtab (tree type)
{
tree initlist;
/* sel_ref_cnt = { ..., 5, ... } */
- initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
+ initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
/* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
if (flag_next_runtime || ! sel_ref_chain)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
initlist = tree_cons (NULL_TREE,
build_unary_op (ADDR_EXPR,
/* cls_def_cnt = { ..., 5, ... } */
- initlist = tree_cons (NULL_TREE, build_int_2 (imp_count, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, imp_count), initlist);
/* cat_def_cnt = { ..., 5, ... } */
- initlist = tree_cons (NULL_TREE, build_int_2 (cat_count, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, cat_count), initlist);
/* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
- if (imp_count || cat_count || static_instances_decl)
+ if (imp_count || cat_count || !flag_next_runtime)
{
tree field = TYPE_FIELDS (type);
return objc_build_constructor (type, nreverse (initlist));
}
+/* Generate forward declarations for metadata such as
+ 'OBJC_CLASS_...'. */
+
+static tree
+build_metadata_decl (const char *name, tree type)
+{
+ tree decl, decl_specs;
+ /* extern struct TYPE NAME_<name>; */
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]);
+ decl_specs = tree_cons (NULL_TREE, type, decl_specs);
+ decl = define_decl (synth_id_with_class_suffix
+ (name,
+ objc_implementation_context),
+ decl_specs);
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ TREE_PUBLIC (decl) = 0;
+ return decl;
+}
+
/* Push forward-declarations of all the categories so that
init_def_list can use them in a CONSTRUCTOR. */
static void
-forward_declare_categories ()
+forward_declare_categories (void)
{
struct imp_entry *impent;
tree sav = objc_implementation_context;
{
/* Set an invisible arg to synth_id_with_class_suffix. */
objc_implementation_context = impent->imp_context;
- impent->class_decl
- = create_builtin_decl (VAR_DECL, objc_category_template,
- IDENTIFIER_POINTER (synth_id_with_class_suffix ("_OBJC_CATEGORY", objc_implementation_context)));
- TREE_PUBLIC (impent->class_decl) = 0;
+ /* extern struct objc_category _OBJC_CATEGORY_<name>; */
+ impent->class_decl = build_metadata_decl ("_OBJC_CATEGORY",
+ objc_category_template);
}
}
objc_implementation_context = sav;
}
-/* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab'
+/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab'
and initialized appropriately. */
static void
-generate_objc_symtab_decl ()
+generate_objc_symtab_decl (void)
{
tree sc_spec;
}
\f
static tree
-init_module_descriptor (type)
- tree type;
+init_module_descriptor (tree type)
{
tree initlist, expr;
/* version = { 1, ... } */
- expr = build_int_2 (OBJC_VERSION, 0);
+ expr = build_int_cst (NULL_TREE, OBJC_VERSION);
initlist = build_tree_list (NULL_TREE, expr);
/* size = { ..., sizeof (struct objc_module), ... } */
if (UOBJC_SYMBOLS_decl)
expr = build_unary_op (ADDR_EXPR, UOBJC_SYMBOLS_decl, 0);
else
- expr = build_int_2 (0, 0);
+ expr = build_int_cst (NULL_TREE, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
return objc_build_constructor (type, nreverse (initlist));
struct objc_module { ... } _OBJC_MODULE = { ... }; */
static rtx
-build_module_descriptor ()
+build_module_descriptor (void)
{
tree decl_specs, field_decl, field_decl_chain;
/* Mark the decl to avoid "defined but not used" warning. */
DECL_IN_SYSTEM_HEADER (UOBJC_MODULES_decl) = 1;
+
+ mark_decl_referenced (UOBJC_MODULES_decl);
/* Generate a constructor call for the module descriptor.
This code was generated by reading the grammar rules
{
tree parms, execclass_decl, decelerator, void_list_node_1;
- tree init_function_name, init_function_decl;
+ tree init_function_name, init_function_decl, compound;
/* Declare void __objc_execClass (void *); */
get_identifier (TAG_EXECCLASS),
build_function_type (void_type_node,
tree_cons (NULL_TREE, ptr_type_node,
- void_list_node_1)));
+ void_list_node)));
+
DECL_EXTERNAL (execclass_decl) = 1;
DECL_ARTIFICIAL (execclass_decl) = 1;
TREE_PUBLIC (execclass_decl) = 1;
pushdecl (execclass_decl);
- rest_of_decl_compilation (execclass_decl, 0, 0, 0);
+ rest_of_decl_compilation (execclass_decl, 0, 0);
assemble_external (execclass_decl);
/* void _GLOBAL_$I$<gnyf> () {objc_execClass (&L_OBJC_MODULES);} */
start_function (void_list_node_1,
build_nt (CALL_EXPR, init_function_name,
tree_cons (NULL_TREE, NULL_TREE,
- void_list_node_1),
+ void_list_node),
NULL_TREE),
NULL_TREE);
store_parm_decls ();
+ compound = c_begin_compound_stmt (true);
init_function_decl = current_function_decl;
TREE_PUBLIC (init_function_decl) = ! targetm.have_ctors_dtors;
/* Don't let this one be deferred. */
DECL_INLINE (init_function_decl) = 0;
DECL_UNINLINABLE (init_function_decl) = 1;
- current_function_cannot_inline
- = "static constructors and destructors cannot be inlined";
parms
= build_tree_list (NULL_TREE,
build_unary_op (ADDR_EXPR, UOBJC_MODULES_decl, 0));
decelerator = build_function_call (execclass_decl, parms);
- c_expand_expr_stmt (decelerator);
+ add_stmt (decelerator);
+ add_stmt (c_end_compound_stmt (compound, true));
- finish_function (0, 0);
+ finish_function ();
return XEXP (DECL_RTL (init_function_decl), 0);
}
}
-/* extern const char _OBJC_STRINGS[]; */
-
-static void
-generate_forward_declaration_to_string_table ()
-{
- 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
-get_objc_string_decl (ident, section)
- tree ident;
- enum string_section section;
+get_objc_string_decl (tree ident, enum string_section section)
{
tree chain;
for the array built. */
static void
-generate_static_references ()
+generate_static_references (void)
{
tree decls = NULL_TREE, ident, decl_spec, expr_decl, expr = NULL_TREE;
tree class_name, class, decl, initlist;
- tree cl_chain, in_chain, type;
+ tree cl_chain, in_chain;
int num_inst, num_class;
char buf[256];
sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class);
ident = get_identifier (buf);
- expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE, NULL_TREE, NULL_TREE);
decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
build_tree_list (NULL_TREE,
ridpointers[(int) RID_STATIC]));
decl = start_decl (expr_decl, decl_spec, 1, NULL_TREE);
DECL_CONTEXT (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
+ TREE_USED (decl) = 1;
/* Output {class_name, ...}. */
class = TREE_VALUE (cl_chain);
- class_name = get_objc_string_decl (TYPE_NAME (class), class_names);
+ class_name = get_objc_string_decl (OBJC_TYPE_NAME (class), class_names);
initlist = build_tree_list (NULL_TREE,
build_unary_op (ADDR_EXPR, class_name, 1));
}
/* Output {..., NULL}. */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
expr = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist));
finish_decl (decl, expr, NULL_TREE);
- TREE_USED (decl) = 1;
-
- type = build_array_type (build_pointer_type (void_type_node), 0);
- decl = build_decl (VAR_DECL, ident, type);
- TREE_USED (decl) = 1;
- TREE_STATIC (decl) = 1;
decls
= tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, decl, 1), decls);
}
- decls = tree_cons (NULL_TREE, build_int_2 (0, 0), decls);
+ decls = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), decls);
ident = get_identifier ("_OBJC_STATIC_INSTANCES");
- expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE, NULL_TREE, NULL_TREE);
decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
build_tree_list (NULL_TREE,
ridpointers[(int) RID_STATIC]));
expr = objc_build_constructor (TREE_TYPE (static_instances_decl),
nreverse (decls));
finish_decl (static_instances_decl, expr, NULL_TREE);
+ rest_of_decl_compilation (static_instances_decl, 0, 0);
}
/* Output all strings. */
static void
-generate_strings ()
+generate_strings (void)
{
tree sc_spec, decl_specs, expr_decl;
tree chain, string_expr;
sc_spec
= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
- expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+ NULL_TREE, NULL_TREE);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
DECL_CONTEXT (decl) = NULL_TREE;
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
sc_spec
= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
- expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+ NULL_TREE, NULL_TREE);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
DECL_CONTEXT (decl) = NULL_TREE;
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
sc_spec
= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
- expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+ NULL_TREE, NULL_TREE);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
DECL_CONTEXT (decl) = NULL_TREE;
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
}
static GTY(()) int selector_reference_idx;
+
static tree
-build_selector_reference_decl ()
+build_selector_reference_decl (void)
{
tree decl, ident;
char buf[256];
ident = get_identifier (buf);
- decl = build_decl (VAR_DECL, ident, selector_type);
+ decl = build_decl (VAR_DECL, ident, objc_selector_type);
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 0;
TREE_USED (decl) = 1;
- TREE_READONLY (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_CONTEXT (decl) = 0;
- make_decl_rtl (decl, 0);
+ make_decl_rtl (decl);
pushdecl_top_level (decl);
return decl;
/* Just a handy wrapper for add_objc_string. */
static tree
-build_selector (ident)
- tree ident;
+build_selector (tree ident)
{
tree expr = add_objc_string (ident, meth_var_names);
if (flag_typed_selectors)
return expr;
else
- return build_c_cast (selector_type, expr); /* cast! */
+ return build_c_cast (objc_selector_type, expr); /* cast! */
}
static void
-build_selector_translation_table ()
+build_selector_translation_table (void)
{
tree sc_spec, decl_specs;
tree chain, initlist = NULL_TREE;
sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]);
/* static SEL _OBJC_SELECTOR_REFERENCES_n = ...; */
- decl_specs = tree_cons (NULL_TREE, selector_type, sc_spec);
+ decl_specs = tree_cons (NULL_TREE, objc_selector_type, sc_spec);
var_decl = name;
if (flag_next_runtime)
finish_decl (decl, expr, NULL_TREE);
- else
+ else
{
if (flag_typed_selectors)
{
nreverse (eltlist));
}
initlist = tree_cons (NULL_TREE, expr, initlist);
-
+
}
}
DECL_EXTERNAL (UOBJC_SELECTOR_TABLE_decl) = 0;
TREE_STATIC (UOBJC_SELECTOR_TABLE_decl) = 1;
/* NULL terminate the list and fix the decl for output. */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
DECL_INITIAL (UOBJC_SELECTOR_TABLE_decl) = objc_ellipsis_node;
initlist = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl),
nreverse (initlist));
}
static tree
-get_proto_encoding (proto)
- tree proto;
+get_proto_encoding (tree proto)
{
tree encoding;
if (proto)
{
- tree tmp_decl;
-
if (! METHOD_ENCODING (proto))
{
- tmp_decl = build_tmp_function_decl ();
- hack_method_prototype (proto, tmp_decl);
- encoding = encode_method_prototype (proto, tmp_decl);
- METHOD_ENCODING (proto) = encoding;
- }
+ encoding = encode_method_prototype (proto);
+ METHOD_ENCODING (proto) = encoding;
+ }
else
encoding = METHOD_ENCODING (proto);
return add_objc_string (encoding, meth_var_types);
}
else
- return build_int_2 (0, 0);
+ return build_int_cst (NULL_TREE, 0);
}
/* sel_ref_chain is a list whose "value" fields will be instances of
identifier_node that represent the selector. */
static tree
-build_typed_selector_reference (ident, prototype)
- tree ident, prototype;
+build_typed_selector_reference (tree ident, tree prototype)
{
tree *chain = &sel_ref_chain;
tree expr;
return_at_index:
expr = build_unary_op (ADDR_EXPR,
build_array_ref (UOBJC_SELECTOR_TABLE_decl,
- build_int_2 (index, 0)),
+ build_int_cst (NULL_TREE, index)),
1);
- return build_c_cast (selector_type, expr);
+ return build_c_cast (objc_selector_type, expr);
}
static tree
-build_selector_reference (ident)
- tree ident;
+build_selector_reference (tree ident)
{
tree *chain = &sel_ref_chain;
tree expr;
return (flag_next_runtime
? TREE_PURPOSE (*chain)
: build_array_ref (UOBJC_SELECTOR_TABLE_decl,
- build_int_2 (index, 0)));
+ build_int_cst (NULL_TREE, index)));
index++;
chain = &TREE_CHAIN (*chain);
return (flag_next_runtime
? expr
: build_array_ref (UOBJC_SELECTOR_TABLE_decl,
- build_int_2 (index, 0)));
+ build_int_cst (NULL_TREE, index)));
}
static GTY(()) int class_reference_idx;
+
static tree
-build_class_reference_decl ()
+build_class_reference_decl (void)
{
tree decl, ident;
char buf[256];
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 0;
TREE_USED (decl) = 1;
- TREE_READONLY (decl) = 1;
DECL_CONTEXT (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
- make_decl_rtl (decl, 0);
+ make_decl_rtl (decl);
pushdecl_top_level (decl);
return decl;
it. */
static void
-add_class_reference (ident)
- tree ident;
+add_class_reference (tree ident)
{
tree chain;
reference variable. */
tree
-get_class_reference (ident)
- tree ident;
+objc_get_class_reference (tree ident)
{
- if (flag_next_runtime)
+ tree orig_ident;
+
+#ifdef OBJCPLUS
+ if (processing_template_decl)
+ /* Must wait until template instantiation time. */
+ return build_min_nt (CLASS_REFERENCE_EXPR, ident);
+ if (TREE_CODE (ident) == TYPE_DECL)
+ ident = DECL_NAME (ident);
+#endif
+ orig_ident = ident;
+
+ if (!(ident = objc_is_class_name (ident)))
+ {
+ error ("`%s' is not an Objective-C class name or alias",
+ IDENTIFIER_POINTER (orig_ident));
+ return error_mark_node;
+ }
+
+ if (flag_next_runtime && !flag_zero_link)
{
tree *chain;
tree decl;
to decls for the strings. */
static tree
-add_objc_string (ident, section)
- tree ident;
- enum string_section section;
+add_objc_string (tree ident, enum string_section section)
{
tree *chain, decl;
static GTY(()) int meth_var_types_idx;
static tree
-build_objc_string_decl (section)
- enum string_section section;
+build_objc_string_decl (enum string_section section)
{
tree decl, ident;
char buf[256];
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 0;
TREE_USED (decl) = 1;
- TREE_READONLY (decl) = 1;
TREE_CONSTANT (decl) = 1;
DECL_CONTEXT (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
-
- make_decl_rtl (decl, 0);
+
+ make_decl_rtl (decl);
pushdecl_top_level (decl);
return decl;
void
-objc_declare_alias (alias_ident, class_ident)
- tree alias_ident;
- tree class_ident;
+objc_declare_alias (tree alias_ident, tree class_ident)
{
- if (is_class_name (class_ident) != class_ident)
+ tree underlying_class;
+
+#ifdef OBJCPLUS
+ if (current_namespace != global_namespace) {
+ error ("Objective-C declarations may only appear in global scope");
+ }
+#endif /* OBJCPLUS */
+
+ if (!(underlying_class = objc_is_class_name (class_ident)))
warning ("cannot find class `%s'", IDENTIFIER_POINTER (class_ident));
- else if (is_class_name (alias_ident))
+ else if (objc_is_class_name (alias_ident))
warning ("class `%s' already exists", IDENTIFIER_POINTER (alias_ident));
else
- alias_chain = tree_cons (class_ident, alias_ident, alias_chain);
+ alias_chain = tree_cons (underlying_class, alias_ident, alias_chain);
}
void
-objc_declare_class (ident_list)
- tree ident_list;
+objc_declare_class (tree ident_list)
{
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))
{
tree ident = TREE_VALUE (list);
- tree decl;
- if ((decl = lookup_name (ident)))
+ if (! objc_is_class_name (ident))
{
- error ("`%s' redeclared as different kind of symbol",
- IDENTIFIER_POINTER (ident));
- error_with_decl (decl, "previous declaration of `%s'");
- }
+ tree record = lookup_name (ident);
+
+ if (record && ! TREE_STATIC_TEMPLATE (record))
+ {
+ error ("`%s' redeclared as different kind of symbol",
+ IDENTIFIER_POINTER (ident));
+ error ("%Jprevious declaration of '%D'",
+ record, record);
+ }
- if (! is_class_name (ident))
- {
- tree record = xref_tag (RECORD_TYPE, ident);
+ record = xref_tag (RECORD_TYPE, ident);
TREE_STATIC_TEMPLATE (record) = 1;
class_chain = tree_cons (NULL_TREE, ident, class_chain);
}
}
tree
-is_class_name (ident)
- tree ident;
+objc_is_class_name (tree ident)
{
tree chain;
+ if (ident && TREE_CODE (ident) == IDENTIFIER_NODE
+ && identifier_global_value (ident))
+ ident = identifier_global_value (ident);
+ while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident))
+ ident = TYPE_NAME (DECL_ORIGINAL_TYPE (ident));
+
+#ifdef OBJCPLUS
+ if (ident && TREE_CODE (ident) == RECORD_TYPE)
+ ident = TYPE_NAME (ident);
+ if (ident && TREE_CODE (ident) == TYPE_DECL)
+ ident = DECL_NAME (ident);
+#endif
+ if (!ident || TREE_CODE (ident) != IDENTIFIER_NODE)
+ return NULL_TREE;
+
if (lookup_interface (ident))
return ident;
return 0;
}
+/* Check whether TYPE is either 'id', 'Class', or a pointer to an ObjC
+ class instance. This is needed by other parts of the compiler to
+ handle ObjC types gracefully. */
+
tree
-objc_is_id (ident)
- tree ident;
+objc_is_object_ptr (tree type)
{
- /* NB: This function may be called before the ObjC front-end
- has been initialized, in which case ID_TYPE will be NULL. */
- return (id_type && ident && TYPE_P (ident) && IS_ID (ident))
- ? id_type
- : NULL_TREE;
+ type = TYPE_MAIN_VARIANT (type);
+ if (!type || TREE_CODE (type) != POINTER_TYPE)
+ return 0;
+ /* NB: This function may be called before the ObjC front-end has
+ been initialized, in which case OBJC_ID_TYPE will be NULL. */
+ if (objc_id_type && type && TYPE_P (type)
+ && (IS_ID (type)
+ || TREE_TYPE (type) == TREE_TYPE (objc_class_type)))
+ return type;
+ return objc_is_class_name (OBJC_TYPE_NAME (TREE_TYPE (type)));
}
-tree
-lookup_interface (ident)
- tree ident;
+static tree
+lookup_interface (tree ident)
{
tree chain;
+#ifdef OBJCPLUS
+ if (ident && TREE_CODE (ident) == TYPE_DECL)
+ ident = DECL_NAME (ident);
+#endif
for (chain = interface_chain; chain; chain = TREE_CHAIN (chain))
{
if (ident == CLASS_NAME (chain))
- return chain;
+ return chain;
}
return NULL_TREE;
}
+/* Implement @defs (<classname>) within struct bodies. */
+
+tree
+objc_get_class_ivars (tree class_name)
+{
+ tree interface = lookup_interface (class_name);
+ tree field, fields = NULL_TREE;
+
+ if (interface)
+ {
+ tree raw_ivar = get_class_ivars (interface, 1);
+
+ /* Regenerate the FIELD_DECLs for the enclosing struct. */
+ for (; raw_ivar; raw_ivar = TREE_CHAIN (raw_ivar))
+ {
+ field = grokfield (TREE_PURPOSE (TREE_VALUE (raw_ivar)),
+ TREE_PURPOSE (raw_ivar),
+ TREE_VALUE (TREE_VALUE (raw_ivar)));
+#ifdef OBJCPLUS
+ finish_member_declaration (field);
+#else
+ fields = chainon (fields, field);
+#endif
+ }
+ }
+ else
+ error ("cannot find interface declaration for `%s'",
+ IDENTIFIER_POINTER (class_name));
+
+ return fields;
+}
+
/* Used by: build_private_template, continue_class,
and for @defs constructs. */
-tree
-get_class_ivars (interface)
- tree interface;
+static tree
+get_class_ivars (tree interface, int raw)
{
tree my_name, super_name, ivar_chain;
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);
- ivar_chain = CLASS_IVARS (interface);
-
- /* Save off a pristine copy of the leaf ivars (i.e, those not
- inherited from a super class). */
- if (!CLASS_OWN_IVARS (interface))
- CLASS_OWN_IVARS (interface) = copy_list (ivar_chain);
+ if (raw)
+ ivar_chain = CLASS_RAW_IVARS (interface);
+ else
+ {
+ ivar_chain = CLASS_IVARS (interface);
+ /* Save off a pristine copy of the leaf ivars (i.e, those not
+ inherited from a super class). */
+ if (!CLASS_OWN_IVARS (interface))
+ CLASS_OWN_IVARS (interface) = copy_list (ivar_chain);
+ }
while (super_name)
{
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);
- op1 = CLASS_OWN_IVARS (interface);
+ op1 = (raw ? CLASS_RAW_IVARS (interface) : CLASS_OWN_IVARS (interface));
if (op1)
{
tree head = copy_list (op1);
ivar_chain = head;
}
}
+
return ivar_chain;
}
-/* struct <classname> {
- struct objc_class *isa;
- ...
- }; */
-
static tree
-build_private_template (class)
- tree class;
+objc_create_temporary_var (tree type)
{
- tree ivar_context;
+ tree decl;
+
+ decl = build_decl (VAR_DECL, NULL_TREE, type);
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_CONTEXT (decl) = current_function_decl;
- if (CLASS_STATIC_TEMPLATE (class))
- {
- uprivate_record = CLASS_STATIC_TEMPLATE (class);
- ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class));
- }
- else
- {
- uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));
+ 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
+ we're doing "native" exception handling or legacy Darwin setjmp exceptions.
+ We abstract all of this in a handful of appropriately named routines. */
- ivar_context = get_class_ivars (class);
+/* Stack of open try blocks. */
- finish_struct (uprivate_record, ivar_context, NULL_TREE);
+struct objc_try_context
+{
+ struct objc_try_context *outer;
- CLASS_STATIC_TEMPLATE (class) = uprivate_record;
+ /* Statements (or statement lists) as processed by the parser. */
+ tree try_body;
+ tree finally_body;
- /* mark this record as class template - for class type checking */
- TREE_STATIC_TEMPLATE (uprivate_record) = 1;
- }
+ /* Some file position locations. */
+ location_t try_locus;
+ location_t end_try_locus;
+ location_t end_catch_locus;
+ location_t finally_locus;
+ location_t end_finally_locus;
- instance_type
- = groktypename (build_tree_list (build_tree_list (NULL_TREE,
- uprivate_record),
- build1 (INDIRECT_REF, NULL_TREE,
- NULL_TREE)));
+ /* A STATEMENT_LIST of CATCH_EXPRs, appropriate for sticking into op1
+ of a TRY_CATCH_EXPR. Even when doing Darwin setjmp. */
+ tree catch_list;
- return ivar_context;
-}
-\f
-/* Begin code generation for protocols... */
+ /* The CATCH_EXPR of an open @catch clause. */
+ tree current_catch;
-/* struct objc_protocol {
- char *protocol_name;
- struct objc_protocol **protocol_list;
- struct objc_method_desc *instance_methods;
- struct objc_method_desc *class_methods;
- }; */
+ /* The VAR_DECL holding the Darwin equivalent of EXC_PTR_EXPR. */
+ tree caught_decl;
+ tree stack_decl;
+ tree rethrow_decl;
+};
+
+static struct objc_try_context *cur_try_context;
+
+/* This hook, called via lang_eh_runtime_type, generates a runtime object
+ that represents TYPE. For Objective-C, this is just the class name. */
+/* ??? Isn't there a class object or some such? Is it easy to get? */
static tree
-build_protocol_template ()
+objc_eh_runtime_type (tree type)
{
- tree decl_specs, field_decl, field_decl_chain;
- tree template;
+ return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
+}
- template = start_struct (RECORD_TYPE, get_identifier (UTAG_PROTOCOL));
+/* Initialize exception handling. */
- /* struct objc_class *isa; */
+static void
+objc_init_exceptions (void)
+{
+ static bool done = false;
+ if (done)
+ return;
+ done = true;
- decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
- get_identifier (UTAG_CLASS)));
+ /* Why? */
+ if (!flag_objc_exceptions)
+ warning ("use %<-fobjc-exceptions%> to enable Objective-C "
+ "exception syntax");
+
+ if (!flag_objc_sjlj_exceptions)
+ {
+ c_eh_initialized_p = true;
+ eh_personality_libfunc
+ = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ ? "__gnu_objc_personality_sj0"
+ : "__gnu_objc_personality_v0");
+ using_eh_for_cleanups ();
+ lang_eh_runtime_type = objc_eh_runtime_type;
+ }
+}
+
+/* Build an EXC_PTR_EXPR, or the moral equivalent. In the case of Darwin,
+ we'll arrange for it to be initialized (and associated with a binding)
+ later. */
+
+static tree
+objc_build_exc_ptr (void)
+{
+ if (flag_objc_sjlj_exceptions)
+ {
+ tree var = cur_try_context->caught_decl;
+ if (!var)
+ {
+ var = objc_create_temporary_var (objc_id_type);
+ cur_try_context->caught_decl = var;
+ }
+ return var;
+ }
+ else
+ return build (EXC_PTR_EXPR, objc_id_type);
+}
+
+/* Build "objc_exception_try_exit(&_stack)". */
+
+static tree
+next_sjlj_build_try_exit (void)
+{
+ tree t;
+ t = build_fold_addr_expr (cur_try_context->stack_decl);
+ t = tree_cons (NULL, t, NULL);
+ t = build_function_call (objc_exception_try_exit_decl, t);
+ return t;
+}
+
+/* Build
+ objc_exception_try_enter (&_stack);
+ if (_setjmp(&_stack.buf))
+ ;
+ else
+ ;
+ Return the COND_EXPR. Note that the THEN and ELSE fields are left
+ empty, ready for the caller to fill them in. */
+
+static tree
+next_sjlj_build_enter_and_setjmp (void)
+{
+ tree t, enter, sj, cond;
+
+ t = build_fold_addr_expr (cur_try_context->stack_decl);
+ t = tree_cons (NULL, t, NULL);
+ enter = build_function_call (objc_exception_try_enter_decl, t);
+
+ t = build_component_ref (cur_try_context->stack_decl,
+ get_identifier ("buf"));
+ t = build_fold_addr_expr (t);
+ t = convert (ptr_type_node, t);
+ t = tree_cons (NULL, t, NULL);
+ sj = build_function_call (objc_setjmp_decl, t);
+
+ cond = build (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj);
+ cond = lang_hooks.truthvalue_conversion (cond);
+
+ return build (COND_EXPR, void_type_node, cond, NULL, NULL);
+}
+
+/* Build
+ DECL = objc_exception_extract(&_stack);
+*/
+
+static tree
+next_sjlj_build_exc_extract (tree decl)
+{
+ tree t;
+
+ t = build_fold_addr_expr (cur_try_context->stack_decl);
+ t = tree_cons (NULL, t, NULL);
+ t = build_function_call (objc_exception_extract_decl, t);
+ t = convert (TREE_TYPE (decl), t);
+ t = build (MODIFY_EXPR, void_type_node, decl, t);
+
+ return t;
+}
+
+/* Build
+ if (objc_exception_match(obj_get_class(TYPE), _caught)
+ BODY
+ else if (...)
+ ...
+ else
+ {
+ _rethrow = _caught;
+ objc_exception_try_exit(&_stack);
+ }
+ from the sequence of CATCH_EXPRs in the current try context. */
+
+static tree
+next_sjlj_build_catch_list (void)
+{
+ tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
+ tree catch_seq, t;
+ tree *last = &catch_seq;
+ bool saw_id = false;
+
+ for (; !tsi_end_p (i); tsi_next (&i))
+ {
+ tree stmt = tsi_stmt (i);
+ tree type = CATCH_TYPES (stmt);
+ tree body = CATCH_BODY (stmt);
+
+ if (type == NULL)
+ {
+ *last = body;
+ saw_id = true;
+ break;
+ }
+ else
+ {
+ tree args, cond;
+
+ if (type == error_mark_node)
+ cond = error_mark_node;
+ else
+ {
+ args = tree_cons (NULL, cur_try_context->caught_decl, NULL);
+ t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type)));
+ args = tree_cons (NULL, t, args);
+ t = build_function_call (objc_exception_match_decl, args);
+ cond = lang_hooks.truthvalue_conversion (t);
+ }
+ t = build (COND_EXPR, void_type_node, cond, body, NULL);
+ SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
+
+ *last = t;
+ last = &COND_EXPR_ELSE (t);
+ }
+ }
+
+ if (!saw_id)
+ {
+ t = build (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl,
+ cur_try_context->caught_decl);
+ annotate_with_locus (t, cur_try_context->end_catch_locus);
+ append_to_statement_list (t, last);
+
+ t = next_sjlj_build_try_exit ();
+ annotate_with_locus (t, cur_try_context->end_catch_locus);
+ append_to_statement_list (t, last);
+ }
+
+ return catch_seq;
+}
+
+/* Build a complete @try-@catch-@finally block for legacy Darwin setjmp
+ exception handling. We aim to build:
+
+ {
+ struct _objc_exception_data _stack;
+ id volatile _rethrow = 0;
+ try
+ {
+ objc_exception_try_enter (&_stack);
+ if (_setjmp(&_stack.buf))
+ {
+ id _caught = objc_exception_extract(&_stack);
+ objc_exception_try_enter (&_stack);
+ if (_setjmp(&_stack.buf))
+ _rethrow = objc_exception_extract(&_stack);
+ else
+ CATCH-LIST
+ }
+ else
+ TRY-BLOCK
+ }
+ finally
+ {
+ if (!_rethrow)
+ objc_exception_try_exit(&_stack);
+ FINALLY-BLOCK
+ if (_rethrow)
+ objc_exception_throw(_rethrow);
+ }
+ }
+
+ If CATCH-LIST is empty, we can omit all of the block containing
+ "_caught" except for the setting of _rethrow. Note the use of
+ a real TRY_FINALLY_EXPR here, which is not involved in EH per-se,
+ but handles goto and other exits from the block. */
+
+static tree
+next_sjlj_build_try_catch_finally (void)
+{
+ tree rethrow_decl, stack_decl, t;
+ tree catch_seq, try_fin, bind;
+
+ /* Create the declarations involved. */
+ t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
+ stack_decl = objc_create_temporary_var (t);
+ cur_try_context->stack_decl = stack_decl;
+
+ rethrow_decl = objc_create_temporary_var (objc_id_type);
+ cur_try_context->rethrow_decl = rethrow_decl;
+ TREE_THIS_VOLATILE (rethrow_decl) = 1;
+ TREE_CHAIN (rethrow_decl) = stack_decl;
+
+ /* Build the outermost varible binding level. */
+ bind = build (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL);
+ annotate_with_locus (bind, cur_try_context->try_locus);
+ TREE_SIDE_EFFECTS (bind) = 1;
+
+ /* Initialize rethrow_decl. */
+ t = build (MODIFY_EXPR, void_type_node, rethrow_decl,
+ convert (objc_id_type, null_pointer_node));
+ annotate_with_locus (t, cur_try_context->try_locus);
+ append_to_statement_list (t, &BIND_EXPR_BODY (bind));
+
+ /* Build the outermost TRY_FINALLY_EXPR. */
+ try_fin = build (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
+ annotate_with_locus (try_fin, cur_try_context->try_locus);
+ TREE_SIDE_EFFECTS (try_fin) = 1;
+ append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind));
+
+ /* Create the complete catch sequence. */
+ if (cur_try_context->catch_list)
+ {
+ tree caught_decl = objc_build_exc_ptr ();
+ catch_seq = build_stmt (BIND_EXPR, caught_decl, NULL, NULL);
+
+ t = next_sjlj_build_exc_extract (caught_decl);
+ append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
+
+ t = next_sjlj_build_enter_and_setjmp ();
+ COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (rethrow_decl);
+ COND_EXPR_ELSE (t) = next_sjlj_build_catch_list ();
+ append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
+ }
+ else
+ catch_seq = next_sjlj_build_exc_extract (rethrow_decl);
+ annotate_with_locus (catch_seq, cur_try_context->end_try_locus);
+
+ /* Build the main register-and-try if statement. */
+ t = next_sjlj_build_enter_and_setjmp ();
+ annotate_with_locus (t, cur_try_context->try_locus);
+ COND_EXPR_THEN (t) = catch_seq;
+ COND_EXPR_ELSE (t) = cur_try_context->try_body;
+ TREE_OPERAND (try_fin, 0) = t;
+
+ /* Build the complete FINALLY statement list. */
+ t = next_sjlj_build_try_exit ();
+ t = build_stmt (COND_EXPR,
+ lang_hooks.truthvalue_conversion (rethrow_decl),
+ NULL, t);
+ annotate_with_locus (t, cur_try_context->finally_locus);
+ append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
+
+ append_to_statement_list (cur_try_context->finally_body,
+ &TREE_OPERAND (try_fin, 1));
+
+ t = tree_cons (NULL, rethrow_decl, NULL);
+ t = build_function_call (objc_exception_throw_decl, t);
+ t = build_stmt (COND_EXPR,
+ lang_hooks.truthvalue_conversion (rethrow_decl),
+ t, NULL);
+ annotate_with_locus (t, cur_try_context->end_finally_locus);
+ append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
+
+ return bind;
+}
+
+/* Called just after parsing the @try and its associated BODY. We now
+ must prepare for the tricky bits -- handling the catches and finally. */
+
+void
+objc_begin_try_stmt (location_t try_locus, tree body)
+{
+ struct objc_try_context *c = xcalloc (1, sizeof (*c));
+ c->outer = cur_try_context;
+ c->try_body = body;
+ c->try_locus = try_locus;
+ c->end_try_locus = input_location;
+ cur_try_context = c;
+
+ objc_init_exceptions ();
+}
+
+/* Called just after parsing "@catch (parm)". Open a binding level,
+ enter PARM into the binding level, and initialize it. Leave the
+ binding level open while the body of the compound statement is parsed. */
+
+void
+objc_begin_catch_clause (tree parm)
+{
+ tree compound, decl, type, t;
+
+ /* Begin a new scope that the entire catch clause will live in. */
+ compound = c_begin_compound_stmt (1);
+
+ /* Turn the raw declarator/declspecs into a decl in the current scope. */
+ decl = define_decl (TREE_VALUE (TREE_PURPOSE (parm)),
+ TREE_PURPOSE (TREE_PURPOSE (parm)));
+
+ /* 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;
+
+ /* 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);
+ 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)))
+ {
+ error ("@catch parameter is not a known Objective-C class type");
+ type = error_mark_node;
+ }
+ else if (cur_try_context->catch_list)
+ {
+ /* 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))
+ {
+ tree stmt = tsi_stmt (i);
+ t = CATCH_TYPES (stmt);
+ if (t == error_mark_node)
+ continue;
+ if (!t || objc_comptypes (TREE_TYPE (t), TREE_TYPE (type), 0) == 1)
+ {
+ warning ("exception of type %<%T%> will be caught",
+ TREE_TYPE (type));
+ warning ("%H by earlier handler for %<%T%>",
+ EXPR_LOCUS (stmt), TREE_TYPE (t ? t : objc_id_type));
+ break;
+ }
+ }
+ }
+
+ /* Record the data for the catch in the try context so that we can
+ finalize it later. */
+ t = build_stmt (CATCH_EXPR, type, compound);
+ cur_try_context->current_catch = t;
+
+ /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */
+ t = objc_build_exc_ptr ();
+ t = convert (TREE_TYPE (decl), t);
+ t = build (MODIFY_EXPR, void_type_node, decl, t);
+ add_stmt (t);
+}
+
+/* Called just after parsing the closing brace of a @catch clause. Close
+ the open binding level, and record a CATCH_EXPR for it. */
+
+void
+objc_finish_catch_clause (void)
+{
+ tree c = cur_try_context->current_catch;
+ cur_try_context->current_catch = NULL;
+ cur_try_context->end_catch_locus = input_location;
+
+ CATCH_BODY (c) = c_end_compound_stmt (CATCH_BODY (c), 1);
+ append_to_statement_list (c, &cur_try_context->catch_list);
+}
+
+/* Called after parsing a @finally clause and its associated BODY.
+ Record the body for later placement. */
+
+void
+objc_build_finally_clause (location_t finally_locus, tree body)
+{
+ cur_try_context->finally_body = body;
+ cur_try_context->finally_locus = finally_locus;
+ cur_try_context->end_finally_locus = input_location;
+}
+
+/* Called to finalize a @try construct. */
+
+void
+objc_finish_try_stmt (void)
+{
+ struct objc_try_context *c = cur_try_context;
+ tree stmt;
+
+ if (c->catch_list == NULL && c->finally_body == NULL)
+ error ("`@try' without `@catch' or `@finally'");
+
+ /* If we're doing Darwin setjmp exceptions, build the big nasty. */
+ if (flag_objc_sjlj_exceptions)
+ {
+ if (!cur_try_context->finally_body)
+ {
+ cur_try_context->finally_locus = input_location;
+ cur_try_context->end_finally_locus = input_location;
+ }
+ stmt = next_sjlj_build_try_catch_finally ();
+ }
+ else
+ {
+ /* Otherwise, nest the CATCH inside a FINALLY. */
+ stmt = c->try_body;
+ if (c->catch_list)
+ {
+ stmt = build_stmt (TRY_CATCH_EXPR, stmt, c->catch_list);
+ annotate_with_locus (stmt, cur_try_context->try_locus);
+ }
+ if (c->finally_body)
+ {
+ stmt = build_stmt (TRY_FINALLY_EXPR, stmt, c->finally_body);
+ annotate_with_locus (stmt, cur_try_context->try_locus);
+ }
+ }
+ add_stmt (stmt);
+
+ cur_try_context = c->outer;
+ free (c);
+}
+
+tree
+objc_build_throw_stmt (tree throw_expr)
+{
+ tree args;
+
+ objc_init_exceptions ();
+
+ if (throw_expr == NULL)
+ {
+ /* If we're not inside a @catch block, there is no "current
+ exception" to be rethrown. */
+ if (cur_try_context == NULL
+ || cur_try_context->current_catch == NULL)
+ {
+ error ("%<@throw%> (rethrow) used outside of a @catch block");
+ return NULL_TREE;
+ }
+
+ /* Otherwise the object is still sitting in the EXC_PTR_EXPR
+ value that we get from the runtime. */
+ throw_expr = objc_build_exc_ptr ();
+ }
+
+ /* A throw is just a call to the runtime throw function with the
+ object as a parameter. */
+ args = tree_cons (NULL, throw_expr, NULL);
+ return add_stmt (build_function_call (objc_exception_throw_decl, args));
+}
+
+void
+objc_build_synchronized (location_t start_locus, tree mutex, tree body)
+{
+ tree args, call;
+
+ /* First lock the mutex. */
+ mutex = save_expr (mutex);
+ args = tree_cons (NULL, mutex, NULL);
+ call = build_function_call (objc_sync_enter_decl, args);
+ annotate_with_locus (call, start_locus);
+ add_stmt (call);
+
+ /* Build the mutex unlock. */
+ args = tree_cons (NULL, mutex, NULL);
+ call = build_function_call (objc_sync_exit_decl, args);
+ annotate_with_locus (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);
+ objc_finish_try_stmt ();
+}
+
+\f
+/* Predefine the following data type:
+
+ struct _objc_exception_data
+ {
+ int buf[_JBLEN];
+ void *pointers[4];
+ }; */
+
+/* The following yuckiness should prevent users from having to #include
+ <setjmp.h> in their code... */
+
+#ifdef TARGET_POWERPC
+/* snarfed from /usr/include/ppc/setjmp.h */
+#define _JBLEN (26 + 36 + 129 + 1)
+#else
+/* snarfed from /usr/include/i386/{setjmp,signal}.h */
+#define _JBLEN 18
+#endif
+
+static void
+build_next_objc_exception_stuff (void)
+{
+ tree field_decl, field_decl_chain, index, temp_type;
+
+ /* Suppress outputting debug symbols, because
+ dbxout_init hasn't been called yet. */
+ enum debug_info_type save_write_symbols = write_symbols;
+ const struct gcc_debug_hooks *save_hooks = debug_hooks;
+
+ write_symbols = NO_DEBUG;
+ debug_hooks = &do_nothing_debug_hooks;
+
+ objc_exception_data_template
+ = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
+
+ /* int buf[_JBLEN]; */
+
+ index = build_index_type (build_int_cst (NULL_TREE, _JBLEN - 1));
+ field_decl = create_builtin_decl (FIELD_DECL,
+ build_array_type (integer_type_node, index),
+ "buf");
+ field_decl_chain = field_decl;
+
+ /* void *pointers[4]; */
+
+ index = build_index_type (build_int_cst (NULL_TREE, 4 - 1));
+ field_decl = create_builtin_decl (FIELD_DECL,
+ build_array_type (ptr_type_node, index),
+ "pointers");
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_exception_data_template, field_decl_chain, NULL_TREE);
+
+ /* int _setjmp(...); */
+ /* 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
+ = builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
+
+ /* id objc_exception_extract(struct _objc_exception_data *); */
+ temp_type
+ = build_function_type (objc_id_type,
+ tree_cons (NULL_TREE,
+ build_pointer_type (objc_exception_data_template),
+ 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 *); */
+ /* void objc_exception_try_exit(struct _objc_exception_data *); */
+ temp_type
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE,
+ build_pointer_type (objc_exception_data_template),
+ 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
+ = builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
+
+ /* int objc_exception_match(id, id); */
+ temp_type
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, objc_id_type,
+ tree_cons (NULL_TREE, objc_id_type,
+ void_list_node)));
+ objc_exception_match_decl
+ = builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
+
+ write_symbols = save_write_symbols;
+ debug_hooks = save_hooks;
+}
+
+static void
+build_objc_exception_stuff (void)
+{
+ tree noreturn_list, nothrow_list, temp_type;
+
+ noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL);
+ nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL);
+
+ /* void objc_exception_throw(id) __attribute__((noreturn)); */
+ /* void objc_sync_enter(id); */
+ /* void objc_sync_exit(id); */
+ temp_type = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, objc_id_type,
+ void_list_node));
+ objc_exception_throw_decl
+ = builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL,
+ noreturn_list);
+ objc_sync_enter_decl
+ = builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN,
+ NULL, nothrow_list);
+ objc_sync_exit_decl
+ = builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN,
+ NULL, nothrow_list);
+}
+
+
+/* struct <classname> {
+ struct objc_class *isa;
+ ...
+ }; */
+
+static tree
+build_private_template (tree class)
+{
+ tree ivar_context;
+
+ if (CLASS_STATIC_TEMPLATE (class))
+ {
+ uprivate_record = CLASS_STATIC_TEMPLATE (class);
+ ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class));
+ }
+ else
+ {
+ uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));
+ ivar_context = get_class_ivars (class, 0);
+
+ finish_struct (uprivate_record, ivar_context, NULL_TREE);
+
+ CLASS_STATIC_TEMPLATE (class) = uprivate_record;
+
+ /* mark this record as class template - for class type checking */
+ TREE_STATIC_TEMPLATE (uprivate_record) = 1;
+ }
+
+ objc_instance_type
+ = groktypename (build_tree_list (build_tree_list (NULL_TREE,
+ uprivate_record),
+ build1 (INDIRECT_REF, NULL_TREE,
+ NULL_TREE)));
+
+ return ivar_context;
+}
+\f
+/* Begin code generation for protocols... */
+
+/* struct objc_protocol {
+ char *protocol_name;
+ struct objc_protocol **protocol_list;
+ struct objc_method_desc *instance_methods;
+ struct objc_method_desc *class_methods;
+ }; */
+
+static tree
+build_protocol_template (void)
+{
+ tree decl_specs, field_decl, field_decl_chain;
+ tree template;
+
+ template = start_struct (RECORD_TYPE, get_identifier (UTAG_PROTOCOL));
+
+ /* struct objc_class *isa; */
+
+ decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_CLASS)));
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa"));
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
}
static tree
-build_descriptor_table_initializer (type, entries)
- tree type;
- tree entries;
+build_descriptor_table_initializer (tree type, tree entries)
{
tree initlist = NULL_TREE;
/* struct objc_method_prototype_list {
int count;
struct objc_method_prototype {
- SEL name;
- char *types;
+ SEL name;
+ char *types;
} list[1];
}; */
static tree
-build_method_prototype_list_template (list_type, size)
- tree list_type;
- int size;
+build_method_prototype_list_template (tree list_type, int size)
{
tree objc_ivar_list_record;
tree decl_specs, field_decl, field_decl_chain;
decl_specs = build_tree_list (NULL_TREE, list_type);
field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
- build_int_2 (size, 0));
+ build_int_cst (NULL_TREE, size), NULL_TREE, NULL_TREE);
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
}
static tree
-build_method_prototype_template ()
+build_method_prototype_template (void)
{
tree proto_record;
tree decl_specs, field_decl, field_decl_chain;
return proto_record;
}
-/* True if last call to forwarding_offset yielded a register offset. */
-static int offset_is_register;
+static tree
+objc_method_parm_type (tree type)
+{
+ type = groktypename (TREE_TYPE (type));
+ if (TREE_CODE (type) == TYPE_DECL)
+ type = TREE_TYPE (type);
+ return TYPE_MAIN_VARIANT (type);
+}
static int
-forwarding_offset (parm)
- tree parm;
+objc_encoded_type_size (tree type)
{
- int offset_in_bytes;
-
- if (GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
- {
- rtx addr = XEXP (DECL_INCOMING_RTL (parm), 0);
-
- /* ??? Here we assume that the parm address is indexed
- off the frame pointer or arg pointer.
- If that is not true, we produce meaningless results,
- but do not crash. */
- if (GET_CODE (addr) == PLUS
- && GET_CODE (XEXP (addr, 1)) == CONST_INT)
- offset_in_bytes = INTVAL (XEXP (addr, 1));
- else
- offset_in_bytes = 0;
-
- offset_in_bytes += OBJC_FORWARDING_STACK_OFFSET;
- offset_is_register = 0;
- }
- else if (GET_CODE (DECL_INCOMING_RTL (parm)) == REG)
- {
- int regno = REGNO (DECL_INCOMING_RTL (parm));
- offset_in_bytes = apply_args_register_offset (regno);
- offset_is_register = 1;
- }
- else
- return 0;
-
- /* This is the case where the parm is passed as an int or double
- and it is converted to a char, short or float and stored back
- in the parmlist. In this case, describe the parm
- with the variable's declared type, and adjust the address
- if the least significant bytes (which we are using) are not
- the first ones. */
- if (BYTES_BIG_ENDIAN && TREE_TYPE (parm) != DECL_ARG_TYPE (parm))
- offset_in_bytes += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parm)))
- - GET_MODE_SIZE (GET_MODE (DECL_RTL (parm))));
+ int sz = int_size_in_bytes (type);
- return offset_in_bytes;
+ /* Make all integer and enum types at least as large
+ as an int. */
+ if (sz > 0 && (TREE_CODE (type) == INTEGER_TYPE
+ || TREE_CODE (type) == BOOLEAN_TYPE
+ || TREE_CODE (type) == ENUMERAL_TYPE))
+ sz = MAX (sz, int_size_in_bytes (integer_type_node));
+ /* Treat arrays as pointers, since that's how they're
+ passed in. */
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ sz = int_size_in_bytes (ptr_type_node);
+ return sz;
}
static tree
-encode_method_prototype (method_decl, func_decl)
- tree method_decl;
- tree func_decl;
+encode_method_prototype (tree method_decl)
{
tree parms;
- int stack_size, i;
- tree user_args;
- HOST_WIDE_INT max_parm_end = 0;
+ int parm_offset, i;
char buf[40];
tree result;
/* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */
encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl)));
- /* C type. */
- encode_type (TREE_TYPE (TREE_TYPE (func_decl)),
+ /* Encode return type. */
+ encode_type (objc_method_parm_type (method_decl),
obstack_object_size (&util_obstack),
OBJC_ENCODE_INLINE_DEFS);
/* Stack size. */
- for (parms = DECL_ARGUMENTS (func_decl); parms;
+ /* The first two arguments (self and _cmd) are pointers; account for
+ their size. */
+ i = int_size_in_bytes (ptr_type_node);
+ parm_offset = 2 * i;
+ for (parms = METHOD_SEL_ARGS (method_decl); parms;
parms = TREE_CHAIN (parms))
{
- HOST_WIDE_INT parm_end = (forwarding_offset (parms)
- + int_size_in_bytes (TREE_TYPE (parms)));
+ tree type = objc_method_parm_type (parms);
+ int sz = objc_encoded_type_size (type);
- if (!offset_is_register && max_parm_end < parm_end)
- max_parm_end = parm_end;
+ /* If a type size is not known, bail out. */
+ if (sz < 0)
+ {
+ error ("%Jtype '%D' does not have a known size",
+ type, type);
+ /* Pretend that the encoding succeeded; the compilation will
+ fail nevertheless. */
+ goto finish_encoding;
+ }
+ parm_offset += sz;
}
- stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET;
-
- sprintf (buf, "%d", stack_size);
+ sprintf (buf, "%d@0:%d", parm_offset, i);
obstack_grow (&util_obstack, buf, strlen (buf));
- user_args = METHOD_SEL_ARGS (method_decl);
-
/* Argument types. */
- for (parms = DECL_ARGUMENTS (func_decl), i = 0; parms;
- parms = TREE_CHAIN (parms), i++)
+ parm_offset = 2 * i;
+ for (parms = METHOD_SEL_ARGS (method_decl); parms;
+ parms = TREE_CHAIN (parms))
{
+ tree type = objc_method_parm_type (parms);
+
/* Process argument qualifiers for user supplied arguments. */
- if (i > 1)
- {
- encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (user_args)));
- user_args = TREE_CHAIN (user_args);
- }
+ encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms)));
/* Type. */
- encode_type (TREE_TYPE (parms),
- obstack_object_size (&util_obstack),
+ encode_type (type, obstack_object_size (&util_obstack),
OBJC_ENCODE_INLINE_DEFS);
/* Compute offset. */
- sprintf (buf, "%d", forwarding_offset (parms));
+ sprintf (buf, "%d", parm_offset);
+ parm_offset += objc_encoded_type_size (type);
- /* Indicate register. */
- if (offset_is_register)
- obstack_1grow (&util_obstack, '+');
-
obstack_grow (&util_obstack, buf, strlen (buf));
}
+ finish_encoding:
obstack_1grow (&util_obstack, '\0');
result = get_identifier (obstack_finish (&util_obstack));
obstack_free (&util_obstack, util_firstobj);
}
static tree
-generate_descriptor_table (type, name, size, list, proto)
- tree type;
- const char *name;
- int size;
- tree list;
- tree proto;
+generate_descriptor_table (tree type, const char *name, int size, tree list,
+ tree proto)
{
tree sc_spec, decl_specs, decl, initlist;
decl_specs, 1, NULL_TREE);
DECL_CONTEXT (decl) = NULL_TREE;
- initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0));
+ initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size));
initlist = tree_cons (NULL_TREE, list, initlist);
finish_decl (decl, objc_build_constructor (type, nreverse (initlist)),
}
static void
-generate_method_descriptors (protocol)
- tree protocol;
+generate_method_descriptors (tree protocol)
{
tree initlist, chain, method_list_template;
tree cast, variable_length_type;
= build_method_prototype_list_template (objc_method_prototype_template,
size);
- initlist
+ initlist
= build_descriptor_table_initializer (objc_method_prototype_template,
chain);
UOBJC_INSTANCE_METHODS_decl = 0;
}
-/* Generate a temporary FUNCTION_DECL node to be used in
- hack_method_prototype below. */
-
-static GTY(()) int build_tmp_function_decl_xxx;
-static tree
-build_tmp_function_decl ()
-{
- tree decl_specs, expr_decl, parms;
- char buffer[80];
- tree tmp_decl;
-
- /* struct objc_object *objc_xxx (id, SEL, ...); */
- pushlevel (0);
- decl_specs = build_tree_list (NULL_TREE, objc_object_reference);
- push_parm_decl (build_tree_list
- (build_tree_list (decl_specs,
- build1 (INDIRECT_REF, NULL_TREE,
- NULL_TREE)),
- NULL_TREE));
-
- decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
- get_identifier (TAG_SELECTOR)));
- expr_decl = build1 (INDIRECT_REF, NULL_TREE, NULL_TREE);
-
- push_parm_decl (build_tree_list (build_tree_list (decl_specs, expr_decl),
- NULL_TREE));
- parms = get_parm_info (0);
- poplevel (0, 0, 0);
-
- decl_specs = build_tree_list (NULL_TREE, objc_object_reference);
- sprintf (buffer, "__objc_tmp_%x", build_tmp_function_decl_xxx++);
- expr_decl = build_nt (CALL_EXPR, get_identifier (buffer), parms, NULL_TREE);
- expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl);
-
- tmp_decl = define_decl (expr_decl, decl_specs);
- DECL_SOURCE_LINE (tmp_decl) = 0;
-
- return tmp_decl;
-}
-
-/* Generate the prototypes for protocol methods. This is used to
- generate method encodings for these.
-
- NST_METHODS is the method to generate a _DECL node for TMP_DECL is
- a decl node to be used. This is also where the return value is
- given. */
-
static void
-hack_method_prototype (nst_methods, tmp_decl)
- tree nst_methods;
- tree tmp_decl;
-{
- tree parms;
- tree parm;
-
- /* Hack to avoid problem with static typing of self arg. */
- TREE_SET_CODE (nst_methods, CLASS_METHOD_DECL);
- start_method_def (nst_methods);
- TREE_SET_CODE (nst_methods, INSTANCE_METHOD_DECL);
-
- if (METHOD_ADD_ARGS (nst_methods) == objc_ellipsis_node)
- parms = get_parm_info (0); /* we have a `, ...' */
- else
- parms = get_parm_info (1); /* place a `void_at_end' */
-
- poplevel (0, 0, 0); /* Must be called BEFORE start_function. */
-
- /* Usually called from store_parm_decls -> init_function_start. */
-
- DECL_ARGUMENTS (tmp_decl) = TREE_PURPOSE (parms);
-
- if (current_function_decl)
- abort ();
- current_function_decl = tmp_decl;
-
- {
- /* Code taken from start_function. */
- tree restype = TREE_TYPE (TREE_TYPE (tmp_decl));
- /* Promote the value to int before returning it. */
- if (TREE_CODE (restype) == INTEGER_TYPE
- && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node))
- restype = integer_type_node;
- DECL_RESULT (tmp_decl) = build_decl (RESULT_DECL, 0, restype);
- }
-
- for (parm = DECL_ARGUMENTS (tmp_decl); parm; parm = TREE_CHAIN (parm))
- DECL_CONTEXT (parm) = tmp_decl;
-
- init_function_start (tmp_decl);
-
- /* Typically called from expand_function_start for function definitions. */
- assign_parms (tmp_decl);
-
- /* install return type */
- TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods));
-
- current_function_decl = NULL;
-}
-
-static void
-generate_protocol_references (plist)
- tree plist;
+generate_protocol_references (tree plist)
{
tree lproto;
@protocol() or from a class/category implementation). These
statically allocated objects can be referred to via the static
(that is, private to this module) symbols _OBJC_PROTOCOL_n.
-
+
The statically allocated Protocol objects that we generate here
need to be fixed up at runtime in order to be used: the 'isa'
- pointer of the objects need to be set up to point to the 'Protocol'
+ pointer of the objects need to be set up to point to the 'Protocol'
class, as known at runtime.
The NeXT runtime fixes up all protocols at program startup time,
being referenced multiple times when compiled with the GNU runtime,
and end up being fixed up multiple times at runtime inizialization.
But that doesn't hurt, it's just a little inefficient. */
+
static void
-generate_protocols ()
+generate_protocols (void)
{
- tree p, tmp_decl, encoding;
+ tree p, encoding;
tree sc_spec, decl_specs, decl;
tree initlist, protocol_name_expr, refs_decl, refs_expr;
tree cast_type2;
- tmp_decl = build_tmp_function_decl ();
-
if (! objc_protocol_template)
objc_protocol_template = build_protocol_template ();
{
if (! METHOD_ENCODING (nst_methods))
{
- hack_method_prototype (nst_methods, tmp_decl);
- encoding = encode_method_prototype (nst_methods, tmp_decl);
+ encoding = encode_method_prototype (nst_methods);
METHOD_ENCODING (nst_methods) = encoding;
}
nst_methods = TREE_CHAIN (nst_methods);
{
if (! METHOD_ENCODING (cls_methods))
{
- hack_method_prototype (cls_methods, tmp_decl);
- encoding = encode_method_prototype (cls_methods, tmp_decl);
+ encoding = encode_method_prototype (cls_methods);
METHOD_ENCODING (cls_methods) = encoding;
}
TREE_TYPE (refs_expr) = cast_type2;
}
else
- refs_expr = build_int_2 (0, 0);
+ refs_expr = build_int_cst (NULL_TREE, 0);
/* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set
by generate_method_descriptors, which is called above. */
}
static tree
-build_protocol_initializer (type, protocol_name, protocol_list,
- instance_methods, class_methods)
- tree type;
- tree protocol_name;
- tree protocol_list;
- tree instance_methods;
- tree class_methods;
+build_protocol_initializer (tree type, tree protocol_name,
+ tree protocol_list, tree instance_methods,
+ tree class_methods)
{
tree initlist = NULL_TREE, expr;
tree cast_type;
/* Filling the "isa" in with one allows the runtime system to
detect that the version change...should remove before final release. */
- expr = build_int_2 (PROTOCOL_VERSION, 0);
- TREE_TYPE (expr) = cast_type;
+ expr = build_int_cst (cast_type, PROTOCOL_VERSION);
initlist = tree_cons (NULL_TREE, expr, initlist);
initlist = tree_cons (NULL_TREE, protocol_name, initlist);
initlist = tree_cons (NULL_TREE, protocol_list, initlist);
if (!instance_methods)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
expr = build_unary_op (ADDR_EXPR, instance_methods, 0);
}
if (!class_methods)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
expr = build_unary_op (ADDR_EXPR, class_methods, 0);
}; */
static void
-build_category_template ()
+build_category_template (void)
{
tree decl_specs, field_decl, field_decl_chain;
}; */
static void
-build_selector_template ()
+build_selector_template (void)
{
tree decl_specs, field_decl, field_decl_chain;
- objc_selector_template
+ objc_selector_template
= start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR));
/* void *sel_id; */
struct objc_class *sibling_class;
}
struct objc_protocol_list *protocols;
+ if (flag_next_runtime)
+ void *sel_id;
void *gc_object_type;
}; */
+/* NB: The 'sel_id' and 'gc_object_type' fields are not being used by
+ the NeXT/Apple runtime; still, the compiler must generate them to
+ maintain backward binary compatibility (and to allow for future
+ expansion). */
+
static void
-build_class_template ()
+build_class_template (void)
{
tree decl_specs, field_decl, field_decl_chain;
/* struct objc_protocol **protocol_list; */
- decl_specs = build_tree_list (NULL_TREE,
+ decl_specs = build_tree_list (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_PROTOCOL)));
field_decl
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
- /* void *sel_id; */
+ if (flag_next_runtime)
+ {
+ /* void *sel_id; */
- decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]);
- field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id"));
- field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
- chainon (field_decl_chain, field_decl);
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id"));
+ field_decl
+ = grokfield (field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+ }
/* void *gc_object_type; */
/* Generate appropriate forward declarations for an implementation. */
static void
-synth_forward_declarations ()
+synth_forward_declarations (void)
{
- tree sc_spec, decl_specs, an_id;
+ tree an_id;
/* static struct objc_class _OBJC_CLASS_<my_name>; */
-
- an_id = synth_id_with_class_suffix ("_OBJC_CLASS", objc_implementation_context);
-
- sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]);
- decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec);
- UOBJC_CLASS_decl = define_decl (an_id, decl_specs);
- TREE_USED (UOBJC_CLASS_decl) = 1;
- DECL_ARTIFICIAL (UOBJC_CLASS_decl) = 1;
- TREE_PUBLIC (UOBJC_CLASS_decl) = 0;
+ UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS",
+ objc_class_template);
/* static struct objc_class _OBJC_METACLASS_<my_name>; */
-
- an_id = synth_id_with_class_suffix ("_OBJC_METACLASS",
- objc_implementation_context);
-
- UOBJC_METACLASS_decl = define_decl (an_id, decl_specs);
- TREE_USED (UOBJC_METACLASS_decl) = 1;
- DECL_ARTIFICIAL (UOBJC_METACLASS_decl) = 1;
- TREE_PUBLIC (UOBJC_METACLASS_decl) = 0;
+ UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS",
+ objc_class_template);
+
+ mark_decl_referenced (UOBJC_CLASS_decl);
+ mark_decl_referenced (UOBJC_METACLASS_decl);
/* Pre-build the following entities - for speed/convenience. */
}
static void
-error_with_ivar (message, decl, rawdecl)
- const char *message;
- tree decl;
- tree rawdecl;
+error_with_ivar (const char *message, tree decl, tree rawdecl)
{
- error ("%H%s `%s'", &DECL_SOURCE_LOCATION (decl),
+ error ("%J%s `%s'", decl,
message, gen_declaration (rawdecl, errbuf));
}
static void
-check_ivars (inter, imp)
- tree inter;
- tree imp;
+check_ivars (tree inter, tree imp)
{
tree intdecls = CLASS_IVARS (inter);
tree impdecls = CLASS_IVARS (imp);
{
tree t1, t2;
+#ifdef OBJCPLUS
+ if (intdecls && TREE_CODE (intdecls) == TYPE_DECL)
+ intdecls = TREE_CHAIN (intdecls);
+#endif
if (intdecls == 0 && impdecls == 0)
break;
if (intdecls == 0 || impdecls == 0)
t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
- if (!comptypes (t1, t2, false))
+ if (TREE_VALUE (TREE_VALUE (rawimpdecls)))
+ {
+ /* t1 is the bit-field type, so t2 must be converted to the
+ bit-field type for comparison as well. */
+ unsigned HOST_WIDE_INT width
+ = tree_low_cst (TREE_VALUE (TREE_VALUE (rawimpdecls)), 1);
+ if (width != TYPE_PRECISION (t2))
+ t2 = build_nonstandard_integer_type (width, TYPE_UNSIGNED (t2));
+ }
+
+ if (!comptypes (t1, t2)
+ || !tree_int_cst_equal (TREE_VALUE (TREE_VALUE (rawintdecls)),
+ TREE_VALUE (TREE_VALUE (rawimpdecls))))
{
if (DECL_NAME (intdecls) == DECL_NAME (impdecls))
{
}
}
-/* Set super_type to the data type node for struct objc_super *,
- first defining struct objc_super itself.
+/* Set 'objc_super_template' to the data type node for 'struct _objc_super'.
This needs to be done just once per compilation. */
-static tree
-build_super_template ()
+static void
+build_super_template (void)
{
- tree record, decl_specs, field_decl, field_decl_chain;
+ tree decl_specs, field_decl, field_decl_chain;
- record = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER));
+ /* Suppress outputting debug symbols, because
+ dbxout_init hasn't been called yet. */
+ enum debug_info_type save_write_symbols = write_symbols;
+ const struct gcc_debug_hooks *save_hooks = debug_hooks;
+
+ write_symbols = NO_DEBUG;
+ debug_hooks = &do_nothing_debug_hooks;
+
+ objc_super_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER));
/* struct objc_object *self; */
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);
- finish_struct (record, field_decl_chain, NULL_TREE);
+ finish_struct (objc_super_template, field_decl_chain, NULL_TREE);
- /* `struct objc_super *' */
- super_type = groktypename (build_tree_list (build_tree_list (NULL_TREE,
- record),
- build1 (INDIRECT_REF,
- NULL_TREE, NULL_TREE)));
- return record;
+ write_symbols = save_write_symbols;
+ debug_hooks = save_hooks;
}
/* struct objc_ivar {
}; */
static tree
-build_ivar_template ()
+build_ivar_template (void)
{
tree objc_ivar_id, objc_ivar_record;
tree decl_specs, field_decl, field_decl_chain;
}; */
static tree
-build_ivar_list_template (list_type, size)
- tree list_type;
- int size;
+build_ivar_list_template (tree list_type, int size)
{
tree objc_ivar_list_record;
tree decl_specs, field_decl, field_decl_chain;
decl_specs = build_tree_list (NULL_TREE, list_type);
field_decl = build_nt (ARRAY_REF, get_identifier ("ivar_list"),
- build_int_2 (size, 0));
+ build_int_cst (NULL_TREE, size), NULL_TREE, NULL_TREE);
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
}; */
static tree
-build_method_list_template (list_type, size)
- tree list_type;
- int size;
+build_method_list_template (tree list_type, int size)
{
tree objc_ivar_list_record;
tree decl_specs, field_decl, field_decl_chain;
decl_specs
= build_tree_list
- (NULL_TREE,
+ (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
field_decl
decl_specs = build_tree_list (NULL_TREE, list_type);
field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
- build_int_2 (size, 0));
+ build_int_cst (NULL_TREE, size), NULL_TREE, NULL_TREE);
field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
}
static tree
-build_ivar_list_initializer (type, field_decl)
- tree type;
- tree field_decl;
+build_ivar_list_initializer (tree type, tree field_decl)
{
tree initlist = NULL_TREE;
ivar);
else
/* Unnamed bit-field ivar (yuck). */
- ivar = tree_cons (NULL_TREE, build_int_2 (0, 0), ivar);
+ ivar = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), ivar);
/* Set type. */
encode_field_decl (field_decl,
/* Set offset. */
ivar = tree_cons (NULL_TREE, byte_position (field_decl), ivar);
- initlist = tree_cons (NULL_TREE,
+ initlist = tree_cons (NULL_TREE,
objc_build_constructor (type, nreverse (ivar)),
initlist);
-
- field_decl = TREE_CHAIN (field_decl);
+ do
+ field_decl = TREE_CHAIN (field_decl);
+ while (field_decl && TREE_CODE (field_decl) != FIELD_DECL);
}
while (field_decl);
}
static tree
-generate_ivars_list (type, name, size, list)
- tree type;
- const char *name;
- int size;
- tree list;
+generate_ivars_list (tree type, const char *name, int size, tree list)
{
tree sc_spec, decl_specs, decl, initlist;
decl = start_decl (synth_id_with_class_suffix (name, objc_implementation_context),
decl_specs, 1, NULL_TREE);
- initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0));
+ initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size));
initlist = tree_cons (NULL_TREE, list, initlist);
finish_decl (decl,
return decl;
}
+/* Count only the fields occurring in T. */
+static int
+ivar_list_length (tree t)
+{
+ int count = 0;
+
+ for (; t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) == FIELD_DECL)
+ ++count;
+
+ return count;
+}
+
static void
-generate_ivar_lists ()
+generate_ivar_lists (void)
{
tree initlist, ivar_list_template, chain;
tree cast, variable_length_type;
if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE
&& (chain = TYPE_FIELDS (objc_class_template)))
{
- size = list_length (chain);
+ size = ivar_list_length (chain);
ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
initlist = build_ivar_list_initializer (objc_ivar_template, chain);
chain = CLASS_IVARS (implementation_template);
if (chain)
{
- size = list_length (chain);
+ size = ivar_list_length (chain);
ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
initlist = build_ivar_list_initializer (objc_ivar_template, chain);
}
static tree
-build_dispatch_table_initializer (type, entries)
- tree type;
- tree entries;
+build_dispatch_table_initializer (tree type, tree entries)
{
tree initlist = NULL_TREE;
/* Generate the method encoding if we don't have one already. */
if (! METHOD_ENCODING (entries))
METHOD_ENCODING (entries) =
- encode_method_def (METHOD_DEFINITION (entries));
+ encode_method_prototype (entries);
elemlist = tree_cons (NULL_TREE,
add_objc_string (METHOD_ENCODING (entries),
meth_var_types),
elemlist);
- elemlist = tree_cons (NULL_TREE,
+ elemlist = tree_cons (NULL_TREE,
build_unary_op (ADDR_EXPR,
METHOD_DEFINITION (entries), 1),
elemlist);
- initlist = tree_cons (NULL_TREE,
+ initlist = tree_cons (NULL_TREE,
objc_build_constructor (type, nreverse (elemlist)),
initlist);
inane warnings, the definition of the dispatch table entries were
changed from:
- struct objc_method { SEL _cmd; ...; id (*_imp)(); };
+ struct objc_method { SEL _cmd; ...; id (*_imp)(); };
to:
- struct objc_method { SEL _cmd; ...; void *_imp; }; */
+ struct objc_method { SEL _cmd; ...; void *_imp; }; */
static tree
-build_method_template ()
+build_method_template (void)
{
tree _SLT_record;
tree decl_specs, field_decl, field_decl_chain;
static tree
-generate_dispatch_table (type, name, size, list)
- tree type;
- const char *name;
- int size;
- tree list;
+generate_dispatch_table (tree type, const char *name, int size, tree list)
{
tree sc_spec, decl_specs, decl, initlist;
decl = start_decl (synth_id_with_class_suffix (name, objc_implementation_context),
decl_specs, 1, NULL_TREE);
- initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
- initlist = tree_cons (NULL_TREE, build_int_2 (size, 0), initlist);
+ initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, size), initlist);
initlist = tree_cons (NULL_TREE, list, initlist);
finish_decl (decl,
}
static void
-mark_referenced_methods ()
+mark_referenced_methods (void)
{
struct imp_entry *impent;
tree chain;
chain = CLASS_CLS_METHODS (impent->imp_context);
while (chain)
{
- cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)), 1);
+ cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
chain = TREE_CHAIN (chain);
}
+
chain = CLASS_NST_METHODS (impent->imp_context);
while (chain)
{
- cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)), 1);
+ cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
chain = TREE_CHAIN (chain);
}
}
}
static void
-generate_dispatch_tables ()
+generate_dispatch_tables (void)
{
tree initlist, chain, method_list_template;
tree cast, variable_length_type;
}
static tree
-generate_protocol_list (i_or_p)
- tree i_or_p;
+generate_protocol_list (tree i_or_p)
{
tree initlist, decl_specs, sc_spec;
tree refs_decl, expr_decl, lproto, e, plist;
size++;
/* Build initializer. */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), NULL_TREE);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), NULL_TREE);
- e = build_int_2 (size, 0);
- TREE_TYPE (e) = cast_type;
+ e = build_int_cst (cast_type, size);
initlist = tree_cons (NULL_TREE, e, initlist);
for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
expr_decl = build_nt (ARRAY_REF,
synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS",
i_or_p),
- build_int_2 (size + 2, 0));
+ build_int_cst (NULL_TREE, size + 2), NULL_TREE, NULL_TREE);
else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE)
expr_decl = build_nt (ARRAY_REF,
synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS",
i_or_p),
- build_int_2 (size + 2, 0));
+ build_int_cst (NULL_TREE, size + 2), NULL_TREE, NULL_TREE);
else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
expr_decl
= build_nt (ARRAY_REF,
synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS",
i_or_p),
- build_int_2 (size + 2, 0));
+ build_int_cst (NULL_TREE, size + 2), NULL_TREE, NULL_TREE);
else
abort ();
}
static tree
-build_category_initializer (type, cat_name, class_name,
- instance_methods, class_methods, protocol_list)
- tree type;
- tree cat_name;
- tree class_name;
- tree instance_methods;
- tree class_methods;
- tree protocol_list;
+build_category_initializer (tree type, tree cat_name, tree class_name,
+ tree instance_methods, tree class_methods,
+ tree protocol_list)
{
tree initlist = NULL_TREE, expr;
initlist = tree_cons (NULL_TREE, class_name, initlist);
if (!instance_methods)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
expr = build_unary_op (ADDR_EXPR, instance_methods, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
}
if (!class_methods)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
expr = build_unary_op (ADDR_EXPR, class_methods, 0);
/* protocol_list = */
if (!protocol_list)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
tree cast_type2 = groktypename
struct objc_class *sibling_class;
}
struct objc_protocol_list *protocols;
+ if (flag_next_runtime)
+ void *sel_id;
void *gc_object_type;
}; */
static tree
-build_shared_structure_initializer (type, isa, super, name, size, status,
- dispatch_table, ivar_list, protocol_list)
- tree type;
- tree isa;
- tree super;
- tree name;
- tree size;
- int status;
- tree dispatch_table;
- tree ivar_list;
- tree protocol_list;
+build_shared_structure_initializer (tree type, tree isa, tree super,
+ tree name, tree size, int status,
+ tree dispatch_table, tree ivar_list,
+ tree protocol_list)
{
tree initlist = NULL_TREE, expr;
initlist = tree_cons (NULL_TREE, default_conversion (name), initlist);
/* version = */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
/* info = */
- initlist = tree_cons (NULL_TREE, build_int_2 (status, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, status), initlist);
/* instance_size = */
initlist = tree_cons (NULL_TREE, size, initlist);
/* objc_ivar_list = */
if (!ivar_list)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
expr = build_unary_op (ADDR_EXPR, ivar_list, 0);
/* objc_method_list = */
if (!dispatch_table)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
expr = build_unary_op (ADDR_EXPR, dispatch_table, 0);
if (flag_next_runtime)
/* method_cache = */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
/* dtable = */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
/* subclass_list = */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
/* sibling_class = */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
}
/* protocol_list = */
if (! protocol_list)
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
tree cast_type2
initlist = tree_cons (NULL_TREE, expr, initlist);
}
+ if (flag_next_runtime)
+ /* sel_id = NULL */
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
+
/* gc_object_type = NULL */
- initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
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
-generate_category (cat)
- tree cat;
+generate_category (tree cat)
{
tree sc_spec, decl_specs, decl;
tree initlist, cat_name_expr, class_name_expr;
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))
{
UOBJC_CLASS_METHODS_decl,
protocol_decl);
- TREE_USED (decl) = 1;
finish_decl (decl, initlist, NULL_TREE);
}
static struct objc_class _OBJC_CLASS_Foo={ ... }; */
static void
-generate_shared_structures ()
+generate_shared_structures (void)
{
tree sc_spec, decl_specs, decl;
tree name_expr, super_expr, root_expr;
super_expr = build_c_cast (cast_type, super_expr); /* cast! */
}
else
- super_expr = build_int_2 (0, 0);
+ super_expr = build_int_cst (NULL_TREE, 0);
root_expr = add_objc_string (my_root_id, class_names);
root_expr = build_c_cast (cast_type, root_expr); /* cast! */
}
static tree
-synth_id_with_class_suffix (preamble, ctxt)
- const char *preamble;
- tree ctxt;
+synth_id_with_class_suffix (const char *preamble, tree ctxt)
{
char *string;
if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE
}
else
abort ();
-
+
return get_identifier (string);
}
static int
-is_objc_type_qualifier (node)
- tree node;
+is_objc_type_qualifier (tree node)
{
return (TREE_CODE (node) == IDENTIFIER_NODE
&& (node == ridpointers [(int) RID_CONST]
type of id (otherwise grokdeclarator will default to int). */
static tree
-adjust_type_for_id_default (type)
- tree type;
+adjust_type_for_id_default (tree type)
{
tree declspecs, chain;
chain = TREE_CHAIN (chain))
{
if (TYPED_OBJECT (TREE_VALUE (chain))
- && !(TREE_VALUE (type)
+ && !(TREE_VALUE (type)
&& TREE_CODE (TREE_VALUE (type)) == INDIRECT_REF))
error ("can not use an object as parameter to a method\n");
if (!is_objc_type_qualifier (TREE_VALUE (chain)))
}
/* Usage:
- keyworddecl:
- selector ':' '(' typename ')' identifier
-
+ keyworddecl:
+ selector ':' '(' typename ')' identifier
+
Purpose:
- Transform an Objective-C keyword argument into
- the C equivalent parameter declarator.
-
+ Transform an Objective-C keyword argument into
+ the C equivalent parameter declarator.
+
In: key_name, an "identifier_node" (optional).
- arg_type, a "tree_list" (optional).
- arg_name, an "identifier_node".
-
+ arg_type, a "tree_list" (optional).
+ arg_name, an "identifier_node".
+
Note: It would be really nice to strongly type the preceding
- arguments in the function prototype; however, then I
- could not use the "accessor" macros defined in "tree.h".
-
+ arguments in the function prototype; however, then I
+ could not use the "accessor" macros defined in "tree.h".
+
Out: an instance of "keyword_decl". */
tree
-build_keyword_decl (key_name, arg_type, arg_name)
- tree key_name;
- tree arg_type;
- tree arg_name;
+objc_build_keyword_decl (tree key_name, tree arg_type, tree arg_name)
{
tree keyword_decl;
/* Given a chain of keyword_decl's, synthesize the full keyword selector. */
static tree
-build_keyword_selector (selector)
- tree selector;
+build_keyword_selector (tree selector)
{
int len = 0;
tree key_chain, key_name;
if (TREE_CODE (selector) == KEYWORD_DECL)
key_name = KEYWORD_KEY_NAME (key_chain);
else if (TREE_CODE (selector) == TREE_LIST)
- key_name = TREE_PURPOSE (key_chain);
+ {
+ key_name = TREE_PURPOSE (key_chain);
+ /* The keyword decl chain will later be used as a function argument
+ chain. Unhook the selector itself so as to not confuse other
+ parts of the compiler. */
+ TREE_PURPOSE (key_chain) = NULL_TREE;
+ }
else
abort ();
/* Used for declarations and definitions. */
tree
-build_method_decl (code, ret_type, selector, add_args)
- enum tree_code code;
- tree ret_type;
- tree selector;
- tree add_args;
+build_method_decl (enum tree_code code, tree ret_type, tree selector,
+ tree add_args)
{
tree method_decl;
#define METHOD_DEF 0
#define METHOD_REF 1
-/* Used by `build_objc_method_call' and `comp_method_types'. Return
+/* 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. */
+ the method call are done together. If METH is null, user-defined
+ arguments (i.e., beyond self and _cmd) shall be represented by `...'. */
static tree
-get_arg_type_list (meth, context, superflag)
- tree meth;
- int context;
- int superflag;
+get_arg_type_list (tree meth, int context, int superflag)
{
tree arglist, akey;
/* Receiver type. */
if (flag_next_runtime && superflag)
- arglist = build_tree_list (NULL_TREE, super_type);
+ arglist = build_tree_list (NULL_TREE, objc_super_type);
else if (context == METHOD_DEF)
arglist = build_tree_list (NULL_TREE, TREE_TYPE (self_decl));
else
- arglist = build_tree_list (NULL_TREE, id_type);
+ arglist = build_tree_list (NULL_TREE, objc_id_type);
/* Selector type - will eventually change to `int'. */
- chainon (arglist, build_tree_list (NULL_TREE, selector_type));
+ chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type));
+
+ /* No actual method prototype given -- assume that remaining arguments
+ are `...'. */
+ if (!meth)
+ return arglist;
/* Build a list of argument types. */
for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey))
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, build_tree_list (NULL_TREE, void_type_node));
+ /* finalize the arglist...simulate get_parm_info (false) */
+ chainon (arglist, void_list_node);
return arglist;
}
static tree
-check_duplicates (hsh)
- hash hsh;
+check_duplicates (hash hsh, int methods, int is_class)
{
tree meth = NULL_TREE;
if (hsh->list)
{
- /* We have two methods with the same name and different types. */
+ /* 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 declarations for method `%s'",
+ warning ("multiple %s named `%c%s' found",
+ methods ? "methods" : "selectors",
+ (is_class ? '+' : '-'),
IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
- warn_with_method ("using", 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;
}
/* If RECEIVER is a class reference, return the identifier node for
- the referenced class. RECEIVER is created by get_class_reference,
+ the referenced class. RECEIVER is created by objc_get_class_reference,
so we check the exact form created depending on which runtimes are
used. */
static tree
-receiver_is_class_object (receiver)
- tree receiver;
+receiver_is_class_object (tree receiver, int self, int super)
{
tree chain, exp, arg;
- /* The receiver is 'self' in the context of a class method. */
+ /* The receiver is 'self' or 'super' in the context of a class method. */
if (objc_method_context
- && receiver == self_decl
- && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
- {
- return CLASS_NAME (objc_implementation_context);
- }
-
+ && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL
+ && (self || super))
+ return (super
+ ? CLASS_SUPER_NAME (implementation_template)
+ : CLASS_NAME (implementation_template));
+
if (flag_next_runtime)
{
/* The receiver is a variable created by
build_class_reference_decl. */
if (TREE_CODE (receiver) == VAR_DECL
- && TREE_TYPE (receiver) == objc_class_type)
- /* Look up the identifier. */
+ && TREE_TYPE (TREE_TYPE (receiver)) == TREE_TYPE (objc_class_type))
+ /* Look up the identifier. */
for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
if (TREE_PURPOSE (chain) == receiver)
- return TREE_VALUE (chain);
- }
- else
- {
- /* The receiver is a function call that returns an id. Check if
- it is a call to objc_getClass, if so, pick up the class name. */
- if (TREE_CODE (receiver) == CALL_EXPR
- && (exp = TREE_OPERAND (receiver, 0))
- && TREE_CODE (exp) == ADDR_EXPR
- && (exp = TREE_OPERAND (exp, 0))
- && TREE_CODE (exp) == FUNCTION_DECL
- && exp == objc_get_class_decl
- /* We have a call to objc_getClass! */
- && (arg = TREE_OPERAND (receiver, 1))
- && TREE_CODE (arg) == TREE_LIST
- && (arg = TREE_VALUE (arg)))
- {
- STRIP_NOPS (arg);
- if (TREE_CODE (arg) == ADDR_EXPR
- && (arg = TREE_OPERAND (arg, 0))
- && TREE_CODE (arg) == STRING_CST)
- /* Finally, we have the class name. */
- return get_identifier (TREE_STRING_POINTER (arg));
- }
+ return TREE_VALUE (chain);
+ }
+
+ /* The receiver is a function call that returns an id. Check if
+ it is a call to objc_getClass, if so, pick up the class name. */
+ if (TREE_CODE (receiver) == CALL_EXPR
+ && (exp = TREE_OPERAND (receiver, 0))
+ && TREE_CODE (exp) == ADDR_EXPR
+ && (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(). 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)
+ /* We have a call to objc_get_class/objc_getClass! */
+ && (arg = TREE_OPERAND (receiver, 1))
+ && TREE_CODE (arg) == TREE_LIST
+ && (arg = TREE_VALUE (arg)))
+ {
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) == ADDR_EXPR
+ && (arg = TREE_OPERAND (arg, 0))
+ && TREE_CODE (arg) == STRING_CST)
+ /* Finally, we have the class name. */
+ return get_identifier (TREE_STRING_POINTER (arg));
}
return 0;
}
static tree current_objc_message_selector = 0;
tree
-objc_message_selector ()
+objc_message_selector (void)
{
return current_objc_message_selector;
}
(*(<abstract_decl>(*)())_msgSuper)(receiver, selTransTbl[n], ...); */
tree
-build_message_expr (mess)
- tree mess;
+objc_build_message_expr (tree mess)
{
tree receiver = TREE_PURPOSE (mess);
tree sel_name;
method_params = args;
}
+#ifdef OBJCPLUS
+ if (processing_template_decl)
+ /* Must wait until template instantiation time. */
+ return build_min_nt (MESSAGE_SEND_EXPR, receiver, sel_name,
+ method_params);
+#endif
+
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, int is_class)
+{
+ 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);
+ is_class = 1;
+ }
+
+ return check_duplicates (method_prototype, 1, is_class);
+}
+
/* The 'finish_message_expr' routine is called from within
- 'build_message_expr' for non-template functions. In the case of
+ '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. */
-
+
tree
-finish_message_expr (receiver, sel_name, method_params)
- tree receiver, sel_name, method_params;
-{
- tree method_prototype = NULL_TREE, class_ident = NULL_TREE;
- tree selector, self_object, retval;
- int statically_typed = 0, statically_allocated = 0;
-
- /* Determine receiver type. */
- tree rtype = TREE_TYPE (receiver);
- int super = IS_SUPER (rtype);
-
- if (! super)
- {
- if (TREE_STATIC_TEMPLATE (rtype))
- statically_allocated = 1;
- else if (TREE_CODE (rtype) == POINTER_TYPE
- && TREE_STATIC_TEMPLATE (TREE_TYPE (rtype)))
- statically_typed = 1;
- else if ((flag_next_runtime
- || (IS_ID (rtype)))
- && (class_ident = receiver_is_class_object (receiver)))
- ;
- else if (! IS_ID (rtype)
- /* Allow any type that matches objc_class_type. */
- && ! comptypes (rtype, objc_class_type, false))
+finish_message_expr (tree receiver, tree sel_name, tree method_params)
+{
+ tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype;
+ tree selector, retval, class_tree;
+ int self, super, have_cast;
+
+ /* Extract the receiver of the message, as well as its type
+ (where the latter may take the form of a cast or be inferred
+ from the implementation context). */
+ rtype = receiver;
+ while (TREE_CODE (rtype) == COMPOUND_EXPR
+ || TREE_CODE (rtype) == MODIFY_EXPR
+ || TREE_CODE (rtype) == NOP_EXPR
+ || TREE_CODE (rtype) == COMPONENT_REF)
+ rtype = TREE_OPERAND (rtype, 0);
+ self = (rtype == self_decl);
+ super = (rtype == UOBJC_SUPER_decl);
+ rtype = TREE_TYPE (receiver);
+ have_cast = (TREE_CODE (receiver) == NOP_EXPR
+ || (TREE_CODE (receiver) == COMPOUND_EXPR
+ && !IS_SUPER (rtype)));
+
+ /* If the receiver is a class object, retrieve the corresponding
+ @interface, if one exists. */
+ class_tree = receiver_is_class_object (receiver, self, super);
+
+ /* Now determine the receiver type (if an explicit cast has not been
+ provided). */
+ if (!have_cast)
+ {
+ if (class_tree)
+ rtype = lookup_interface (class_tree);
+ /* Handle `self' and `super'. */
+ else if (super)
{
- warning ("invalid receiver type `%s'",
- gen_declaration (rtype, errbuf));
+ if (!CLASS_SUPER_NAME (implementation_template))
+ {
+ error ("no super class declared in @interface for `%s'",
+ IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
+ return error_mark_node;
+ }
+ rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template));
}
- if (statically_allocated)
- receiver = build_unary_op (ADDR_EXPR, receiver, 0);
-
- /* Don't evaluate the receiver twice. */
- receiver = save_expr (receiver);
- self_object = receiver;
+ else if (self)
+ rtype = lookup_interface (CLASS_NAME (implementation_template));
}
- else
- /* If sending to `super', use current self as the object. */
- self_object = self_decl;
- /* Determine operation return type. */
-
- if (super)
+ /* If receiver is of type `id' or `Class' (or if the @interface for a
+ class is not visible), we shall be satisfied with the existence of
+ any instance or class method. */
+ if (!rtype || IS_ID (rtype)
+ || TREE_TYPE (rtype) == TREE_TYPE (objc_class_type))
{
- tree iface;
-
- if (CLASS_SUPER_NAME (implementation_template))
+ if (!rtype)
+ rtype = xref_tag (RECORD_TYPE, class_tree);
+ else if (IS_ID (rtype))
{
- iface
- = lookup_interface (CLASS_SUPER_NAME (implementation_template));
-
- if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL)
- method_prototype = lookup_instance_method_static (iface, sel_name);
- else
- method_prototype = lookup_class_method_static (iface, sel_name);
-
- if (iface && !method_prototype)
- warning ("`%s' does not respond to `%s'",
- IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template)),
- IDENTIFIER_POINTER (sel_name));
+ rprotos = TYPE_PROTOCOL_LIST (rtype);
+ rtype = NULL_TREE;
}
else
- {
- error ("no super class declared in interface for `%s'",
- IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
- return error_mark_node;
- }
-
- }
- else if (statically_allocated)
- {
- tree ctype = TREE_TYPE (rtype);
- tree iface = lookup_interface (TYPE_NAME (rtype));
-
- if (iface)
- method_prototype = lookup_instance_method_static (iface, sel_name);
+ class_tree = TYPE_NAME (rtype) = get_identifier ("Class");
- if (! method_prototype && ctype && TYPE_PROTOCOL_LIST (ctype))
+ if (rprotos)
method_prototype
- = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype),
- sel_name, 0);
-
- if (!method_prototype)
- warning ("`%s' does not respond to `%s'",
- IDENTIFIER_POINTER (TYPE_NAME (rtype)),
- IDENTIFIER_POINTER (sel_name));
+ = lookup_method_in_protocol_list (rprotos, sel_name,
+ class_tree != NULL_TREE);
+ if (!method_prototype && !rprotos)
+ method_prototype
+ = lookup_method_in_hash_lists (sel_name,
+ class_tree != NULL_TREE);
}
- else if (statically_typed)
+ else
{
- tree ctype = TREE_TYPE (rtype);
-
- /* `self' is now statically_typed. All methods should be visible
- within the context of the implementation. */
- if (objc_implementation_context
- && CLASS_NAME (objc_implementation_context) == TYPE_NAME (ctype))
- {
- method_prototype
- = lookup_instance_method_static (implementation_template,
- sel_name);
-
- if (! method_prototype && TYPE_PROTOCOL_LIST (ctype))
- method_prototype
- = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype),
- sel_name, 0);
-
- if (! method_prototype
- && implementation_template != objc_implementation_context)
- /* The method is not published in the interface. Check
- locally. */
- method_prototype
- = lookup_method (CLASS_NST_METHODS (objc_implementation_context),
- sel_name);
- }
- else
+ tree orig_rtype = rtype, saved_rtype;
+
+ if (TREE_CODE (rtype) == POINTER_TYPE)
+ rtype = TREE_TYPE (rtype);
+ /* Traverse typedef aliases */
+ while (TREE_CODE (rtype) == RECORD_TYPE && TYPE_NAME (rtype)
+ && TREE_CODE (TYPE_NAME (rtype)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (rtype)))
+ rtype = DECL_ORIGINAL_TYPE (TYPE_NAME (rtype));
+ saved_rtype = rtype;
+ if (TYPED_OBJECT (rtype))
{
- tree iface;
-
- if ((iface = lookup_interface (TYPE_NAME (ctype))))
- method_prototype = lookup_instance_method_static (iface, sel_name);
-
- if (! method_prototype)
- {
- tree protocol_list = TYPE_PROTOCOL_LIST (ctype);
- if (protocol_list)
- method_prototype
- = lookup_method_in_protocol_list (protocol_list,
- sel_name, 0);
- }
+ rprotos = TYPE_PROTOCOL_LIST (rtype);
+ rtype = lookup_interface (OBJC_TYPE_NAME (rtype));
}
-
- if (!method_prototype)
- warning ("`%s' does not respond to `%s'",
- IDENTIFIER_POINTER (TYPE_NAME (ctype)),
- IDENTIFIER_POINTER (sel_name));
- }
- else if (class_ident)
- {
- if (objc_implementation_context
- && CLASS_NAME (objc_implementation_context) == class_ident)
+ /* If we could not find an @interface declaration, we must have
+ only seen a @class declaration; so, we cannot say anything
+ more intelligent about which methods the receiver will
+ understand. */
+ if (!rtype)
+ rtype = saved_rtype;
+ else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE
+ || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE)
{
+ /* We have a valid ObjC class name. Look up the method name
+ in the published @interface for the class (and its
+ superclasses). */
method_prototype
- = lookup_class_method_static (implementation_template, sel_name);
+ = lookup_method_static (rtype, sel_name, class_tree != NULL_TREE);
- if (!method_prototype
- && implementation_template != objc_implementation_context)
- /* The method is not published in the interface. Check
- locally. */
+ /* If the method was not found in the @interface, it may still
+ exist locally as part of the @implementation. */
+ if (!method_prototype && objc_implementation_context
+ && CLASS_NAME (objc_implementation_context)
+ == OBJC_TYPE_NAME (rtype))
method_prototype
- = lookup_method (CLASS_CLS_METHODS (objc_implementation_context),
- sel_name);
+ = lookup_method
+ ((class_tree
+ ? CLASS_CLS_METHODS (objc_implementation_context)
+ : CLASS_NST_METHODS (objc_implementation_context)),
+ sel_name);
+
+ /* If we haven't found a candidate method by now, try looking for
+ it in the protocol list. */
+ if (!method_prototype && rprotos)
+ method_prototype
+ = lookup_method_in_protocol_list (rprotos, sel_name,
+ class_tree != NULL_TREE);
}
else
{
- tree iface;
-
- if ((iface = lookup_interface (class_ident)))
- method_prototype = lookup_class_method_static (iface, sel_name);
- }
-
- if (!method_prototype)
- {
- warning ("cannot find class (factory) method");
- warning ("return type for `%s' defaults to id",
- IDENTIFIER_POINTER (sel_name));
+ warning ("invalid receiver type `%s'",
+ gen_declaration (orig_rtype, errbuf));
+ rtype = rprotos = NULL_TREE;
}
- }
- else if (IS_PROTOCOL_QUALIFIED_ID (rtype))
- {
- /* An anonymous object that has been qualified with a protocol. */
-
- tree protocol_list = TYPE_PROTOCOL_LIST (rtype);
-
- method_prototype = lookup_method_in_protocol_list (protocol_list,
- sel_name, 0);
+ }
- if (!method_prototype)
- {
- hash hsh;
-
- warning ("method `%s' not implemented by protocol",
- IDENTIFIER_POINTER (sel_name));
-
- /* Try and find the method signature in the global pools. */
-
- if (!(hsh = hash_lookup (nst_method_hash_list, sel_name)))
- hsh = hash_lookup (cls_method_hash_list, sel_name);
-
- if (!(method_prototype = check_duplicates (hsh)))
- warning ("return type defaults to id");
- }
- }
- else
+ if (!method_prototype)
{
- hash hsh;
-
- /* We think we have an instance...loophole: extern id Object; */
- hsh = hash_lookup (nst_method_hash_list, sel_name);
-
- if (!hsh)
- /* For various loopholes */
- hsh = hash_lookup (cls_method_hash_list, sel_name);
+ static bool warn_missing_methods = false;
- method_prototype = check_duplicates (hsh);
- if (!method_prototype)
+ if (rtype)
+ warning ("`%s' may not respond to `%c%s'",
+ IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
+ (class_tree ? '+' : '-'),
+ IDENTIFIER_POINTER (sel_name));
+ if (rprotos)
+ warning ("`%c%s' not implemented by protocol(s)",
+ (class_tree ? '+' : '-'),
+ IDENTIFIER_POINTER (sel_name));
+ if (!warn_missing_methods)
{
- warning ("cannot find method");
- warning ("return type for `%s' defaults to id",
- IDENTIFIER_POINTER (sel_name));
+ warning ("(Messages without a matching method signature");
+ warning ("will be assumed to return `id' and accept");
+ warning ("`...' as arguments.)");
+ warn_missing_methods = true;
}
}
selector = build_selector_reference (sel_name);
retval = build_objc_method_call (super, method_prototype,
- receiver, self_object,
+ receiver,
selector, method_params);
current_objc_message_selector = 0;
If SUPER_FLAG is nonzero, we look up the superclass's method. */
static tree
-build_objc_method_call (super_flag, method_prototype, lookup_object, object,
- selector, method_params)
- int super_flag;
- tree method_prototype, lookup_object, object, selector, method_params;
-{
- tree sender = (super_flag ? umsg_super_decl : umsg_decl);
- tree rcv_p = (super_flag
- ? build_pointer_type (xref_tag (RECORD_TYPE,
- get_identifier (TAG_SUPER)))
- : id_type);
+build_objc_method_call (int super_flag, tree method_prototype,
+ tree lookup_object, tree selector,
+ tree method_params)
+{
+ tree sender = (super_flag ? umsg_super_decl :
+ (!flag_next_runtime || flag_nil_receivers
+ ? umsg_decl
+ : umsg_nonnil_decl));
+ tree rcv_p = (super_flag ? objc_super_type : objc_id_type);
+
+ /* If a prototype for the method to be called exists, then cast
+ the sender's return type and arguments to match that of the method.
+ Otherwise, leave sender as is. */
+ tree ret_type
+ = (method_prototype
+ ? groktypename (TREE_TYPE (method_prototype))
+ : objc_id_type);
+ tree sender_cast
+ = build_pointer_type
+ (build_function_type
+ (ret_type,
+ get_arg_type_list
+ (method_prototype, METHOD_REF, super_flag)));
+ tree method, t;
+
+ lookup_object = build_c_cast (rcv_p, lookup_object);
+
+ /* Use SAVE_EXPR to avoid evaluating the receiver twice. */
+ lookup_object = save_expr (lookup_object);
if (flag_next_runtime)
{
- if (! method_prototype)
- {
- method_params = tree_cons (NULL_TREE, lookup_object,
- tree_cons (NULL_TREE, selector,
- method_params));
- assemble_external (sender);
- return build_function_call (sender, method_params);
- }
- else
- {
- /* This is a real kludge, but it is used only for the Next.
- Clobber the data type of SENDER temporarily to accept
- all the arguments for this operation, and to return
- whatever this operation returns. */
- tree arglist = NULL_TREE, retval, savarg, savret;
- tree ret_type = groktypename (TREE_TYPE (method_prototype));
-
- /* Save the proper contents of SENDER's data type. */
- savarg = TYPE_ARG_TYPES (TREE_TYPE (sender));
- savret = TREE_TYPE (TREE_TYPE (sender));
-
- /* Install this method's argument types. */
- arglist = get_arg_type_list (method_prototype, METHOD_REF,
- super_flag);
- TYPE_ARG_TYPES (TREE_TYPE (sender)) = arglist;
-
- /* Install this method's return type. */
- TREE_TYPE (TREE_TYPE (sender)) = ret_type;
-
- /* Call SENDER with all the parameters. This will do type
- checking using the arg types for this method. */
- method_params = tree_cons (NULL_TREE, lookup_object,
- tree_cons (NULL_TREE, selector,
- method_params));
- assemble_external (sender);
- retval = build_function_call (sender, method_params);
-
- /* Restore SENDER's return/argument types. */
- TYPE_ARG_TYPES (TREE_TYPE (sender)) = savarg;
- TREE_TYPE (TREE_TYPE (sender)) = savret;
- return retval;
- }
+ /* 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 (!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);
+
+ method_params = tree_cons (NULL_TREE, lookup_object,
+ tree_cons (NULL_TREE, selector,
+ method_params));
+ method = build_fold_addr_expr (sender);
}
else
{
- /* This is the portable way.
- First call the lookup function to get a pointer to the method,
- then cast the pointer, then call it with the method arguments. */
- tree method;
-
- /* Avoid trouble since we may evaluate each of these twice. */
- object = save_expr (object);
- selector = save_expr (selector);
-
- lookup_object = build_c_cast (rcv_p, lookup_object);
+ /* This is the portable (GNU) way. */
+ tree object;
- assemble_external (sender);
- method
- = build_function_call (sender,
- tree_cons (NULL_TREE, lookup_object,
- tree_cons (NULL_TREE, selector,
- NULL_TREE)));
+ /* First, call the lookup function to get a pointer to the method,
+ then cast the pointer, then call it with the method arguments. */
+
+ object = (super_flag ? self_decl : lookup_object);
- /* If we have a method prototype, construct the data type this
- method needs, and cast what we got from SENDER into a pointer
- to that type. */
- if (method_prototype)
- {
- tree arglist = get_arg_type_list (method_prototype, METHOD_REF,
- super_flag);
- tree valtype = groktypename (TREE_TYPE (method_prototype));
- tree fake_function_type = build_function_type (valtype, arglist);
- TREE_TYPE (method) = build_pointer_type (fake_function_type);
- }
- else
- TREE_TYPE (method)
- = build_pointer_type (build_function_type (ptr_type_node, NULL_TREE));
+ t = tree_cons (NULL_TREE, selector, NULL_TREE);
+ t = tree_cons (NULL_TREE, lookup_object, t);
+ method = build_function_call (sender, t);
/* Pass the object to the method. */
- assemble_external (method);
- return build_function_call (method,
- tree_cons (NULL_TREE, object,
- tree_cons (NULL_TREE, selector,
- method_params)));
+ method_params = tree_cons (NULL_TREE, object,
+ tree_cons (NULL_TREE, selector,
+ method_params));
}
+
+ /* ??? Selector is not at this point something we can use inside
+ the compiler itself. Set it to garbage for the nonce. */
+ t = build (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node);
+ return build_function_call (t, method_params);
}
\f
static void
-build_protocol_reference (p)
- tree p;
+build_protocol_reference (tree p)
{
tree decl, ident, ptype;
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
- make_decl_rtl (decl, 0);
+ make_decl_rtl (decl);
pushdecl_top_level (decl);
}
/* This function is called by the parser when (and only when) a
@protocol() expression is found, in order to compile it. */
tree
-build_protocol_expr (protoname)
- tree protoname;
+objc_build_protocol_expr (tree protoname)
{
tree expr;
tree p = lookup_protocol (protoname);
expr = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0);
- TREE_TYPE (expr) = protocol_type;
+ /* ??? Ideally we'd build the reference with objc_protocol_type directly,
+ if we have it, rather than converting it here. */
+ expr = convert (objc_protocol_type, expr);
/* The @protocol() expression is being compiled into a pointer to a
statically allocated instance of the Protocol class. To become
if (! flag_next_runtime)
{
/* This type is a struct containing the fields of a Protocol
- object. (Cfr. protocol_type instead is the type of a pointer
+ object. (Cfr. objc_protocol_type instead is the type of a pointer
to such a struct). */
- tree protocol_struct_type = xref_tag
+ tree protocol_struct_type = xref_tag
(RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
tree *chain;
-
+
/* Look for the list of Protocol statically allocated instances
to fixup at runtime. Create a new list to hold Protocol
statically allocated instances, if the list is not found. At
if (!*chain)
{
*chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE);
- add_objc_string (TYPE_NAME (protocol_struct_type),
+ add_objc_string (OBJC_TYPE_NAME (protocol_struct_type),
class_names);
}
-
+
/* Add this statically allocated instance to the Protocol list. */
- TREE_PURPOSE (*chain) = tree_cons (NULL_TREE,
+ TREE_PURPOSE (*chain) = tree_cons (NULL_TREE,
PROTOCOL_FORWARD_DECL (p),
TREE_PURPOSE (*chain));
}
-
+
return expr;
}
is found, in order to compile it. It is only called by the parser
and only to compile a @selector(). */
tree
-build_selector_expr (selnamelist)
- tree selnamelist;
+objc_build_selector_expr (tree selnamelist)
{
tree selname;
/* First try with instance methods. */
hsh = hash_lookup (nst_method_hash_list, selname);
-
+
/* If not found, try with class methods. */
if (!hsh)
{
hsh = hash_lookup (cls_method_hash_list, selname);
}
-
+
/* If still not found, print out a warning. */
if (!hsh)
{
warning ("undeclared selector `%s'", IDENTIFIER_POINTER (selname));
}
}
-
+
if (flag_typed_selectors)
return build_typed_selector_reference (selname, 0);
}
tree
-build_encode_expr (type)
- tree type;
+objc_build_encode_expr (tree type)
{
tree result;
const char *string;
}
tree
-build_ivar_reference (id)
- tree id;
+build_ivar_reference (tree id)
{
if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
{
paradigm. */
warning ("instance variable `%s' accessed in class method",
IDENTIFIER_POINTER (id));
- TREE_TYPE (self_decl) = instance_type; /* cast */
+ TREE_TYPE (self_decl) = objc_instance_type; /* cast */
}
return build_component_ref (build_indirect_ref (self_decl, "->"), id);
/* Compute a hash value for a given method SEL_NAME. */
static size_t
-hash_func (sel_name)
- tree sel_name;
+hash_func (tree sel_name)
{
- const unsigned char *s
+ const unsigned char *s
= (const unsigned char *)IDENTIFIER_POINTER (sel_name);
size_t h = 0;
-
+
while (*s)
h = h * 67 + *s++ - 113;
- return h;
+ return h;
}
-
+
static void
-hash_init ()
+hash_init (void)
{
- nst_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash));
- cls_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash));
+ nst_method_hash_list
+ = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash));
+ cls_method_hash_list
+ = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash));
}
/* WARNING!!!! hash_enter is called with a method, and will peek
entry's key (method) for comparison. */
static void
-hash_enter (hashlist, method)
- hash *hashlist;
- tree method;
+hash_enter (hash *hashlist, tree method)
{
hash obj;
int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
}
static hash
-hash_lookup (hashlist, sel_name)
- hash *hashlist;
- tree sel_name;
+hash_lookup (hash *hashlist, tree sel_name)
{
hash target;
}
static void
-hash_add_attr (entry, value)
- hash entry;
- tree value;
+hash_add_attr (hash entry, tree value)
{
attr obj;
}
\f
static tree
-lookup_method (mchain, method)
- tree mchain;
- tree method;
+lookup_method (tree mchain, tree method)
{
tree key;
}
static tree
-lookup_instance_method_static (interface, ident)
- tree interface;
- tree ident;
+lookup_method_static (tree interface, tree ident, int is_class)
{
+ tree meth = NULL_TREE, root_inter = NULL_TREE;
tree inter = interface;
- tree chain = CLASS_NST_METHODS (inter);
- tree meth = NULL_TREE;
- do
+ while (inter)
{
+ tree chain = is_class ? CLASS_CLS_METHODS (inter) : CLASS_NST_METHODS (inter);
+ tree category = inter;
+
+ /* First, look up the method in the class itself. */
if ((meth = lookup_method (chain, ident)))
return meth;
- if (CLASS_CATEGORY_LIST (inter))
+ /* Failing that, look for the method in each category of the class. */
+ while ((category = CLASS_CATEGORY_LIST (category)))
{
- tree category = CLASS_CATEGORY_LIST (inter);
- chain = CLASS_NST_METHODS (category);
-
- do
- {
- if ((meth = lookup_method (chain, ident)))
- return meth;
-
- /* Check for instance methods in protocols in categories. */
- if (CLASS_PROTOCOL_LIST (category))
- {
- if ((meth = (lookup_method_in_protocol_list
- (CLASS_PROTOCOL_LIST (category), ident, 0))))
- return meth;
- }
+ chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category);
- if ((category = CLASS_CATEGORY_LIST (category)))
- chain = CLASS_NST_METHODS (category);
- }
- while (category);
- }
-
- if (CLASS_PROTOCOL_LIST (inter))
- {
- if ((meth = (lookup_method_in_protocol_list
- (CLASS_PROTOCOL_LIST (inter), ident, 0))))
+ /* Check directly in each category. */
+ if ((meth = lookup_method (chain, ident)))
return meth;
- }
-
- if ((inter = lookup_interface (CLASS_SUPER_NAME (inter))))
- chain = CLASS_NST_METHODS (inter);
- }
- while (inter);
-
- return meth;
-}
-
-static tree
-lookup_class_method_static (interface, ident)
- tree interface;
- tree ident;
-{
- tree inter = interface;
- tree chain = CLASS_CLS_METHODS (inter);
- tree meth = NULL_TREE;
- tree root_inter = NULL_TREE;
-
- do
- {
- if ((meth = lookup_method (chain, ident)))
- return meth;
-
- if (CLASS_CATEGORY_LIST (inter))
- {
- tree category = CLASS_CATEGORY_LIST (inter);
- chain = CLASS_CLS_METHODS (category);
- do
+ /* Failing that, check in each category's protocols. */
+ if (CLASS_PROTOCOL_LIST (category))
{
- if ((meth = lookup_method (chain, ident)))
+ if ((meth = (lookup_method_in_protocol_list
+ (CLASS_PROTOCOL_LIST (category), ident, is_class))))
return meth;
-
- /* Check for class methods in protocols in categories. */
- if (CLASS_PROTOCOL_LIST (category))
- {
- if ((meth = (lookup_method_in_protocol_list
- (CLASS_PROTOCOL_LIST (category), ident, 1))))
- return meth;
- }
-
- if ((category = CLASS_CATEGORY_LIST (category)))
- chain = CLASS_CLS_METHODS (category);
}
- while (category);
}
- /* Check for class methods in protocols. */
+ /* If not found in categories, check in protocols of the main class. */
if (CLASS_PROTOCOL_LIST (inter))
{
if ((meth = (lookup_method_in_protocol_list
- (CLASS_PROTOCOL_LIST (inter), ident, 1))))
+ (CLASS_PROTOCOL_LIST (inter), ident, is_class))))
return meth;
}
+ /* Failing that, climb up the inheritance hierarchy. */
root_inter = inter;
- if ((inter = lookup_interface (CLASS_SUPER_NAME (inter))))
- chain = CLASS_CLS_METHODS (inter);
+ inter = lookup_interface (CLASS_SUPER_NAME (inter));
}
while (inter);
/* If no class (factory) method was found, check if an _instance_
method of the same name exists in the root class. This is what
- the Objective-C runtime will do. */
- return lookup_instance_method_static (root_inter, ident);
+ the Objective-C runtime will do. If an instance method was not
+ found, return 0. */
+ return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE;
}
-tree
-add_class_method (class, method)
- tree class;
- tree method;
+/* 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)
{
- tree mth;
hash hsh;
- if (!(mth = lookup_method (CLASS_CLS_METHODS (class), method)))
- {
- /* put method on list in reverse order */
- TREE_CHAIN (method) = CLASS_CLS_METHODS (class);
- CLASS_CLS_METHODS (class) = method;
- }
- else
- {
- if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
- error ("duplicate definition of class method `%s'",
- IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
- else
- {
- /* Check types; if different, complain. */
- if (!comp_proto_with_proto (method, mth))
- error ("duplicate declaration of class method `%s'",
- IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
- }
- }
-
- if (!(hsh = hash_lookup (cls_method_hash_list, METHOD_SEL_NAME (method))))
+ if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method))))
{
/* Install on a global chain. */
- hash_enter (cls_method_hash_list, method);
+ hash_enter (hash_list, method);
}
else
{
- /* Check types; if different, add to a list. */
- if (!comp_proto_with_proto (method, hsh->key))
- hash_add_attr (hsh, method);
+ /* 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);
}
- return method;
}
-\f
+
tree
-add_instance_method (class, method)
- tree class;
- tree method;
+objc_add_method (tree class, tree method, int is_class)
{
tree mth;
- hash hsh;
- if (!(mth = lookup_method (CLASS_NST_METHODS (class), method)))
+ if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), method)))
{
- /* Put method on list in reverse order. */
- TREE_CHAIN (method) = CLASS_NST_METHODS (class);
- CLASS_NST_METHODS (class) = method;
+ /* put method on list in reverse order */
+ if (is_class)
+ {
+ TREE_CHAIN (method) = CLASS_CLS_METHODS (class);
+ CLASS_CLS_METHODS (class) = method;
+ }
+ else
+ {
+ TREE_CHAIN (method) = CLASS_NST_METHODS (class);
+ CLASS_NST_METHODS (class) = method;
+ }
}
else
{
- if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
- error ("duplicate definition of instance method `%s'",
- IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
- else
- {
- /* Check types; if different, complain. */
- if (!comp_proto_with_proto (method, mth))
- error ("duplicate declaration of instance method `%s'",
- IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
- }
+ /* 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))
+ error ("duplicate declaration of method `%c%s'",
+ is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
}
- if (!(hsh = hash_lookup (nst_method_hash_list, METHOD_SEL_NAME (method))))
- {
- /* Install on a global chain. */
- hash_enter (nst_method_hash_list, method);
- }
+ if (is_class)
+ add_method_to_hash_list (cls_method_hash_list, method);
else
{
- /* Check types; if different, add to a list. */
- if (!comp_proto_with_proto (method, hsh->key))
- 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;
}
static tree
-add_class (class)
- tree class;
+add_class (tree class)
{
/* Put interfaces on list in reverse order. */
TREE_CHAIN (class) = interface_chain;
}
static void
-add_category (class, category)
- tree class;
- tree category;
+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))
- warning ("duplicate interface declaration for category `%s(%s)'",
- 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
PUBLIC is 1 for public, 0 for protected, and 2 for private. */
tree
-add_instance_variable (class, public, declarator, declspecs, width)
- tree class;
- int public;
- tree declarator;
- tree declspecs;
- tree width;
+add_instance_variable (tree class, int public, tree declarator,
+ tree declspecs, tree width)
{
- tree field_decl, raw_decl;
-
- raw_decl = build_tree_list (declspecs, declarator);
+ tree field_decl = grokfield (declarator, declspecs, width);
+ tree field_type = TREE_TYPE (field_decl);
+ const char *ivar_name = DECL_NAME (field_decl)
+ ? IDENTIFIER_POINTER (DECL_NAME (field_decl))
+ : "<unnamed>";
+ tree raw_decl;
- if (CLASS_RAW_IVARS (class))
- chainon (CLASS_RAW_IVARS (class), raw_decl);
- else
- CLASS_RAW_IVARS (class) = raw_decl;
+#ifdef OBJCPLUS
+ if (TREE_CODE (field_type) == REFERENCE_TYPE)
+ {
+ error ("illegal reference type specified for instance variable `%s'",
+ ivar_name);
+ /* Return class as is without adding this ivar. */
+ return class;
+ }
+#endif
- field_decl = grokfield (declarator, declspecs, width);
+ if (field_type == error_mark_node || !TYPE_SIZE (field_type)
+ || TYPE_SIZE (field_type) == error_mark_node
+ /* 'type[0]' is allowed, but 'type[]' is not! */
+#ifdef OBJCPLUS
+ || (TYPE_SIZE (field_type) == bitsize_zero_node
+ && !TREE_OPERAND (declarator, 1))
+#endif
+ )
+ {
+ error ("instance variable `%s' has unknown size", ivar_name);
+ /* Return class as is without adding this ivar. */
+ return class;
+ }
+
+#ifdef OBJCPLUS
+ /* zlaski 2001-Apr-24: C++ classes with non-trivial constructors and/or destructors
+ cannot be ivars; ditto for classes with vtables. */
+ if(IS_AGGR_TYPE (field_type) && (TYPE_NEEDS_CONSTRUCTING (field_type)
+ || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type) || TYPE_POLYMORPHIC_P (field_type)))
+ {
+ const char *type_name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (field_type));
+ if(TYPE_POLYMORPHIC_P (field_type)) {
+ /* vtable pointers are Real Bad(tm), since Obj-C cannot initialize them */
+ error ("type `%s' has virtual member functions", type_name);
+ error ("illegal aggregate type `%s' specified for instance variable `%s'",
+ type_name, ivar_name);
+ /* Return class as is without adding this ivar. */
+ return class;
+ }
+ /* user-defined constructors and destructors are not known to Obj-C and
+ hence will not be called. This may or may not be a problem. */
+ if (TYPE_NEEDS_CONSTRUCTING (field_type))
+ warning ("type `%s' has a user-defined constructor", type_name);
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type))
+ warning ("type `%s' has a user-defined destructor", type_name);
+ warning ("C++ constructors and destructors will not be invoked for Objective-C fields");
+ }
+#endif
/* Overload the public attribute, it is not used for FIELD_DECLs. */
switch (public)
}
- if (CLASS_IVARS (class))
- chainon (CLASS_IVARS (class), field_decl);
- else
- CLASS_IVARS (class) = field_decl;
-
+ raw_decl = build_tree_list (declspecs, build_tree_list (declarator, width));
+ CLASS_RAW_IVARS (class) = chainon (CLASS_RAW_IVARS (class), raw_decl);
+ CLASS_IVARS (class) = chainon (CLASS_IVARS (class), field_decl);
return class;
}
\f
tree
-is_ivar (decl_chain, ident)
- tree decl_chain;
- tree ident;
+is_ivar (tree decl_chain, tree ident)
{
for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain))
if (DECL_NAME (decl_chain) == ident)
/* True if the ivar is private and we are not in its implementation. */
int
-is_private (decl)
- tree decl;
+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 (expr, identifier)
- tree expr;
- tree identifier;
+objc_is_public (tree expr, tree identifier)
{
tree basetype = TREE_TYPE (expr);
enum tree_code code = TREE_CODE (basetype);
{
if (TREE_STATIC_TEMPLATE (basetype))
{
- if (!lookup_interface (TYPE_NAME (basetype)))
+ if (!lookup_interface (OBJC_TYPE_NAME (basetype)))
{
error ("cannot find interface declaration for `%s'",
- IDENTIFIER_POINTER (TYPE_NAME (basetype)));
+ IDENTIFIER_POINTER (OBJC_TYPE_NAME (basetype)));
return 0;
}
|| (TREE_CODE (objc_implementation_context)
== CATEGORY_IMPLEMENTATION_TYPE))
&& (CLASS_NAME (objc_implementation_context)
- == TYPE_NAME (basetype))))
- return ! is_private (decl);
+ == OBJC_TYPE_NAME (basetype))))
+ {
+ 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... */
+ if (!objc_method_context)
+ {
+ warning ("instance variable `%s' is %s; "
+ "this will be a hard error in the future",
+ IDENTIFIER_POINTER (identifier),
+ TREE_PRIVATE (decl) ? "@private" : "@protected");
+ return 1;
+ }
+
error ("instance variable `%s' is declared %s",
IDENTIFIER_POINTER (identifier),
TREE_PRIVATE (decl) ? "private" : "protected");
/* Make sure all entries in CHAIN are also in LIST. */
static int
-check_methods (chain, list, mtype)
- tree chain;
- tree list;
- int mtype;
+check_methods (tree chain, tree list, int mtype)
{
int first = 1;
/* Check if CLASS, or its superclasses, explicitly conforms to PROTOCOL. */
static int
-conforms_to_protocol (class, protocol)
- tree class;
- tree protocol;
+conforms_to_protocol (tree class, tree protocol)
{
if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE)
{
return 1;
}
-/* Make sure all methods in CHAIN are accessible as MTYPE methods in
+/* Make sure all methods in CHAIN are accessible as MTYPE methods in
CONTEXT. This is one of two mechanisms to check protocol integrity. */
static int
-check_methods_accessible (chain, context, mtype)
- tree chain;
- tree context;
- int mtype;
+check_methods_accessible (tree chain, tree context, int mtype)
{
int first = 1;
tree list;
list = CLASS_NST_METHODS (context);
if (lookup_method (list, chain))
- break;
+ break;
else if (TREE_CODE (context) == CLASS_IMPLEMENTATION_TYPE
|| TREE_CODE (context) == CLASS_INTERFACE_TYPE)
- context = (CLASS_SUPER_NAME (context)
+ context = (CLASS_SUPER_NAME (context)
? lookup_interface (CLASS_SUPER_NAME (context))
: NULL_TREE);
else if (TREE_CODE (context) == CATEGORY_IMPLEMENTATION_TYPE
|| TREE_CODE (context) == CATEGORY_INTERFACE_TYPE)
- context = (CLASS_NAME (context)
+ context = (CLASS_NAME (context)
? lookup_interface (CLASS_NAME (context))
: NULL_TREE);
else
/* Check whether the current interface (accessible via
'objc_implementation_context') actually implements protocol P, along
with any protocols that P inherits. */
-
+
static void
-check_protocol (p, type, name)
- tree p;
- const char *type;
- const char *name;
+check_protocol (tree p, const char *type, const char *name)
{
if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
{
warning ("%s `%s' does not fully implement the `%s' protocol",
type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
-
+
/* Check protocols recursively. */
if (PROTOCOL_LIST (p))
{
tree super_class =
lookup_interface (CLASS_SUPER_NAME (implementation_template));
- while (subs)
+ while (subs)
{
tree sub = TREE_VALUE (subs);
}
}
}
-
+
/* Check whether the current interface (accessible via
'objc_implementation_context') actually implements the protocols listed
in PROTO_LIST. */
-
+
static void
-check_protocols (proto_list, type, name)
- tree proto_list;
- const char *type;
- const char *name;
+check_protocols (tree proto_list, const char *type, const char *name)
{
for ( ; proto_list; proto_list = TREE_CHAIN (proto_list))
{
CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE. */
tree
-start_class (code, class_name, super_name, protocol_list)
- enum tree_code code;
- tree class_name;
- tree super_name;
- tree protocol_list;
+start_class (enum tree_code code, tree class_name, tree super_name,
+ tree protocol_list)
{
tree class, decl;
+#ifdef OBJCPLUS
+ if (current_namespace != global_namespace) {
+ error ("Objective-C declarations may only appear in global scope");
+ }
+#endif /* OBJCPLUS */
+
if (objc_implementation_context)
{
warning ("`@end' missing in implementation context");
}
class = make_node (code);
- TYPE_BINFO (class) = make_tree_vec (BINFO_ELTS);
+ TYPE_LANG_SLOT_1 (class) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
CLASS_NAME (class) = class_name;
CLASS_SUPER_NAME (class) = super_name;
CLASS_CLS_METHODS (class) = NULL_TREE;
- if (! is_class_name (class_name) && (decl = lookup_name (class_name)))
+ if (! objc_is_class_name (class_name)
+ && (decl = lookup_name (class_name)))
{
error ("`%s' redeclared as different kind of symbol",
IDENTIFIER_POINTER (class_name));
- error_with_decl (decl, "previous declaration of `%s'");
+ error ("%Jprevious declaration of '%D'",
+ decl, decl);
}
if (code == CLASS_IMPLEMENTATION_TYPE)
implemented_classes);
}
- /* Pre-build the following entities - for speed/convenience. */
- if (!self_id)
- self_id = get_identifier ("self");
- if (!ucmd_id)
- ucmd_id = get_identifier ("_cmd");
- if (!unused_list)
- unused_list
- = build_tree_list (get_identifier ("__unused__"), NULL_TREE);
- if (!objc_super_template)
- objc_super_template = build_super_template ();
-
/* Reset for multiple classes per file. */
method_slot = 0;
else if (! super_name)
{
- CLASS_SUPER_NAME (objc_implementation_context)
+ CLASS_SUPER_NAME (objc_implementation_context)
= CLASS_SUPER_NAME (implementation_template);
}
}
else if (code == CLASS_INTERFACE_TYPE)
{
if (lookup_interface (class_name))
- warning ("duplicate interface declaration for class `%s'",
- IDENTIFIER_POINTER (class_name));
+#ifdef OBJCPLUS
+ error ("duplicate interface declaration for class `%s'",
+#else
+ warning ("duplicate interface declaration for class `%s'",
+#endif
+ IDENTIFIER_POINTER (class_name));
else
add_class (class);
else if (code == CATEGORY_IMPLEMENTATION_TYPE)
{
- /* Pre-build the following entities for speed/convenience. */
- if (!self_id)
- self_id = get_identifier ("self");
- if (!ucmd_id)
- ucmd_id = get_identifier ("_cmd");
- if (!unused_list)
- unused_list
- = build_tree_list (get_identifier ("__unused__"), NULL_TREE);
- if (!objc_super_template)
- objc_super_template = build_super_template ();
-
/* Reset for multiple classes per file. */
method_slot = 0;
}
tree
-continue_class (class)
- tree class;
+continue_class (tree class)
{
if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE
|| TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE)
{
- tree record = xref_tag (RECORD_TYPE, CLASS_NAME (class));
-
- if (!TYPE_FIELDS (record))
+ if (!CLASS_STATIC_TEMPLATE (class))
{
- finish_struct (record, get_class_ivars (class), NULL_TREE);
+ tree record = start_struct (RECORD_TYPE, CLASS_NAME (class));
+ finish_struct (record, get_class_ivars (class, 0), NULL_TREE);
CLASS_STATIC_TEMPLATE (class) = record;
/* Mark this record as a class template for static typing. */
/* This is called once we see the "@end" in an interface/implementation. */
void
-finish_class (class)
- tree class;
+finish_class (tree class)
{
if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
{
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)
{
}
static tree
-add_protocol (protocol)
- tree protocol;
+add_protocol (tree protocol)
{
/* Put protocol on list in reverse order. */
TREE_CHAIN (protocol) = protocol_chain;
}
static tree
-lookup_protocol (ident)
- tree ident;
+lookup_protocol (tree ident)
{
tree chain;
they are already declared or defined, the function has no effect. */
void
-objc_declare_protocols (names)
- tree names;
+objc_declare_protocols (tree names)
{
tree list;
+#ifdef OBJCPLUS
+ if (current_namespace != global_namespace) {
+ error ("Objective-C declarations may only appear in global scope");
+ }
+#endif /* OBJCPLUS */
+
for (list = names; list; list = TREE_CHAIN (list))
{
tree name = TREE_VALUE (list);
{
tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
- TYPE_BINFO (protocol) = make_tree_vec (2);
+ TYPE_LANG_SLOT_1 (protocol)
+ = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
PROTOCOL_NAME (protocol) = name;
PROTOCOL_LIST (protocol) = NULL_TREE;
add_protocol (protocol);
}
tree
-start_protocol (code, name, list)
- enum tree_code code;
- tree name;
- tree list;
+start_protocol (enum tree_code code, tree name, tree list)
{
tree protocol;
+#ifdef OBJCPLUS
+ if (current_namespace != global_namespace) {
+ error ("Objective-C declarations may only appear in global scope");
+ }
+#endif /* OBJCPLUS */
+
/* This is as good a place as any. Need to invoke
push_tag_toplevel. */
if (!objc_protocol_template)
if (!protocol)
{
protocol = make_node (code);
- TYPE_BINFO (protocol) = make_tree_vec (2);
+ TYPE_LANG_SLOT_1 (protocol) = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
PROTOCOL_NAME (protocol) = name;
PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
}
void
-finish_protocol (protocol)
- tree protocol ATTRIBUTE_UNUSED;
+finish_protocol (tree protocol ATTRIBUTE_UNUSED)
{
}
??? What is the FORMAT? Someone please document this! */
static void
-encode_type_qualifiers (declspecs)
- tree declspecs;
+encode_type_qualifiers (tree declspecs)
{
tree spec;
/* Encode a pointer type. */
static void
-encode_pointer (type, curtype, format)
- tree type;
- int curtype;
- int format;
+encode_pointer (tree type, int curtype, int format)
{
tree pointer_to = TREE_TYPE (type);
if (TREE_CODE (pointer_to) == RECORD_TYPE)
{
- if (TYPE_NAME (pointer_to)
- && TREE_CODE (TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
+ if (OBJC_TYPE_NAME (pointer_to)
+ && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
{
- const char *name = IDENTIFIER_POINTER (TYPE_NAME (pointer_to));
+ const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to));
if (strcmp (name, TAG_OBJECT) == 0) /* '@' */
{
else if (TREE_CODE (pointer_to) == INTEGER_TYPE
&& TYPE_MODE (pointer_to) == QImode)
{
- obstack_1grow (&util_obstack, '*');
- return;
+ tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE
+ ? OBJC_TYPE_NAME (pointer_to)
+ : DECL_NAME (OBJC_TYPE_NAME (pointer_to));
+
+ if (!flag_next_runtime || strcmp (IDENTIFIER_POINTER (pname), "BOOL"))
+ {
+ obstack_1grow (&util_obstack, '*');
+ return;
+ }
}
/* We have a type that does not get special treatment. */
}
static void
-encode_array (type, curtype, format)
- tree type;
- int curtype;
- int format;
+encode_array (tree type, int curtype, int format)
{
tree an_int_cst = TYPE_SIZE (type);
tree array_of = TREE_TYPE (type);
}
\f
static void
-encode_aggregate_within (type, curtype, format, left, right)
- tree type;
- int curtype;
- int format;
- int left;
- int right;
-{
- /* The RECORD_TYPE may in fact be a typedef! For purposes
- of encoding, we need the real underlying enchilada. */
- if (TYPE_MAIN_VARIANT (type))
- type = TYPE_MAIN_VARIANT (type);
-
- if (obstack_object_size (&util_obstack) > 0
- && *(obstack_next_free (&util_obstack) - 1) == '^')
- {
- tree name = TYPE_NAME (type);
-
- /* we have a reference; this is a NeXT extension. */
-
- if (obstack_object_size (&util_obstack) - curtype == 1
- && format == OBJC_ENCODE_INLINE_DEFS)
- {
- /* Output format of struct for first level only. */
- tree fields = TYPE_FIELDS (type);
-
- if (name && TREE_CODE (name) == IDENTIFIER_NODE)
- {
- obstack_1grow (&util_obstack, left);
- obstack_grow (&util_obstack,
- IDENTIFIER_POINTER (name),
- strlen (IDENTIFIER_POINTER (name)));
- obstack_1grow (&util_obstack, '=');
- }
- else
- {
- obstack_1grow (&util_obstack, left);
- obstack_grow (&util_obstack, "?=", 2);
- }
-
- for ( ; fields; fields = TREE_CHAIN (fields))
- encode_field_decl (fields, curtype, format);
-
- obstack_1grow (&util_obstack, right);
- }
-
- else if (name && TREE_CODE (name) == IDENTIFIER_NODE)
- {
- obstack_1grow (&util_obstack, left);
- obstack_grow (&util_obstack,
- IDENTIFIER_POINTER (name),
- strlen (IDENTIFIER_POINTER (name)));
- obstack_1grow (&util_obstack, right);
- }
-
- else
- {
- /* We have an untagged structure or a typedef. */
- obstack_1grow (&util_obstack, left);
- obstack_1grow (&util_obstack, '?');
- obstack_1grow (&util_obstack, right);
- }
- }
-
+encode_aggregate_within (tree type, int curtype, int format, int left,
+ int right)
+{
+ tree name;
+ /* NB: aggregates that are pointed to have slightly different encoding
+ rules in that you never encode the names of instance variables. */
+ int pointed_to
+ = (obstack_object_size (&util_obstack) > 0
+ && *(obstack_next_free (&util_obstack) - 1) == '^');
+ int inline_contents
+ = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
+ && (!pointed_to || obstack_object_size (&util_obstack) - curtype == 1));
+
+ /* Traverse struct aliases; it is important to get the
+ original struct and its tag name (if any). */
+ type = TYPE_MAIN_VARIANT (type);
+ name = OBJC_TYPE_NAME (type);
+ /* Open parenth/bracket. */
+ obstack_1grow (&util_obstack, left);
+
+ /* Encode the struct/union tag name, or '?' if a tag was
+ not provided. Typedef aliases do not qualify. */
+ if (name && TREE_CODE (name) == IDENTIFIER_NODE
+#ifdef OBJCPLUS
+ /* Did this struct have a tag? */
+ && !TYPE_WAS_ANONYMOUS (type)
+#endif
+ )
+ obstack_grow (&util_obstack,
+ IDENTIFIER_POINTER (name),
+ strlen (IDENTIFIER_POINTER (name)));
else
+ obstack_1grow (&util_obstack, '?');
+
+ /* Encode the types (and possibly names) of the inner fields,
+ if required. */
+ if (inline_contents)
{
- tree name = TYPE_NAME (type);
tree fields = TYPE_FIELDS (type);
- if (format == OBJC_ENCODE_INLINE_DEFS
- || generating_instance_variables)
+ obstack_1grow (&util_obstack, '=');
+ for (; fields; fields = TREE_CHAIN (fields))
{
- obstack_1grow (&util_obstack, left);
- if (name && TREE_CODE (name) == IDENTIFIER_NODE)
- obstack_grow (&util_obstack,
- IDENTIFIER_POINTER (name),
- strlen (IDENTIFIER_POINTER (name)));
- else
- obstack_1grow (&util_obstack, '?');
-
- obstack_1grow (&util_obstack, '=');
-
- for (; fields; fields = TREE_CHAIN (fields))
+#ifdef OBJCPLUS
+ /* C++ static members, and things that are not fields at all,
+ should not appear in the encoding. */
+ if (TREE_CODE (fields) != FIELD_DECL || TREE_STATIC (fields))
+ continue;
+#endif
+ if (generating_instance_variables && !pointed_to)
{
- if (generating_instance_variables)
- {
- tree fname = DECL_NAME (fields);
-
- obstack_1grow (&util_obstack, '"');
- if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
- {
- obstack_grow (&util_obstack,
- IDENTIFIER_POINTER (fname),
- strlen (IDENTIFIER_POINTER (fname)));
- }
-
- obstack_1grow (&util_obstack, '"');
- }
-
- encode_field_decl (fields, curtype, format);
+ tree fname = DECL_NAME (fields);
+
+ obstack_1grow (&util_obstack, '"');
+ if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
+ obstack_grow (&util_obstack,
+ IDENTIFIER_POINTER (fname),
+ strlen (IDENTIFIER_POINTER (fname)));
+ obstack_1grow (&util_obstack, '"');
}
-
- obstack_1grow (&util_obstack, right);
- }
-
- else
- {
- obstack_1grow (&util_obstack, left);
- if (name && TREE_CODE (name) == IDENTIFIER_NODE)
- obstack_grow (&util_obstack,
- IDENTIFIER_POINTER (name),
- strlen (IDENTIFIER_POINTER (name)));
- else
- /* We have an untagged structure or a typedef. */
- obstack_1grow (&util_obstack, '?');
-
- obstack_1grow (&util_obstack, right);
+ encode_field_decl (fields, curtype, format);
}
}
+ /* Close parenth/bracket. */
+ obstack_1grow (&util_obstack, right);
}
static void
-encode_aggregate (type, curtype, format)
- tree type;
- int curtype;
- int format;
+encode_aggregate (tree type, int curtype, int format)
{
enum tree_code code = TREE_CODE (type);
{
case RECORD_TYPE:
{
- encode_aggregate_within(type, curtype, format, '{', '}');
+ encode_aggregate_within (type, curtype, format, '{', '}');
break;
}
case UNION_TYPE:
{
- encode_aggregate_within(type, curtype, format, '(', ')');
+ encode_aggregate_within (type, curtype, format, '(', ')');
break;
}
}
}
-/* Support bitfields. The current version of Objective-C does not support
- them. The string will consist of one or more "b:n"'s where n is an
- integer describing the width of the bitfield. Currently, classes in
- the kit implement a method "-(char *)describeBitfieldStruct:" that
- simulates this. If they do not implement this method, the archiver
- assumes the bitfield is 16 bits wide (padded if necessary) and packed
- according to the GNU compiler. After looking at the "kit", it appears
- that all classes currently rely on this default behavior, rather than
- hand generating this string (which is tedious). */
+/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying
+ field type. */
static void
-encode_bitfield (width)
- int width;
+encode_next_bitfield (int width)
{
char buffer[40];
sprintf (buffer, "b%d", width);
}
\f
/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS. */
-
static void
-encode_type (type, curtype, format)
- tree type;
- int curtype;
- int format;
+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)))
- {
- /* 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. */
+ switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
{
- 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)
obstack_1grow (&util_obstack, 'v');
+ else if (code == BOOLEAN_TYPE)
+ obstack_1grow (&util_obstack, 'B');
+
else if (code == ARRAY_TYPE)
encode_array (type, curtype, format);
}
static void
-encode_complete_bitfield (position, type, size)
- int position;
- tree type;
- int size;
+encode_gnu_bitfield (int position, tree type, int size)
{
enum tree_code code = TREE_CODE (type);
char buffer[40];
}
static void
-encode_field_decl (field_decl, curtype, format)
- tree field_decl;
- int curtype;
- int format;
+encode_field_decl (tree field_decl, int curtype, int format)
{
tree type;
+#ifdef OBJCPLUS
+ /* C++ static members, and things that are not fields at all,
+ should not appear in the encoding. */
+ if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl))
+ return;
+#endif
+
type = TREE_TYPE (field_decl);
- /* If this field is obviously a bitfield, or is a bitfield that has been
- clobbered to look like a ordinary integer mode, go ahead and generate
- the bitfield typing information. */
- if (flag_next_runtime)
+ /* Generate the bitfield typing information, if needed. Note the difference
+ between GNU and NeXT runtimes. */
+ if (DECL_BIT_FIELD_TYPE (field_decl))
{
- if (DECL_BIT_FIELD_TYPE (field_decl))
- encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1));
+ int size = tree_low_cst (DECL_SIZE (field_decl), 1);
+
+ if (flag_next_runtime)
+ encode_next_bitfield (size);
else
- encode_type (TREE_TYPE (field_decl), curtype, format);
+ encode_gnu_bitfield (int_bit_position (field_decl),
+ DECL_BIT_FIELD_TYPE (field_decl), size);
}
else
- {
- if (DECL_BIT_FIELD_TYPE (field_decl))
- encode_complete_bitfield (int_bit_position (field_decl),
- DECL_BIT_FIELD_TYPE (field_decl),
- tree_low_cst (DECL_SIZE (field_decl), 1));
- else
- encode_type (TREE_TYPE (field_decl), curtype, format);
- }
+ encode_type (TREE_TYPE (field_decl), curtype, format);
}
static tree
-objc_expr_last (complex_expr)
- tree complex_expr;
+objc_expr_last (tree complex_expr)
{
tree next;
return complex_expr;
}
-\f
-/* Transform a method definition into a function definition as follows:
- - synthesize the first two arguments, "self" and "_cmd". */
-void
-start_method_def (method)
- tree method;
+static void
+synth_self_and_ucmd_args (void)
{
tree decl_specs;
- /* Required to implement _msgSuper. */
- objc_method_context = method;
- UOBJC_SUPER_decl = NULL_TREE;
-
- /* Must be called BEFORE start_function. */
- pushlevel (0);
-
- /* Generate prototype declarations for arguments..."new-style". */
-
- if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL)
+ if (objc_method_context
+ && TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL)
decl_specs = build_tree_list (NULL_TREE, uprivate_record);
else
/* Really a `struct objc_class *'. However, we allow people to
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 (objc_selector_type));
push_parm_decl (build_tree_list
(build_tree_list (decl_specs,
build1 (INDIRECT_REF, NULL_TREE, ucmd_id)),
unused_list));
+}
+
+/* Transform a method definition into a function definition as follows:
+ - synthesize the first two arguments, "self" and "_cmd". */
+
+void
+start_method_def (tree method)
+{
+ /* Required to implement _msgSuper. */
+ objc_method_context = method;
+ UOBJC_SUPER_decl = NULL_TREE;
+
+ /* Must be called BEFORE start_function. */
+ push_scope ();
+ declare_parm_level ();
+
+ /* Generate prototype declarations for arguments..."new-style". */
+ synth_self_and_ucmd_args ();
/* Generate argument declarations if a keyword_decl. */
if (METHOD_SEL_ARGS (method))
(build_tree_list (arg_spec, arg_decl),
NULL_TREE));
+#ifndef OBJCPLUS
/* Unhook: restore the abstract declarator. */
TREE_OPERAND (last_expr, 0) = NULL_TREE;
+#endif
}
else
}
static void
-warn_with_method (message, mtype, method)
- const char *message;
- int mtype;
- tree method;
+warn_with_method (const char *message, int mtype, tree method)
{
/* Add a readable method name to the warning. */
- warning ("%H%s `%c%s'", &DECL_SOURCE_LOCATION (method),
+ warning ("%J%s `%c%s'", method,
message, mtype, gen_method_decl (method, errbuf));
}
/* Return 1 if METHOD is consistent with PROTO. */
static int
-comp_method_with_proto (method, proto)
- tree method, proto;
+comp_method_with_proto (tree method, tree proto)
{
/* Create a function template node at most once. */
if (!function1_template)
function1_template = make_node (FUNCTION_TYPE);
/* Install argument types - normally set by build_function_type. */
- TYPE_ARG_TYPES (function1_template) = get_arg_type_list (proto, METHOD_DEF, 0);
+ TYPE_ARG_TYPES (function1_template)
+ = get_arg_type_list (proto, METHOD_DEF, 0);
/* 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 PROTO1 is consistent with PROTO2. */
+/* Return 1 if TYPE1 is equivalent to TYPE2. */
static int
-comp_proto_with_proto (proto0, proto1)
- tree proto0, proto1;
+objc_types_are_equivalent (tree type1, tree type2)
{
- /* Create a couple of function_template nodes at most once. */
- if (!function1_template)
- function1_template = make_node (FUNCTION_TYPE);
- if (!function2_template)
- function2_template = make_node (FUNCTION_TYPE);
+ if (type1 == type2)
+ return 1;
+ if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
+ return 0;
+ type1 = TYPE_PROTOCOL_LIST (type1);
+ type2 = TYPE_PROTOCOL_LIST (type2);
+ if (list_length (type1) == list_length (type2))
+ {
+ for (; type2; type2 = TREE_CHAIN (type2))
+ if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2)))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+/* Return 1 if PROTO1 is equivalent to PROTO2. */
+
+static int
+comp_proto_with_proto (tree proto1, tree proto2)
+{
+ 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;
- /* Install argument types; normally set by build_function_type. */
- TYPE_ARG_TYPES (function1_template) = get_arg_type_list (proto0, METHOD_REF, 0);
- TYPE_ARG_TYPES (function2_template) = get_arg_type_list (proto1, METHOD_REF, 0);
+ /* Compare return types. */
+ type1 = groktypename (TREE_TYPE (proto1));
+ type2 = groktypename (TREE_TYPE (proto2));
- /* Install return type. */
- TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto0));
- TREE_TYPE (function2_template) = groktypename (TREE_TYPE (proto1));
+ if (!objc_types_are_equivalent (type1, type2))
+ 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)))
+ return 0;
+ }
- return comptypes (function1_template, function2_template, false);
+ return (!type1 && !type2);
}
/* - Generate an identifier for the function. the format is "_n_cls",
- If we have a prototype, check for type consistency. */
static void
-really_start_method (method, parmlist)
- tree method, parmlist;
+really_start_method (tree method, tree parmlist)
{
tree sc_spec, ret_spec, ret_decl, decl_specs;
tree method_decl, method_id;
method_id = get_identifier (buf);
+#ifdef OBJCPLUS
+ /* Objective-C methods cannot be overloaded, so we don't need
+ the type encoding appended. It looks bad anyway... */
+ push_lang_context (lang_name_c);
+#endif
+
method_decl = build_nt (CALL_EXPR, method_id, parmlist, NULL_TREE);
/* Check the declarator portion of the return type for the method. */
TREE_VALUE (TREE_TYPE (method)) = NULL_TREE;
}
+#ifdef OBJCPLUS
+ /* set self_decl from the first argument...this global is used by
+ * build_ivar_reference().build_indirect_ref().
+ */
+ self_decl = DECL_ARGUMENTS (current_function_decl);
+
+ /* snaroff (3/28/96): when compiling with -Wall, this suppresses
+ * the following: warning:unused parameter `struct objc_selector * _cmd'
+ */
+ TREE_USED (self_decl) = 1;
+ TREE_USED (TREE_CHAIN (self_decl)) = 1;
+ /* Ditto for the underlying (static) C function. */
+ TREE_USED (current_function_decl) = 1;
+ pop_lang_context ();
+#endif
+
METHOD_DEFINITION (method) = current_function_decl;
/* Check consistency...start_function, pushdecl, duplicate_decls. */
if (implementation_template != objc_implementation_context)
{
- tree proto;
-
- if (TREE_CODE (method) == INSTANCE_METHOD_DECL)
- proto = lookup_instance_method_static (implementation_template,
- METHOD_SEL_NAME (method));
- else
- proto = lookup_class_method_static (implementation_template,
- METHOD_SEL_NAME (method));
+ tree proto
+ = lookup_method_static (implementation_template,
+ 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);
}
}
}
/* The following routine is always called...this "architecture" is to
accommodate "old-style" variable length selectors.
-
+
- a:a b:b // prototype ; id c; id d; // old-style. */
void
-continue_method_def ()
+continue_method_def (void)
{
tree parmlist;
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
build_ivar_reference calling build_indirect_ref. */
self_decl = TREE_PURPOSE (parmlist);
+#endif /* !OBJCPLUS */
- poplevel (0, 0, 0);
+ pop_scope ();
really_start_method (objc_method_context, parmlist);
store_parm_decls ();
}
-/* Called by the parser, from the `pushlevel' production. */
-
-void
-add_objc_decls ()
-{
- if (!UOBJC_SUPER_decl)
- {
- UOBJC_SUPER_decl = start_decl (get_identifier (UTAG_SUPER),
- build_tree_list (NULL_TREE,
- objc_super_template),
- 0, NULL_TREE);
-
- finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE);
-
- /* This prevents `unused variable' warnings when compiling with -Wall. */
- TREE_USED (UOBJC_SUPER_decl) = 1;
- DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1;
- }
-}
+static void *UOBJC_SUPER_scope = 0;
/* _n_Method (id self, SEL sel, ...)
{
} */
tree
-get_super_receiver ()
+get_super_receiver (void)
{
if (objc_method_context)
{
tree super_expr, super_expr_list;
+ if (!UOBJC_SUPER_decl)
+ {
+ UOBJC_SUPER_decl = start_decl (get_identifier (TAG_SUPER),
+ build_tree_list (NULL_TREE,
+ objc_super_template),
+ 0, NULL_TREE);
+
+ finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE);
+
+ /* This prevents `unused variable' warnings when compiling with -Wall. */
+ TREE_USED (UOBJC_SUPER_decl) = 1;
+ DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1;
+
+ UOBJC_SUPER_scope = objc_get_current_scope ();
+ }
+
/* Set receiver to self. */
super_expr = build_component_ref (UOBJC_SUPER_decl, self_id);
super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl);
- super_expr_list = build_tree_list (NULL_TREE, super_expr);
+ super_expr_list = 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)
{
return error_mark_node;
}
- if (flag_next_runtime)
+ if (flag_next_runtime && !flag_zero_link)
{
- super_class = get_class_reference (super_name);
+ super_class = objc_get_class_reference (super_name);
if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
- /* Cast the super class to 'id', since the user may not have
- included <objc/objc-class.h>, leaving 'struct objc_class'
- an incomplete type. */
+ /* If we are in a class method, we must retrieve the
+ _metaclass_ for the current class, pointed at by
+ the class's "isa" pointer. The following assumes that
+ "isa" is the first ivar in a class (which it must be). */
super_class
- = build_component_ref (build_indirect_ref
- (build_c_cast (id_type, super_class), "->"),
- get_identifier ("isa"));
+ = build_indirect_ref
+ (build_c_cast (build_pointer_type (objc_class_type),
+ super_class), "unary *");
}
else
{
IDENTIFIER_POINTER (super_name))));
}
- TREE_TYPE (super_class) = TREE_TYPE (ucls_super_ref);
- super_expr = build_modify_expr (super_expr, NOP_EXPR, super_class);
+ super_expr
+ = build_modify_expr (super_expr, NOP_EXPR,
+ build_c_cast (TREE_TYPE (super_expr),
+ super_class));
}
- chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
+ super_expr_list = build_compound_expr (super_expr_list, super_expr);
super_expr = build_unary_op (ADDR_EXPR, UOBJC_SUPER_decl, 0);
- chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
+ super_expr_list = build_compound_expr (super_expr_list, super_expr);
- return build_compound_expr (super_expr_list);
+ return super_expr_list;
}
else
{
}
}
-static tree
-encode_method_def (func_decl)
- tree func_decl;
-{
- tree parms;
- int stack_size;
- HOST_WIDE_INT max_parm_end = 0;
- char buffer[40];
- tree result;
-
- /* Return type. */
- encode_type (TREE_TYPE (TREE_TYPE (func_decl)),
- obstack_object_size (&util_obstack),
- OBJC_ENCODE_INLINE_DEFS);
-
- /* Stack size. */
- for (parms = DECL_ARGUMENTS (func_decl); parms;
- parms = TREE_CHAIN (parms))
- {
- HOST_WIDE_INT parm_end = (forwarding_offset (parms)
- + int_size_in_bytes (TREE_TYPE (parms)));
-
- if (! offset_is_register && parm_end > max_parm_end)
- max_parm_end = parm_end;
- }
-
- stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET;
-
- sprintf (buffer, "%d", stack_size);
- obstack_grow (&util_obstack, buffer, strlen (buffer));
-
- /* Argument types. */
- for (parms = DECL_ARGUMENTS (func_decl); parms;
- parms = TREE_CHAIN (parms))
- {
- /* Type. */
- encode_type (TREE_TYPE (parms),
- obstack_object_size (&util_obstack),
- OBJC_ENCODE_INLINE_DEFS);
-
- /* Compute offset. */
- sprintf (buffer, "%d", forwarding_offset (parms));
-
- /* Indicate register. */
- if (offset_is_register)
- obstack_1grow (&util_obstack, '+');
-
- obstack_grow (&util_obstack, buffer, strlen (buffer));
- }
+/* When exiting a scope, sever links to a 'super' declaration (if any)
+ therein contained. */
- /* Null terminate string. */
- obstack_1grow (&util_obstack, 0);
- result = get_identifier (obstack_finish (&util_obstack));
- obstack_free (&util_obstack, util_firstobj);
- return result;
+void
+objc_clear_super_receiver (void)
+{
+ if (objc_method_context
+ && UOBJC_SUPER_scope == objc_get_current_scope ()) {
+ UOBJC_SUPER_decl = 0;
+ UOBJC_SUPER_scope = 0;
+ }
}
static void
-objc_expand_function_end ()
+objc_expand_function_end (void)
{
- METHOD_ENCODING (objc_method_context) = encode_method_def (current_function_decl);
+ /* This routine may also get called for C functions, including those
+ nested within ObjC methods. In such cases, method encoding is
+ meaningless. */
+ if (objc_method_context == NULL_TREE
+ || DECL_INITIAL (objc_method_context) != current_function_decl)
+ return;
+
+ METHOD_ENCODING (objc_method_context)
+ = encode_method_prototype (objc_method_context);
}
void
-finish_method_def ()
+finish_method_def (void)
{
lang_expand_function_end = objc_expand_function_end;
- finish_function (0, 1);
+ /* We cannot validly inline ObjC methods, at least not without a language
+ extension to declare that a method need not be dynamically
+ dispatched, so suppress all thoughts of doing so. */
+ DECL_INLINE (current_function_decl) = 0;
+ DECL_UNINLINABLE (current_function_decl) = 1;
+
+ finish_function ();
lang_expand_function_end = NULL;
/* Required to implement _msgSuper. This must be done AFTER finish_function,
#if 0
int
-lang_report_error_function (decl)
- tree decl;
+lang_report_error_function (tree decl)
{
if (objc_method_context)
{
#endif
static int
-is_complex_decl (type)
- tree type;
+is_complex_decl (tree type)
{
return (TREE_CODE (type) == ARRAY_TYPE
|| TREE_CODE (type) == FUNCTION_TYPE
static char tmpbuf[256];
static void
-adorn_decl (decl, str)
- tree decl;
- char *str;
+adorn_decl (tree decl, char *str)
{
enum tree_code code = TREE_CODE (decl);
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");
}
static char *
-gen_declarator (decl, buf, name)
- tree decl;
- char *buf;
- const char *name;
+gen_declarator (tree decl, char *buf, const char *name)
{
if (decl)
{
}
static void
-gen_declspecs (declspecs, buf, raw)
- tree declspecs;
- char *buf;
- int raw;
+gen_declspecs (tree declspecs, char *buf, int raw)
{
if (raw)
{
strcat (buf, IDENTIFIER_POINTER (aspec));
else if (TREE_CODE (aspec) == RECORD_TYPE)
{
- if (TYPE_NAME (aspec))
+ if (OBJC_TYPE_NAME (aspec))
{
tree protocol_list = TYPE_PROTOCOL_LIST (aspec);
if (! TREE_STATIC_TEMPLATE (aspec))
strcat (buf, "struct ");
- strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
+ strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec)));
/* NEW!!! */
if (protocol_list)
else if (TREE_CODE (aspec) == UNION_TYPE)
{
- if (TYPE_NAME (aspec))
+ if (OBJC_TYPE_NAME (aspec))
{
if (! TREE_STATIC_TEMPLATE (aspec))
strcat (buf, "union ");
- strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
+ strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec)));
}
else
strcat (buf, "untagged union");
else if (TREE_CODE (aspec) == ENUMERAL_TYPE)
{
- if (TYPE_NAME (aspec))
+ if (OBJC_TYPE_NAME (aspec))
{
if (! TREE_STATIC_TEMPLATE (aspec))
strcat (buf, "enum ");
- strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
+ strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec)));
}
else
strcat (buf, "untagged enum");
else
{
/* Type qualifiers. */
- if (TREE_READONLY (declspecs))
+ if (TYPE_READONLY (declspecs))
strcat (buf, "const ");
if (TYPE_VOLATILE (declspecs))
strcat (buf, "volatile ");
break;
case RECORD_TYPE:
- if (TYPE_NAME (declspecs)
- && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
+ if (OBJC_TYPE_NAME (declspecs)
+ && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
{
tree protocol_list = TYPE_PROTOCOL_LIST (declspecs);
if (! TREE_STATIC_TEMPLATE (declspecs))
strcat (buf, "struct ");
- strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
+ strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs)));
if (protocol_list)
{
break;
case UNION_TYPE:
- if (TYPE_NAME (declspecs)
- && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
+ if (OBJC_TYPE_NAME (declspecs)
+ && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
{
strcat (buf, "union ");
- strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
+ strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs)));
strcat (buf, " ");
}
break;
case ENUMERAL_TYPE:
- if (TYPE_NAME (declspecs)
- && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
+ if (OBJC_TYPE_NAME (declspecs)
+ && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
{
strcat (buf, "enum ");
- strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
+ strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs)));
strcat (buf, " ");
}
}
}
break;
-
+
default:
break;
}
buffer, overwriting the buffer. */
static char *
-gen_declaration (atype_or_adecl, buf)
- tree atype_or_adecl;
- char *buf;
+gen_declaration (tree atype_or_adecl, char *buf)
{
buf[0] = '\0';
gen_declaration_1 (atype_or_adecl, buf);
given buffer. */
static void
-gen_declaration_1 (atype_or_adecl, buf)
- tree atype_or_adecl;
- char *buf;
+gen_declaration_1 (tree atype_or_adecl, char *buf)
{
char declbuf[256];
{
tree declspecs; /* "identifier_node", "record_type" */
tree declarator; /* "array_ref", "indirect_ref", "call_expr"... */
+ tree width = NULL_TREE; /* for bitfields */
/* We have a "raw", abstract declarator (typename). */
declarator = TREE_VALUE (atype_or_adecl);
+ /* In the case of raw ivars, the declarator itself is a list,
+ and contains bitfield widths. */
+ if (declarator && TREE_CODE (declarator) == TREE_LIST)
+ {
+ width = TREE_VALUE (declarator);
+ declarator = TREE_PURPOSE (declarator);
+ }
declspecs = TREE_PURPOSE (atype_or_adecl);
gen_declspecs (declspecs, buf, 1);
strcat (buf, " ");
strcat (buf, gen_declarator (declarator, declbuf, ""));
}
+ if (width)
+ sprintf (buf + strlen (buf), ": " HOST_WIDE_INT_PRINT_UNSIGNED,
+ TREE_INT_CST_LOW (width));
}
else
buffer (overwriting) and return a pointer to the buffer. */
static char *
-gen_method_decl (method, buf)
- tree method;
- char *buf;
+gen_method_decl (tree method, char *buf)
{
tree chain;
prints out an @interface declaration of all classes compiled in
this run); potentially useful for debugging the compiler too. */
static void
-dump_interface (fp, chain)
- FILE *fp;
- tree chain;
+dump_interface (FILE *fp, tree chain)
{
/* FIXME: A heap overflow here whenever a method (or ivar)
declaration is so long that it doesn't fit in the buffer. The
fprintf (fp, "\n@interface %s", my_name);
- /* CLASS_SUPER_NAME is used to store the superclass name for
+ /* CLASS_SUPER_NAME is used to store the superclass name for
classes, and the category name for categories. */
if (CLASS_SUPER_NAME (chain))
{
const char *name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain));
-
- if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE
+
+ if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE
|| TREE_CODE (chain) == CATEGORY_INTERFACE_TYPE)
{
fprintf (fp, " (%s)\n", name);
/* Demangle function for Objective-C */
static const char *
-objc_demangle (mangled)
- const char *mangled;
+objc_demangle (const char *mangled)
{
char *demangled, *cp;
}
const char *
-objc_printable_name (decl, kind)
- tree decl;
- int kind ATTRIBUTE_UNUSED;
+objc_printable_name (tree decl, int kind ATTRIBUTE_UNUSED)
{
return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)));
}
static void
-init_objc ()
+init_objc (void)
{
gcc_obstack_init (&util_obstack);
util_firstobj = (char *) obstack_finish (&util_obstack);
}
\f
static void
-finish_objc ()
+finish_objc (void)
{
struct imp_entry *impent;
tree chain;
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)
UOBJC_CLASS_decl = impent->class_decl;
UOBJC_METACLASS_decl = impent->meta_decl;
-
+
/* Dump the @interface of each class as we compile it, if the
-gen-decls option is in use. TODO: Dump the classes in the
order they were found, rather than in reverse order as we
{
dump_interface (gen_declaration_file, objc_implementation_context);
}
-
+
if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
{
/* all of the following reference the string pool... */
if (protocol_chain)
generate_protocols ();
+ if (flag_replace_objc_classes && imp_list)
+ generate_objc_image_info ();
+
if (objc_implementation_context || class_names_chain || objc_static_instances
|| meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
{
selector which has multiple methods. */
for (slot = 0; slot < SIZEHASHTABLE; slot++)
- for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
- if (hsh->list)
- {
- tree meth = hsh->key;
- char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL
- ? '-' : '+');
- attr loop;
-
- warning ("potential selector conflict for method `%s'",
- IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
- warn_with_method ("found", type, meth);
- for (loop = hsh->list; loop; loop = loop->next)
- warn_with_method ("found", type, loop->value);
- }
-
- for (slot = 0; slot < SIZEHASHTABLE; slot++)
- for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
- if (hsh->list)
- {
- tree meth = hsh->key;
- char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL
- ? '-' : '+');
- attr loop;
-
- warning ("potential selector conflict for method `%s'",
- IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
- warn_with_method ("found", type, meth);
- for (loop = hsh->list; loop; loop = loop->next)
- warn_with_method ("found", type, loop->value);
- }
+ {
+ for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
+ check_duplicates (hsh, 0, 1);
+ for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
+ check_duplicates (hsh, 0, 1);
+ }
}
warn_missing_braces = save_warn_missing_braces;
/* Subroutines of finish_objc. */
static void
-generate_classref_translation_entry (chain)
- tree chain;
+generate_classref_translation_entry (tree chain)
{
tree expr, name, decl_specs, decl, sc_spec;
tree type;
}
static void
-handle_class_ref (chain)
- tree chain;
+handle_class_ref (tree chain)
{
const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain));
char *string = (char *) alloca (strlen (name) + 30);
TREE_PUBLIC (decl) = 1;
pushdecl (decl);
- rest_of_decl_compilation (decl, 0, 0, 0);
+ rest_of_decl_compilation (decl, 0, 0);
/* Make a decl for the address. */
sprintf (string, "%sobjc_class_ref_%s",
TREE_USED (decl) = 1;
pushdecl (decl);
- rest_of_decl_compilation (decl, 0, 0, 0);
+ rest_of_decl_compilation (decl, 0, 0);
}
static void
-handle_impent (impent)
- struct imp_entry *impent;
+handle_impent (struct imp_entry *impent)
{
char *string;
{
tree decl, init;
- init = build_int_2 (0, 0);
- TREE_TYPE (init) = c_common_type_for_size (BITS_PER_WORD, 1);
+ init = build_int_cst (c_common_type_for_size (BITS_PER_WORD, 1), 0);
decl = build_decl (VAR_DECL, get_identifier (string), TREE_TYPE (init));
TREE_PUBLIC (decl) = 1;
TREE_READONLY (decl) = 1;
}
}
\f
+/* 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. */
+
+/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */
+
+static void
+generate_objc_image_info (void)
+{
+ tree sc_spec, decl, initlist;
+
+ sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]);
+ decl
+ = start_decl (get_identifier ("_OBJC_IMAGE_INFO"),
+ tree_cons (NULL_TREE,
+ build_array_type
+ (integer_type_node,
+ build_index_type (build_int_cst (NULL_TREE, 1))),
+ sc_spec),
+ 1,
+ NULL_TREE);
+
+ initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 1), initlist);
+ initlist = build_constructor (TREE_TYPE (decl), nreverse (initlist));
+
+ TREE_USED (decl) = DECL_IGNORED_P (decl) = DECL_ARTIFICIAL (decl) = 1;
+ TREE_CONSTANT (initlist) = TREE_STATIC (initlist) = 1;
+ finish_decl (decl, initlist, NULL_TREE);
+}
+
/* Look up ID as an instance variable. */
+
tree
-lookup_objc_ivar (id)
- tree id;
+objc_lookup_ivar (tree id)
{
tree decl;
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);
}
}
#include "gt-objc-objc-act.h"
-#include "gtype-objc.h"