blob: a0b20fea00bfe001c06f78676fba4ce877e32358 [file] [log] [blame]
/* Implement classes and message passing for Objective C.
Copyright (C) 1992, 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
Contributed by Steve Naroff.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Purpose: This module implements the Objective-C 4.0 language.
compatibility issues (with the Stepstone translator):
- does not recognize the following 3.3 constructs.
@requires, @classes, @messages, = (...)
- methods with variable arguments must conform to ANSI standard.
- tagged structure definitions that appear in BOTH the interface
and implementation are not allowed.
- public/private: all instance variables are public within the
context of the implementation...I consider this to be a bug in
the translator.
- statically allocated objects are not supported. the user will
receive an error if this service is requested.
code generation `options':
- OBJC_INT_SELECTORS */
#include <stdio.h>
#include "config.h"
#include "tree.h"
#include "c-tree.h"
#include "c-lex.h"
#include "flags.h"
#include "objc-act.h"
#include "input.h"
#include "except.h"
#include "function.h"
/* This is the default way of generating a method name. */
/* I am not sure it is really correct.
Perhaps there's a danger that it will make name conflicts
if method names contain underscores. -- rms. */
#ifndef OBJC_GEN_METHOD_LABEL
#define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \
do { \
char *temp; \
sprintf ((BUF), "_%s_%s_%s_%s", \
((IS_INST) ? "i" : "c"), \
(CLASS_NAME), \
((CAT_NAME)? (CAT_NAME) : ""), \
(SEL_NAME)); \
for (temp = (BUF); *temp; temp++) \
if (*temp == ':') *temp = '_'; \
} while (0)
#endif
/* These need specifying. */
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
/* Define the special tree codes that we use. */
/* Table indexed by tree code giving a string containing a character
classifying the tree code. Possibilities are
t, d, s, c, r, <, 1 and 2. See objc-tree.def for details. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
char *objc_tree_code_type[] = {
"x",
#include "objc-tree.def"
};
#undef DEFTREECODE
/* Table indexed by tree code giving number of expression
operands beyond the fixed part of the node structure.
Not used for types or decls. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
int objc_tree_code_length[] = {
0,
#include "objc-tree.def"
};
#undef DEFTREECODE
/* Names of tree components.
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
char *objc_tree_code_name[] = {
"@@dummy",
#include "objc-tree.def"
};
#undef DEFTREECODE
/* Set up for use of obstacks. */
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
/* 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;
/* List of classes with list of their static instances. */
static tree objc_static_instances = NULL_TREE;
/* The declaration of the array administrating the static instances. */
static tree static_instances_decl = NULL_TREE;
/* for encode_method_def */
#include "rtl.h"
#include "c-parse.h"
#define OBJC_VERSION (flag_next_runtime ? 5 : 8)
#define PROTOCOL_VERSION 2
#define OBJC_ENCODE_INLINE_DEFS 0
#define OBJC_ENCODE_DONT_INLINE_DEFS 1
/*** Private Interface (procedures) ***/
/* Used by compile_file. */
static void init_objc PROTO((void));
static void finish_objc PROTO((void));
/* Code generation. */
static void synth_module_prologue PROTO((void));
static tree build_constructor PROTO((tree, tree));
static char *build_module_descriptor PROTO((void));
static tree init_module_descriptor PROTO((tree));
static tree build_objc_method_call PROTO((int, tree, tree,
tree, tree, tree));
static void generate_strings PROTO((void));
static tree get_proto_encoding PROTO((tree));
static void build_selector_translation_table PROTO((void));
static tree build_ivar_chain PROTO((tree, int));
static tree objc_add_static_instance PROTO((tree, tree));
static tree build_ivar_template PROTO((void));
static tree build_method_template PROTO((void));
static tree build_private_template PROTO((tree));
static void build_class_template PROTO((void));
static void build_selector_template PROTO((void));
static void build_category_template PROTO((void));
static tree build_super_template PROTO((void));
static tree build_category_initializer PROTO((tree, tree, tree,
tree, tree, tree));
static tree build_protocol_initializer PROTO((tree, tree, tree,
tree, tree));
static void synth_forward_declarations PROTO((void));
static void generate_ivar_lists PROTO((void));
static void generate_dispatch_tables PROTO((void));
static void generate_shared_structures PROTO((void));
static tree generate_protocol_list PROTO((tree));
static void generate_forward_declaration_to_string_table PROTO((void));
static void build_protocol_reference PROTO((tree));
static tree init_selector PROTO((int));
static tree build_keyword_selector PROTO((tree));
static tree synth_id_with_class_suffix PROTO((char *, tree));
/* From expr.c */
extern int apply_args_register_offset PROTO((int));
/* Misc. bookkeeping */
typedef struct hashed_entry *hash;
typedef struct hashed_attribute *attr;
struct hashed_attribute
{
attr next;
tree value;
};
struct hashed_entry
{
attr list;
hash next;
tree key;
};
static void hash_init PROTO((void));
static void hash_enter PROTO((hash *, tree));
static hash hash_lookup PROTO((hash *, tree));
static void hash_add_attr PROTO((hash, tree));
static tree lookup_method PROTO((tree, tree));
static tree lookup_instance_method_static PROTO((tree, tree));
static tree lookup_class_method_static PROTO((tree, tree));
static tree add_class PROTO((tree));
static void add_category PROTO((tree, tree));
enum string_section
{
class_names, /* class, category, protocol, module names */
meth_var_names, /* method and variable names */
meth_var_types /* method and variable type descriptors */
};
static tree add_objc_string PROTO((tree,
enum string_section));
static tree build_objc_string_decl PROTO((tree,
enum string_section));
static tree build_selector_reference_decl PROTO((tree));
/* Protocol additions. */
static tree add_protocol PROTO((tree));
static tree lookup_protocol PROTO((tree));
static tree lookup_and_install_protocols PROTO((tree));
/* Type encoding. */
static void encode_type_qualifiers PROTO((tree));
static void encode_pointer PROTO((tree, int, int));
static void encode_array PROTO((tree, int, int));
static void encode_aggregate PROTO((tree, int, int));
static void encode_bitfield PROTO((int, int));
static void encode_type PROTO((tree, int, int));
static void encode_field_decl PROTO((tree, int, int));
static void really_start_method PROTO((tree, tree));
static int comp_method_with_proto PROTO((tree, tree));
static int comp_proto_with_proto PROTO((tree, tree));
static tree get_arg_type_list PROTO((tree, int, int));
static tree expr_last PROTO((tree));
/* Utilities for debugging and error diagnostics. */
static void warn_with_method PROTO((char *, int, tree));
static void error_with_ivar PROTO((char *, tree, tree));
static char *gen_method_decl PROTO((tree, char *));
static char *gen_declaration PROTO((tree, char *));
static char *gen_declarator PROTO((tree, char *, char *));
static int is_complex_decl PROTO((tree));
static void adorn_decl PROTO((tree, char *));
static void dump_interface PROTO((FILE *, tree));
/* Everything else. */
static void objc_fatal PROTO((void));
static tree define_decl PROTO((tree, tree));
static tree lookup_method_in_protocol_list PROTO((tree, tree, int));
static tree lookup_protocol_in_reflist PROTO((tree, tree));
static tree create_builtin_decl PROTO((enum tree_code,
tree, char *));
static tree my_build_string PROTO((int, char *));
static void build_objc_symtab_template PROTO((void));
static tree init_def_list PROTO((tree));
static tree init_objc_symtab PROTO((tree));
static void forward_declare_categories PROTO((void));
static void generate_objc_symtab_decl PROTO((void));
static tree build_selector PROTO((tree));
static tree build_msg_pool_reference PROTO((int));
static tree build_typed_selector_reference PROTO((tree, tree));
static tree build_selector_reference PROTO((tree));
static tree build_class_reference_decl PROTO((tree));
static void add_class_reference PROTO((tree));
static tree objc_copy_list PROTO((tree, tree *));
static tree build_protocol_template PROTO((void));
static tree build_descriptor_table_initializer PROTO((tree, tree));
static tree build_method_prototype_list_template PROTO((tree, int));
static tree build_method_prototype_template PROTO((void));
static int forwarding_offset PROTO((tree));
static tree encode_method_prototype PROTO((tree, tree));
static tree generate_descriptor_table PROTO((tree, char *, int, tree, tree));
static void generate_method_descriptors PROTO((tree));
static tree build_tmp_function_decl PROTO((void));
static void hack_method_prototype PROTO((tree, tree));
static void generate_protocol_references PROTO((tree));
static void generate_protocols PROTO((void));
static void check_ivars PROTO((tree, tree));
static tree build_ivar_list_template PROTO((tree, int));
static tree build_method_list_template PROTO((tree, int));
static tree build_ivar_list_initializer PROTO((tree, tree));
static tree generate_ivars_list PROTO((tree, char *,
int, tree));
static tree build_dispatch_table_initializer PROTO((tree, tree));
static tree generate_dispatch_table PROTO((tree, char *,
int, tree));
static tree build_shared_structure_initializer PROTO((tree, tree, tree, tree,
tree, int, tree, tree,
tree));
static void generate_category PROTO((tree));
static int is_objc_type_qualifier PROTO((tree));
static tree adjust_type_for_id_default PROTO((tree));
static tree check_duplicates PROTO((hash));
static tree receiver_is_class_object PROTO((tree));
static int check_methods PROTO((tree, tree, int));
static int conforms_to_protocol PROTO((tree, tree));
static void check_protocols PROTO((tree, char *, char *));
static tree encode_method_def PROTO((tree));
static void gen_declspecs PROTO((tree, char *, int));
static void generate_classref_translation_entry PROTO((tree));
static void handle_class_ref PROTO((tree));
/*** Private Interface (data) ***/
/* Reserved tag definitions. */
#define TYPE_ID "id"
#define TAG_OBJECT "objc_object"
#define TAG_CLASS "objc_class"
#define TAG_SUPER "objc_super"
#define TAG_SELECTOR "objc_selector"
#define UTAG_CLASS "_objc_class"
#define UTAG_IVAR "_objc_ivar"
#define UTAG_IVAR_LIST "_objc_ivar_list"
#define UTAG_METHOD "_objc_method"
#define UTAG_METHOD_LIST "_objc_method_list"
#define UTAG_CATEGORY "_objc_category"
#define UTAG_MODULE "_objc_module"
#define UTAG_STATICS "_objc_statics"
#define UTAG_SYMTAB "_objc_symtab"
#define UTAG_SUPER "_objc_super"
#define UTAG_SELECTOR "_objc_selector"
#define UTAG_PROTOCOL "_objc_protocol"
#define UTAG_PROTOCOL_LIST "_objc_protocol_list"
#define UTAG_METHOD_PROTOTYPE "_objc_method_prototype"
#define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list"
#define STRING_OBJECT_CLASS_NAME "NXConstantString"
#define PROTOCOL_OBJECT_CLASS_NAME "Protocol"
static char *TAG_GETCLASS;
static char *TAG_GETMETACLASS;
static char *TAG_MSGSEND;
static char *TAG_MSGSENDSUPER;
static char *TAG_EXECCLASS;
/* Set by `continue_class' and checked by `is_public'. */
#define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC (record_type))
#define TYPED_OBJECT(type) \
(TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type))
/* Some commonly used instances of "identifier_node". */
static tree self_id, ucmd_id;
static tree unused_list;
static tree self_decl, umsg_decl, umsg_super_decl;
static tree objc_get_class_decl, objc_get_meta_class_decl;
static tree super_type, selector_type, id_type, objc_class_type;
static tree instance_type, protocol_type;
/* Type checking macros. */
#define IS_ID(TYPE) \
(TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (id_type))
#define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
(IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
#define IS_SUPER(TYPE) \
(super_type && TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (super_type))
static tree class_chain = NULL_TREE;
static tree alias_chain = NULL_TREE;
static tree interface_chain = NULL_TREE;
static tree protocol_chain = NULL_TREE;
/* Chains to manage selectors that are referenced and defined in the
module. */
static tree cls_ref_chain = NULL_TREE; /* Classes referenced. */
static tree sel_ref_chain = NULL_TREE; /* Selectors referenced. */
/* Chains to manage uniquing of strings. */
static tree class_names_chain = NULL_TREE;
static tree meth_var_names_chain = NULL_TREE;
static tree meth_var_types_chain = NULL_TREE;
/* Hash tables to manage the global pool of method prototypes. */
static hash *nst_method_hash_list = 0;
static hash *cls_method_hash_list = 0;
/* Backend data declarations. */
static tree UOBJC_SYMBOLS_decl;
static tree UOBJC_INSTANCE_VARIABLES_decl, UOBJC_CLASS_VARIABLES_decl;
static tree UOBJC_INSTANCE_METHODS_decl, UOBJC_CLASS_METHODS_decl;
static tree UOBJC_CLASS_decl, UOBJC_METACLASS_decl;
static tree UOBJC_SELECTOR_TABLE_decl;
static tree UOBJC_MODULES_decl;
static tree UOBJC_STRINGS_decl;
/* The following are used when compiling a class implementation.
implementation_template will normally be an interface, however if
none exists this will be equal to implementation_context...it is
set in start_class. */
static tree implementation_context = NULL_TREE;
static tree implementation_template = NULL_TREE;
struct imp_entry
{
struct imp_entry *next;
tree imp_context;
tree imp_template;
tree class_decl; /* _OBJC_CLASS_<my_name>; */
tree meta_decl; /* _OBJC_METACLASS_<my_name>; */
};
static void handle_impent PROTO((struct imp_entry *));
static struct imp_entry *imp_list = 0;
static int imp_count = 0; /* `@implementation' */
static int cat_count = 0; /* `@category' */
static tree objc_class_template, objc_category_template, uprivate_record;
static tree objc_protocol_template, objc_selector_template;
static tree ucls_super_ref, uucls_super_ref;
static tree objc_method_template, objc_ivar_template;
static tree objc_symtab_template, objc_module_template;
static tree objc_super_template, objc_object_reference;
static tree objc_object_id, objc_class_id, objc_id_id;
static tree constant_string_id;
static tree constant_string_type;
static tree UOBJC_SUPER_decl;
static tree method_context = NULL_TREE;
static int method_slot = 0; /* Used by start_method_def, */
#define BUFSIZE 1024
static char *errbuf; /* Buffer for error diagnostics */
/* Data imported from tree.c. */
extern enum debug_info_type write_symbols;
/* Data imported from toplev.c. */
extern char *dump_base_name;
/* Generate code for GNU or NeXT runtime environment. */
#ifdef NEXT_OBJC_RUNTIME
int flag_next_runtime = 1;
#else
int flag_next_runtime = 0;
#endif
int flag_typed_selectors;
/* Open and close the file for outputting class declarations, if requested. */
int flag_gen_declaration = 0;
FILE *gen_declaration_file;
/* Warn if multiple methods are seen for the same selector, but with
different argument types. */
int warn_selector = 0;
/* Warn if methods required by a protocol are not implemented in the
class adopting it. When turned off, methods inherited to that
class are also considered implemented */
int flag_warn_protocol = 1;
/* Tells "encode_pointer/encode_aggregate" whether we are generating
type descriptors for instance variables (as opposed to methods).
Type descriptors for instance variables contain more information
than methods (for static typing and embedded structures). This
was added to support features being planned for dbkit2. */
static int generating_instance_variables = 0;
void
lang_init ()
{
#if !USE_CPPLIB
/* The beginning of the file is a new line; check for #.
With luck, we discover the real source file's name from that
and put it in input_filename. */
ungetc (check_newline (), finput);
#endif
/* The line number can be -1 if we had -g3 and the input file
had a directive specifying line 0. But we want predefined
functions to have a line number of 0, not -1. */
if (lineno == -1)
lineno = 0;
/* If gen_declaration desired, open the output file. */
if (flag_gen_declaration)
{
int dump_base_name_length = strlen (dump_base_name);
register char *dumpname = (char *) xmalloc (dump_base_name_length + 7);
strcpy (dumpname, dump_base_name);
strcat (dumpname, ".decl");
gen_declaration_file = fopen (dumpname, "w");
if (gen_declaration_file == 0)
pfatal_with_name (dumpname);
}
if (flag_next_runtime)
{
TAG_GETCLASS = "objc_getClass";
TAG_GETMETACLASS = "objc_getMetaClass";
TAG_MSGSEND = "objc_msgSend";
TAG_MSGSENDSUPER = "objc_msgSendSuper";
TAG_EXECCLASS = "__objc_execClass";
}
else
{
TAG_GETCLASS = "objc_get_class";
TAG_GETMETACLASS = "objc_get_meta_class";
TAG_MSGSEND = "objc_msg_lookup";
TAG_MSGSENDSUPER = "objc_msg_lookup_super";
TAG_EXECCLASS = "__objc_exec_class";
flag_typed_selectors = 1;
}
if (doing_objc_thang)
init_objc ();
}
static void
objc_fatal ()
{
fatal ("Objective-C text in C source file");
}
void
finish_file ()
{
if (doing_objc_thang)
finish_objc (); /* Objective-C finalization */
if (gen_declaration_file)
fclose (gen_declaration_file);
}
void
lang_finish ()
{
}
char *
lang_identify ()
{
return "objc";
}
int
lang_decode_option (p)
char *p;
{
if (!strcmp (p, "-lang-objc"))
doing_objc_thang = 1;
else if (!strcmp (p, "-gen-decls"))
flag_gen_declaration = 1;
else if (!strcmp (p, "-Wselector"))
warn_selector = 1;
else if (!strcmp (p, "-Wno-selector"))
warn_selector = 0;
else if (!strcmp (p, "-Wprotocol"))
flag_warn_protocol = 1;
else if (!strcmp (p, "-Wno-protocol"))
flag_warn_protocol = 0;
else if (!strcmp (p, "-fgnu-runtime"))
flag_next_runtime = 0;
else if (!strcmp (p, "-fno-next-runtime"))
flag_next_runtime = 0;
else if (!strcmp (p, "-fno-gnu-runtime"))
flag_next_runtime = 1;
else if (!strcmp (p, "-fnext-runtime"))
flag_next_runtime = 1;
else
return c_decode_option (p);
return 1;
}
static tree
define_decl (declarator, declspecs)
tree declarator;
tree declspecs;
{
tree decl = start_decl (declarator, declspecs, 0, NULL_TREE, 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. */
int
maybe_objc_comptypes (lhs, rhs, reflexive)
tree lhs, rhs;
int reflexive;
{
if (doing_objc_thang)
return objc_comptypes (lhs, rhs, reflexive);
return -1;
}
static tree
lookup_method_in_protocol_list (rproto_list, sel_name, class_meth)
tree rproto_list;
tree sel_name;
int class_meth;
{
tree rproto, p;
tree fnd = 0;
for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
{
p = TREE_VALUE (rproto);
if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
{
if ((fnd = lookup_method (class_meth
? 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);
}
else
; /* An identifier...if we could not find a protocol. */
if (fnd)
return fnd;
}
return 0;
}
static tree
lookup_protocol_in_reflist (rproto_list, lproto)
tree rproto_list;
tree lproto;
{
tree rproto, p;
/* Make sure the protocol is support by the object on the rhs. */
if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE)
{
tree fnd = 0;
for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
{
p = TREE_VALUE (rproto);
if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
{
if (lproto == p)
fnd = lproto;
else if (PROTOCOL_LIST (p))
fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto);
}
if (fnd)
return fnd;
}
}
else
; /* An identifier...if we could not find a protocol. */
return 0;
}
/* 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. */
int
objc_comptypes (lhs, rhs, reflexive)
tree lhs;
tree rhs;
int reflexive;
{
/* New clause for protocols. */
if (TREE_CODE (lhs) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE
&& TREE_CODE (rhs) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
{
int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
if (lhs_is_proto)
{
tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
tree rproto, rproto_list;
tree p;
if (rhs_is_proto)
{
rproto_list = TYPE_PROTOCOL_LIST (rhs);
/* Make sure the protocol is supported by the object
on the rhs. */
for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = lookup_protocol_in_reflist (rproto_list, p);
if (!rproto)
warning ("object does not conform to the `%s' protocol",
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
}
else if (TYPED_OBJECT (TREE_TYPE (rhs)))
{
tree rname = TYPE_NAME (TREE_TYPE (rhs));
tree rinter;
/* Make sure the protocol is supported by the object
on the rhs. */
for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = 0;
rinter = lookup_interface (rname);
while (rinter && !rproto)
{
tree cat;
rproto_list = CLASS_PROTOCOL_LIST (rinter);
rproto = lookup_protocol_in_reflist (rproto_list, p);
/* Check for protocols adopted by categories. */
cat = CLASS_CATEGORY_LIST (rinter);
while (cat && !rproto)
{
rproto_list = CLASS_PROTOCOL_LIST (cat);
rproto = lookup_protocol_in_reflist (rproto_list, p);
cat = CLASS_CATEGORY_LIST (cat);
}
rinter = lookup_interface (CLASS_SUPER_NAME (rinter));
}
if (!rproto)
warning ("class `%s' does not implement the `%s' protocol",
IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
}
/* May change...based on whether there was any mismatch */
return 1;
}
else if (rhs_is_proto)
/* Lhs is not a protocol...warn if it is statically typed */
return (TYPED_OBJECT (TREE_TYPE (lhs)) != 0);
else
/* Defer to comptypes .*/
return -1;
}
else if (TREE_CODE (lhs) == RECORD_TYPE && TREE_CODE (rhs) == RECORD_TYPE)
; /* Fall thru. This is the case we have been handling all along */
else
/* Defer to comptypes. */
return -1;
/* `id' = `<class> *', `<class> *' = `id' */
if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs))
|| (TYPE_NAME (rhs) == objc_object_id && 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))
return 1;
/* `<class> *' = `<class> *' */
else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs))
{
tree lname = TYPE_NAME (lhs);
tree rname = TYPE_NAME (rhs);
tree inter;
if (lname == rname)
return 1;
/* If the left hand side is a super class of the right hand side,
allow it. */
for (inter = lookup_interface (rname); inter;
inter = lookup_interface (CLASS_SUPER_NAME (inter)))
if (lname == CLASS_SUPER_NAME (inter))
return 1;
/* Allow the reverse when reflexive. */
if (reflexive)
for (inter = lookup_interface (lname); inter;
inter = lookup_interface (CLASS_SUPER_NAME (inter)))
if (rname == CLASS_SUPER_NAME (inter))
return 1;
return 0;
}
else
/* Defer to comptypes. */
return -1;
}
/* Called from c-decl.c before all calls to rest_of_decl_compilation. */
void
objc_check_decl (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");
fatal ("statically allocated objects not supported");
}
}
void
maybe_objc_check_decl (decl)
tree decl;
{
if (doing_objc_thang)
objc_check_decl (decl);
}
/* Implement static typing. At this point, we know we have an interface. */
tree
get_static_reference (interface, protocols)
tree interface;
tree protocols;
{
tree type = xref_tag (RECORD_TYPE, interface);
if (protocols)
{
tree t, m = TYPE_MAIN_VARIANT (type);
push_obstacks_nochange ();
end_temporary_allocation ();
t = copy_node (type);
TYPE_BINFO (t) = make_tree_vec (2);
pop_obstacks ();
/* Add this type to the chain of variants of TYPE. */
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
TYPE_NEXT_VARIANT (m) = t;
/* Look up protocols and install in lang specific list. */
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) = 0;
type = t;
}
return type;
}
tree
get_object_reference (protocols)
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)
warning ("Unexpected type for `id' (%s)",
gen_declaration (type, errbuf));
}
else
fatal ("Undefined type `id', please import <objc/objc.h>");
/* This clause creates a new pointer type that is qualified with
the protocol specification...this info is used later to do more
elaborate type checking. */
if (protocols)
{
tree t, m = TYPE_MAIN_VARIANT (type);
push_obstacks_nochange ();
end_temporary_allocation ();
t = copy_node (type);
TYPE_BINFO (t) = make_tree_vec (2);
pop_obstacks ();
/* Add this type to the chain of variants of TYPE. */
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
TYPE_NEXT_VARIANT (m) = t;
/* Look up protocols...and install in lang specific list */
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;
type = t;
}
return type;
}
static tree
lookup_and_install_protocols (protocols)
tree protocols;
{
tree proto;
tree prev = NULL;
tree return_value = protocols;
for (proto = protocols; proto; proto = TREE_CHAIN (proto))
{
tree ident = TREE_VALUE (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);
}
else
{
/* Replace identifier with actual protocol node. */
TREE_VALUE (proto) = p;
prev = proto;
}
}
return return_value;
}
/* Create and push a decl for a built-in external variable or field NAME.
CODE says which.
TYPE is its data type. */
static tree
create_builtin_decl (code, type, name)
enum tree_code code;
tree type;
char *name;
{
tree decl = build_decl (code, get_identifier (name), type);
if (code == VAR_DECL)
{
TREE_STATIC (decl) = 1;
make_decl_rtl (decl, 0, 1);
pushdecl (decl);
}
DECL_ARTIFICIAL (decl) = 1;
return decl;
}
/* Purpose: "play" parser, creating/installing representations
of the declarations that are required by Objective-C.
Model:
type_spec--------->sc_spec
(tree_list) (tree_list)
| |
| |
identifier_node identifier_node */
static void
synth_module_prologue ()
{
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_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)));
/* Declare type of selector-objects that represent an operation name. */
#ifdef OBJC_INT_SELECTORS
/* `unsigned int' */
selector_type = unsigned_type_node;
#else
/* `struct objc_selector *' */
selector_type
= build_pointer_type (xref_tag (RECORD_TYPE,
get_identifier (TAG_SELECTOR)));
#endif /* not OBJC_INT_SELECTORS */
/* Forward declare type, or else the prototype for msgSendSuper will
complain. */
super_p = build_pointer_type (xref_tag (RECORD_TYPE,
get_identifier (TAG_SUPER)));
/* id objc_msgSend (id, SEL, ...); */
temp_type
= build_function_type (id_type,
tree_cons (NULL_TREE, id_type,
tree_cons (NULL_TREE, selector_type,
NULL_TREE)));
if (! flag_next_runtime)
{
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;
if (flag_traditional && TAG_MSGSEND[0] != '_')
DECL_BUILT_IN_NONANSI (umsg_decl) = 1;
make_decl_rtl (umsg_decl, NULL_PTR, 1);
pushdecl (umsg_decl);
}
else
umsg_decl = builtin_function (TAG_MSGSEND, temp_type, NOT_BUILT_IN, 0);
/* 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, NOT_BUILT_IN, 0);
/* 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)));
objc_get_class_decl
= builtin_function (TAG_GETCLASS, temp_type, NOT_BUILT_IN, 0);
/* id objc_getMetaClass (const char *); */
objc_get_meta_class_decl
= builtin_function (TAG_GETMETACLASS, temp_type, NOT_BUILT_IN, 0);
/* static SEL _OBJC_SELECTOR_TABLE[]; */
if (! flag_next_runtime)
{
if (flag_typed_selectors)
{
/* Suppress outputting debug symbols, because
dbxout_init hasn'r been called yet. */
enum debug_info_type save_write_symbols = write_symbols;
write_symbols = NO_DEBUG;
build_selector_template ();
temp_type = build_array_type (objc_selector_template, NULL_TREE);
write_symbols = save_write_symbols;
}
else
temp_type = build_array_type (selector_type, NULL_TREE);
layout_type (temp_type);
UOBJC_SELECTOR_TABLE_decl
= create_builtin_decl (VAR_DECL, temp_type,
"_OBJC_SELECTOR_TABLE");
/* Avoid warning when not sending messages. */
TREE_USED (UOBJC_SELECTOR_TABLE_decl) = 1;
}
generate_forward_declaration_to_string_table ();
/* Forward declare constant_string_id and constant_string_type. */
constant_string_id = get_identifier (STRING_OBJECT_CLASS_NAME);
constant_string_type = xref_tag (RECORD_TYPE, constant_string_id);
}
/* Custom build_string which sets TREE_TYPE! */
static tree
my_build_string (len, str)
int len;
char *str;
{
int wide_flag = 0;
tree a_string = build_string (len, str);
/* Some code from combine_strings, which is local to c-parse.y. */
if (TREE_TYPE (a_string) == int_array_type_node)
wide_flag = 1;
TREE_TYPE (a_string)
= build_array_type (wide_flag ? integer_type_node : char_type_node,
build_index_type (build_int_2 (len - 1, 0)));
TREE_CONSTANT (a_string) = 1; /* Puts string in the readonly segment */
TREE_STATIC (a_string) = 1;
return a_string;
}
/* Return a newly constructed OBJC_STRING_CST node whose value is
the LEN characters at STR.
The TREE_TYPE is not initialized. */
tree
build_objc_string (len, str)
int len;
char *str;
{
tree s = build_string (len, str);
TREE_SET_CODE (s, OBJC_STRING_CST);
return s;
}
/* Given a chain of OBJC_STRING_CST's, build a static instance of
NXConstanString 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 NXConstandString class
object. */
tree
build_objc_string_object (strings)
tree strings;
{
tree string, initlist, constructor;
int length;
if (!doing_objc_thang)
objc_fatal ();
if (lookup_interface (constant_string_id) == NULL_TREE)
{
error ("Cannot find interface declaration for `%s'",
IDENTIFIER_POINTER (constant_string_id));
return error_mark_node;
}
add_class_reference (constant_string_id);
/* Combine_strings will work for OBJC_STRING_CST's too. */
string = combine_strings (strings);
TREE_SET_CODE (string, STRING_CST);
length = TREE_STRING_LENGTH (string) - 1;
if (! flag_next_runtime)
{
push_obstacks_nochange ();
end_temporary_allocation ();
if (! TREE_PERMANENT (strings))
string = my_build_string (length + 1,
TREE_STRING_POINTER (string));
}
/* & ((NXConstantString) {0, string, length}) */
initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
initlist
= tree_cons (NULL_TREE, copy_node (build_unary_op (ADDR_EXPR, string, 1)),
initlist);
initlist = tree_cons (NULL_TREE, build_int_2 (length, 0), initlist);
constructor = build_constructor (constant_string_type, nreverse (initlist));
if (!flag_next_runtime)
{
constructor
= objc_add_static_instance (constructor, constant_string_type);
pop_obstacks ();
}
return (build_unary_op (ADDR_EXPR, constructor, 1));
}
/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */
static tree
objc_add_static_instance (constructor, class_decl)
tree constructor, class_decl;
{
static int num_static_inst;
tree *chain, decl, decl_spec, decl_expr;
char buf[256];
push_obstacks_nochange ();
end_temporary_allocation ();
/* Find the list of static instances for the CLASS_DECL. Create one if
not found. */
for (chain = &objc_static_instances;
*chain && TREE_VALUE (*chain) != class_decl;
chain = &TREE_CHAIN (*chain));
if (!*chain)
{
*chain = tree_cons (NULL_TREE, class_decl, NULL_TREE);
add_objc_string (TYPE_NAME (class_decl), class_names);
}
sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++);
decl = build_decl (VAR_DECL, get_identifier (buf), class_decl);
DECL_COMMON (decl) = 1;
TREE_STATIC (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
pushdecl_top_level (decl);
rest_of_decl_compilation (decl, 0, 1, 0);
/* Do this here so it gets output later instead of possibly
inside something else we are writing. */
DECL_INITIAL (decl) = constructor;
/* Add the DECL to the head of this CLASS' list. */
TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain));
pop_obstacks ();
return decl;
}
/* Build a static constant CONSTRUCTOR
with type TYPE and elements ELTS. */
static tree
build_constructor (type, elts)
tree type, elts;
{
tree constructor = build (CONSTRUCTOR, type, NULL_TREE, elts);
TREE_CONSTANT (constructor) = 1;
TREE_STATIC (constructor) = 1;
TREE_READONLY (constructor) = 1;
return constructor;
}
/* Take care of defining and initializing _OBJC_SYMBOLS. */
/* Predefine the following data type:
struct _objc_symtab
{
long sel_ref_cnt;
SEL *refs;
short cls_def_cnt;
short cat_def_cnt;
void *defs[cls_def_cnt + cat_def_cnt];
}; */
static void
build_objc_symtab_template ()
{
tree field_decl, field_decl_chain, index;
objc_symtab_template
= start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB));
/* long sel_ref_cnt; */
field_decl = create_builtin_decl (FIELD_DECL,
long_integer_type_node,
"sel_ref_cnt");
field_decl_chain = field_decl;
/* SEL *refs; */
field_decl = create_builtin_decl (FIELD_DECL,
build_pointer_type (selector_type),
"refs");
chainon (field_decl_chain, field_decl);
/* short cls_def_cnt; */
field_decl = create_builtin_decl (FIELD_DECL,
short_integer_type_node,
"cls_def_cnt");
chainon (field_decl_chain, field_decl);
/* short cat_def_cnt; */
field_decl = create_builtin_decl (FIELD_DECL,
short_integer_type_node,
"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);
finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE);
}
/* Create the initial value for the `defs' field of _objc_symtab.
This is a CONSTRUCTOR. */
static tree
init_def_list (type)
tree type;
{
tree expr, initlist = NULL_TREE;
struct imp_entry *impent;
if (imp_count)
for (impent = imp_list; impent; impent = impent->next)
{
if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE)
{
expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
}
}
if (cat_count)
for (impent = imp_list; impent; impent = impent->next)
{
if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
{
expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
}
}
if (!flag_next_runtime)
{
/* statics = { ..., _OBJC_STATIC_INSTANCES, ... } */
tree expr;
if (static_instances_decl)
expr = build_unary_op (ADDR_EXPR, static_instances_decl, 0);
else
expr = build_int_2 (0, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
}
return build_constructor (type, nreverse (initlist));
}
/* Construct the initial value for all of _objc_symtab. */
static tree
init_objc_symtab (type)
tree type;
{
tree initlist;
/* sel_ref_cnt = { ..., 5, ... } */
initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
/* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
if (flag_next_runtime || ! sel_ref_chain)
initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
else
initlist = tree_cons (NULL_TREE,
build_unary_op (ADDR_EXPR,
UOBJC_SELECTOR_TABLE_decl, 1),
initlist);
/* cls_def_cnt = { ..., 5, ... } */
initlist = tree_cons (NULL_TREE, build_int_2 (imp_count, 0), initlist);
/* cat_def_cnt = { ..., 5, ... } */
initlist = tree_cons (NULL_TREE, build_int_2 (cat_count, 0), initlist);
/* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
if (imp_count || cat_count || static_instances_decl)
{
tree field = TYPE_FIELDS (type);
field = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (field))));
initlist = tree_cons (NULL_TREE, init_def_list (TREE_TYPE (field)),
initlist);
}
return build_constructor (type, nreverse (initlist));
}
/* Push forward-declarations of all the categories
so that init_def_list can use them in a CONSTRUCTOR. */
static void
forward_declare_categories ()
{
struct imp_entry *impent;
tree sav = implementation_context;
for (impent = imp_list; impent; impent = impent->next)
{
if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
{
/* Set an invisible arg to synth_id_with_class_suffix. */
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", implementation_context)));
}
}
implementation_context = sav;
}
/* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab'
and initialized appropriately. */
static void
generate_objc_symtab_decl ()
{
tree sc_spec;
if (!objc_category_template)
build_category_template ();
/* forward declare categories */
if (cat_count)
forward_declare_categories ();
if (!objc_symtab_template)
build_objc_symtab_template ();
sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]);
UOBJC_SYMBOLS_decl = start_decl (get_identifier ("_OBJC_SYMBOLS"),
tree_cons (NULL_TREE,
objc_symtab_template, sc_spec),
1,
NULL_TREE, NULL_TREE);
TREE_USED (UOBJC_SYMBOLS_decl) = 1;
DECL_IGNORED_P (UOBJC_SYMBOLS_decl) = 1;
DECL_ARTIFICIAL (UOBJC_SYMBOLS_decl) = 1;
finish_decl (UOBJC_SYMBOLS_decl,
init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)),
NULL_TREE);
}
static tree
init_module_descriptor (type)
tree type;
{
tree initlist, expr;
/* version = { 1, ... } */
expr = build_int_2 (OBJC_VERSION, 0);
initlist = build_tree_list (NULL_TREE, expr);
/* size = { ..., sizeof (struct objc_module), ... } */
expr = size_in_bytes (objc_module_template);
initlist = tree_cons (NULL_TREE, expr, initlist);
/* name = { ..., "foo.m", ... } */
expr = add_objc_string (get_identifier (input_filename), class_names);
initlist = tree_cons (NULL_TREE, expr, initlist);
/* symtab = { ..., _OBJC_SYMBOLS, ... } */
if (UOBJC_SYMBOLS_decl)
expr = build_unary_op (ADDR_EXPR, UOBJC_SYMBOLS_decl, 0);
else
expr = build_int_2 (0, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
return build_constructor (type, nreverse (initlist));
}
/* Write out the data structures to describe Objective C classes defined.
If appropriate, compile and output a setup function to initialize them.
Return a string which is the name of a function to call to initialize
the Objective C data structures for this file (and perhaps for other files
also).
struct objc_module { ... } _OBJC_MODULE = { ... }; */
static char *
build_module_descriptor ()
{
tree decl_specs, field_decl, field_decl_chain;
objc_module_template
= start_struct (RECORD_TYPE, get_identifier (UTAG_MODULE));
/* Long version; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
field_decl = get_identifier ("version");
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
/* long size; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
field_decl = get_identifier ("size");
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* char *name; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* struct objc_symtab *symtab; */
decl_specs = get_identifier (UTAG_SYMTAB);
decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs));
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("symtab"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
finish_struct (objc_module_template, field_decl_chain, NULL_TREE);
/* Create an instance of "objc_module". */
decl_specs = tree_cons (NULL_TREE, objc_module_template,
build_tree_list (NULL_TREE,
ridpointers[(int) RID_STATIC]));
UOBJC_MODULES_decl = start_decl (get_identifier ("_OBJC_MODULES"),
decl_specs, 1, NULL_TREE, NULL_TREE);
DECL_ARTIFICIAL (UOBJC_MODULES_decl) = 1;
DECL_IGNORED_P (UOBJC_MODULES_decl) = 1;
finish_decl (UOBJC_MODULES_decl,
init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl)),
NULL_TREE);
/* Mark the decl to avoid "defined but not used" warning. */
DECL_IN_SYSTEM_HEADER (UOBJC_MODULES_decl) = 1;
/* Generate a constructor call for the module descriptor.
This code was generated by reading the grammar rules
of c-parse.in; Therefore, it may not be the most efficient
way of generating the requisite code. */
if (flag_next_runtime)
return 0;
{
tree parms, function_decl, decelerator, void_list_node;
tree function_type;
extern tree get_file_function_name ();
tree init_function_name = get_file_function_name ('I');
/* Declare void __objc_execClass (void *); */
void_list_node = build_tree_list (NULL_TREE, void_type_node);
function_type
= build_function_type (void_type_node,
tree_cons (NULL_TREE, ptr_type_node,
void_list_node));
function_decl = build_decl (FUNCTION_DECL,
get_identifier (TAG_EXECCLASS),
function_type);
DECL_EXTERNAL (function_decl) = 1;
DECL_ARTIFICIAL (function_decl) = 1;
TREE_PUBLIC (function_decl) = 1;
pushdecl (function_decl);
rest_of_decl_compilation (function_decl, 0, 0, 0);
parms
= build_tree_list (NULL_TREE,
build_unary_op (ADDR_EXPR, UOBJC_MODULES_decl, 0));
decelerator = build_function_call (function_decl, parms);
/* void _GLOBAL_$I$<gnyf> () {objc_execClass (&L_OBJC_MODULES);} */
start_function (void_list_node,
build_parse_node (CALL_EXPR, init_function_name,
/* This has the format of the output
of get_parm_info. */
tree_cons (NULL_TREE, NULL_TREE,
void_list_node),
NULL_TREE),
NULL_TREE, NULL_TREE, 0);
#if 0 /* This should be turned back on later
for the systems where collect is not needed. */
/* Make these functions nonglobal
so each file can use the same name. */
TREE_PUBLIC (current_function_decl) = 0;
#endif
TREE_USED (current_function_decl) = 1;
store_parm_decls ();
assemble_external (function_decl);
c_expand_expr_stmt (decelerator);
TREE_PUBLIC (current_function_decl) = 1;
function_decl = current_function_decl;
finish_function (0);
/* Return the name of the constructor function. */
return XSTR (XEXP (DECL_RTL (function_decl), 0), 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;
{
tree chain, decl;
if (section == class_names)
chain = class_names_chain;
else if (section == meth_var_names)
chain = meth_var_names_chain;
else if (section == meth_var_types)
chain = meth_var_types_chain;
for (; chain != 0; chain = TREE_VALUE (chain))
if (TREE_VALUE (chain) == ident)
return (TREE_PURPOSE (chain));
abort ();
return NULL_TREE;
}
/* Output references to all statically allocated objects. Return the DECL
for the array built. */
static tree
generate_static_references ()
{
tree decls = NULL_TREE, ident, decl_spec, expr_decl, expr = NULL_TREE;
tree class_name, class, decl, instance, idecl, initlist;
tree cl_chain, in_chain, type;
int num_inst, num_class;
char buf[256];
if (flag_next_runtime)
abort ();
for (cl_chain = objc_static_instances, num_class = 0;
cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++)
{
for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain);
in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain));
sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class);
ident = get_identifier (buf);
expr_decl = build_nt (ARRAY_REF, ident, 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, NULL_TREE);
DECL_CONTEXT (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
/* Output {class_name, ...}. */
class = TREE_VALUE (cl_chain);
class_name = get_objc_string_decl (TYPE_NAME (class), class_names);
initlist = build_tree_list (NULL_TREE,
build_unary_op (ADDR_EXPR, class_name, 1));
/* Output {..., instance, ...}. */
for (in_chain = TREE_PURPOSE (cl_chain);
in_chain; in_chain = TREE_CHAIN (in_chain))
{
expr = build_unary_op (ADDR_EXPR, TREE_VALUE (in_chain), 1);
initlist = tree_cons (NULL_TREE, expr, initlist);
}
/* Output {..., NULL}. */
initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
expr = 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);
make_decl_rtl (decl, 0, 1);
TREE_USED (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);
ident = get_identifier ("_OBJC_STATIC_INSTANCES");
expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
build_tree_list (NULL_TREE,
ridpointers[(int) RID_STATIC]));
static_instances_decl
= start_decl (expr_decl, decl_spec, 1, NULL_TREE, NULL_TREE);
TREE_USED (static_instances_decl) = 1;
DECL_CONTEXT (static_instances_decl) = 0;
DECL_ARTIFICIAL (static_instances_decl) = 1;
end_temporary_allocation ();
expr = build_constructor (TREE_TYPE (static_instances_decl),
nreverse (decls));
finish_decl (static_instances_decl, expr, NULL_TREE);
}
/* Output all strings. */
static void
generate_strings ()
{
tree sc_spec, decl_specs, expr_decl;
tree chain, string_expr;
tree string, decl;
for (chain = class_names_chain; chain; chain = TREE_CHAIN (chain))
{
string = TREE_VALUE (chain);
decl = TREE_PURPOSE (chain);
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);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
end_temporary_allocation ();
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
IDENTIFIER_POINTER (string));
finish_decl (decl, string_expr, NULL_TREE);
}
for (chain = meth_var_names_chain; chain; chain = TREE_CHAIN (chain))
{
string = TREE_VALUE (chain);
decl = TREE_PURPOSE (chain);
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);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
IDENTIFIER_POINTER (string));
finish_decl (decl, string_expr, NULL_TREE);
}
for (chain = meth_var_types_chain; chain; chain = TREE_CHAIN (chain))
{
string = TREE_VALUE (chain);
decl = TREE_PURPOSE (chain);
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);
decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
IDENTIFIER_POINTER (string));
finish_decl (decl, string_expr, NULL_TREE);
}
}
static tree
build_selector_reference_decl (name)
tree name;
{
tree decl, ident;
char buf[256];
static int idx = 0;
sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", idx++);
push_obstacks_nochange ();
end_temporary_allocation ();
ident = get_identifier (buf);
decl = build_decl (VAR_DECL, ident, selector_type);
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
TREE_USED (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_CONTEXT (decl) = 0;
make_decl_rtl (decl, 0, 1);
pushdecl_top_level (decl);
pop_obstacks ();
return decl;
}
/* Just a handy wrapper for add_objc_string. */
static tree
build_selector (ident)
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! */
}
/* Synthesize the following expr: (char *)&_OBJC_STRINGS[<offset>]
The cast stops the compiler from issuing the following message:
grok.m: warning: initialization of non-const * pointer from const *
grok.m: warning: initialization between incompatible pointer types. */
static tree
build_msg_pool_reference (offset)
int offset;
{
tree expr = build_int_2 (offset, 0);
tree cast;
expr = build_array_ref (UOBJC_STRINGS_decl, expr);
expr = build_unary_op (ADDR_EXPR, expr, 0);
cast = build_tree_list (build_tree_list (NULL_TREE,
ridpointers[(int) RID_CHAR]),
build1 (INDIRECT_REF, NULL_TREE, NULL_TREE));
TREE_TYPE (expr) = groktypename (cast);
return expr;
}
static tree
init_selector (offset)
int offset;
{
tree expr = build_msg_pool_reference (offset);
TREE_TYPE (expr) = selector_type;
return expr;
}
static void
build_selector_translation_table ()
{
tree sc_spec, decl_specs;
tree chain, initlist = NULL_TREE;
int offset = 0;
tree decl, var_decl, name;
/* The corresponding pop_obstacks is in finish_decl,
called at the end of this function. */
if (! flag_next_runtime)
push_obstacks_nochange ();
for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
{
tree expr;
expr = build_selector (TREE_VALUE (chain));
if (flag_next_runtime)
{
name = DECL_NAME (TREE_PURPOSE (chain));
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);
var_decl = name;
/* The `decl' that is returned from start_decl is the one that we
forward declared in `build_selector_reference' */
decl = start_decl (var_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
}
/* add one for the '\0' character */
offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
if (flag_next_runtime)
finish_decl (decl, expr, NULL_TREE);
else
{
if (flag_typed_selectors)
{
tree eltlist = NULL_TREE;
tree encoding = get_proto_encoding (TREE_PURPOSE (chain));
eltlist = tree_cons (NULL_TREE, expr, NULL_TREE);
eltlist = tree_cons (NULL_TREE, encoding, eltlist);
expr = build_constructor (objc_selector_template,
nreverse (eltlist));
}
initlist = tree_cons (NULL_TREE, expr, initlist);
}
}
if (! flag_next_runtime)
{
/* Cause the variable and its initial value to be actually output. */
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);
DECL_INITIAL (UOBJC_SELECTOR_TABLE_decl) = (tree) 1;
initlist = build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl),
nreverse (initlist));
finish_decl (UOBJC_SELECTOR_TABLE_decl, initlist, NULL_TREE);
current_function_decl = NULL_TREE;
}
}
static tree
get_proto_encoding (proto)
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;
}
else
encoding = METHOD_ENCODING (proto);
return add_objc_string (encoding, meth_var_types);
}
else
return build_int_2 (0, 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, proto)
tree ident, proto;
{
tree *chain = &sel_ref_chain;
tree expr;
int index = 0;
while (*chain)
{
if (TREE_PURPOSE (*chain) == ident && TREE_VALUE (*chain) == proto)
goto return_at_index;
index++;
chain = &TREE_CHAIN (*chain);
}
*chain = perm_tree_cons (proto, ident, NULL_TREE);
return_at_index:
expr = build_unary_op (ADDR_EXPR,
build_array_ref (UOBJC_SELECTOR_TABLE_decl,
build_int_2 (index, 0)),
1);
return build_c_cast (selector_type, expr);
}
static tree
build_selector_reference (ident)
tree ident;
{
tree *chain = &sel_ref_chain;
tree expr;
int index = 0;
while (*chain)
{
if (TREE_VALUE (*chain) == ident)
return (flag_next_runtime
? TREE_PURPOSE (*chain)
: build_array_ref (UOBJC_SELECTOR_TABLE_decl,
build_int_2 (index, 0)));
index++;
chain = &TREE_CHAIN (*chain);
}
expr = build_selector_reference_decl (ident);
*chain = perm_tree_cons (expr, ident, NULL_TREE);
return (flag_next_runtime
? expr
: build_array_ref (UOBJC_SELECTOR_TABLE_decl,
build_int_2 (index, 0)));
}
static tree
build_class_reference_decl (name)
tree name;
{
tree decl, ident;
char buf[256];
static int idx = 0;
sprintf (buf, "_OBJC_CLASS_REFERENCES_%d", idx++);
push_obstacks_nochange ();
end_temporary_allocation ();
ident = get_identifier (buf);
decl = build_decl (VAR_DECL, ident, objc_class_type);
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
TREE_USED (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_CONTEXT (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
make_decl_rtl (decl, 0, 1);
pushdecl_top_level (decl);
pop_obstacks ();
return decl;
}
/* Create a class reference, but don't create a variable to reference
it. */
static void
add_class_reference (ident)
tree ident;
{
tree chain;
if ((chain = cls_ref_chain))
{
tree tail;
do
{
if (ident == TREE_VALUE (chain))
return;
tail = chain;
chain = TREE_CHAIN (chain);
}
while (chain);
/* Append to the end of the list */
TREE_CHAIN (tail) = perm_tree_cons (NULL_TREE, ident, NULL_TREE);
}
else
cls_ref_chain = perm_tree_cons (NULL_TREE, ident, NULL_TREE);
}
/* Get a class reference, creating it if necessary. Also create the
reference variable. */
tree
get_class_reference (ident)
tree ident;
{
if (flag_next_runtime)
{
tree *chain;
tree decl;
for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain))
if (TREE_VALUE (*chain) == ident)
{
if (! TREE_PURPOSE (*chain))
TREE_PURPOSE (*chain) = build_class_reference_decl (ident);
return TREE_PURPOSE (*chain);
}
decl = build_class_reference_decl (ident);
*chain = perm_tree_cons (decl, ident, NULL_TREE);
return decl;
}
else
{
tree params;
add_class_reference (ident);
params = build_tree_list (NULL_TREE,
my_build_string (IDENTIFIER_LENGTH (ident) + 1,
IDENTIFIER_POINTER (ident)));
assemble_external (objc_get_class_decl);
return build_function_call (objc_get_class_decl, params);
}
}
/* SEL_REFDEF_CHAIN is a list whose "value" fields will be instances
of identifier_node that represent the selector. It returns the
offset of the selector from the beginning of the _OBJC_STRINGS
pool. This offset is typically used by init_selector during code
generation.
For each string section we have a chain which maps identifier nodes
to decls for the strings. */
static tree
add_objc_string (ident, section)
tree ident;
enum string_section section;
{
tree *chain, decl;
if (section == class_names)
chain = &class_names_chain;
else if (section == meth_var_names)
chain = &meth_var_names_chain;
else if (section == meth_var_types)
chain = &meth_var_types_chain;
while (*chain)
{
if (TREE_VALUE (*chain) == ident)
return build_unary_op (ADDR_EXPR, TREE_PURPOSE (*chain), 1);
chain = &TREE_CHAIN (*chain);
}
decl = build_objc_string_decl (ident, section);
*chain = perm_tree_cons (decl, ident, NULL_TREE);
return build_unary_op (ADDR_EXPR, decl, 1);
}
static tree
build_objc_string_decl (name, section)
tree name;
enum string_section section;
{
tree decl, ident;
char buf[256];
static int class_names_idx = 0;
static int meth_var_names_idx = 0;
static int meth_var_types_idx = 0;
if (section == class_names)
sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
else if (section == meth_var_names)
sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
else if (section == meth_var_types)
sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
push_obstacks_nochange ();
end_temporary_allocation ();
ident = get_identifier (buf);
decl = build_decl (VAR_DECL, ident, build_array_type (char_type_node, 0));
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
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, 1);
pushdecl_top_level (decl);
pop_obstacks ();
return decl;
}
void
objc_declare_alias (alias_ident, class_ident)
tree alias_ident;
tree class_ident;
{
if (!doing_objc_thang)
objc_fatal ();
if (is_class_name (class_ident) != class_ident)
warning ("Cannot find class `%s'", IDENTIFIER_POINTER (class_ident));
else if (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);
}
void
objc_declare_class (ident_list)
tree ident_list;
{
tree list;
if (!doing_objc_thang)
objc_fatal ();
for (list = ident_list; list; list = TREE_CHAIN (list))
{
tree ident = TREE_VALUE (list);
tree decl;
if ((decl = lookup_name (ident)))
{
error ("`%s' redeclared as different kind of symbol",
IDENTIFIER_POINTER (ident));
error_with_decl (decl, "previous declaration of `%s'");
}
if (! is_class_name (ident))
{
tree 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;
{
tree chain;
if (lookup_interface (ident))
return ident;
for (chain = class_chain; chain; chain = TREE_CHAIN (chain))
{
if (ident == TREE_VALUE (chain))
return ident;
}
for (chain = alias_chain; chain; chain = TREE_CHAIN (chain))
{
if (ident == TREE_VALUE (chain))
return TREE_PURPOSE (chain);
}
return 0;
}
tree
lookup_interface (ident)
tree ident;
{
tree chain;
for (chain = interface_chain; chain; chain = TREE_CHAIN (chain))
{
if (ident == CLASS_NAME (chain))
return chain;
}
return NULL_TREE;
}
static tree
objc_copy_list (list, head)
tree list;
tree *head;
{
tree newlist = NULL_TREE, tail = NULL_TREE;
while (list)
{
tail = copy_node (list);
/* The following statement fixes a bug when inheriting instance
variables that are declared to be bitfields. finish_struct
expects to find the width of the bitfield in DECL_INITIAL,
which it nulls out after processing the decl of the super
class...rather than change the way finish_struct works (which
is risky), I create the situation it expects...s.naroff
(7/23/89). */
if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0)
DECL_INITIAL (tail) = build_int_2 (DECL_FIELD_SIZE (tail), 0);
newlist = chainon (newlist, tail);
list = TREE_CHAIN (list);
}
*head = newlist;
return tail;
}
/* Used by: build_private_template, get_class_ivars, and
continue_class. COPY is 1 when called from @defs. In this case
copy all fields. Otherwise don't copy leaf ivars since we rely on
them being side-effected exactly once by finish_struct. */
static tree
build_ivar_chain (interface, copy)
tree interface;
int copy;
{
tree my_name, super_name, ivar_chain;
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);
/* Possibly copy leaf ivars. */
if (copy)
objc_copy_list (CLASS_IVARS (interface), &ivar_chain);
else
ivar_chain = CLASS_IVARS (interface);
while (super_name)
{
tree op1;
tree super_interface = lookup_interface (super_name);
if (!super_interface)
{
/* fatal did not work with 2 args...should fix */
error ("Cannot find interface declaration for `%s', superclass of `%s'",
IDENTIFIER_POINTER (super_name),
IDENTIFIER_POINTER (my_name));
exit (FATAL_EXIT_CODE);
}
if (super_interface == interface)
{
fatal ("Circular inheritance in interface declaration for `%s'",
IDENTIFIER_POINTER (super_name));
}
interface = super_interface;
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);
op1 = CLASS_IVARS (interface);
if (op1)
{
tree head, tail = objc_copy_list (op1, &head);
/* Prepend super class ivars...make a copy of the list, we
do not want to alter the original. */
TREE_CHAIN (tail) = ivar_chain;
ivar_chain = head;
}
}
return ivar_chain;
}
/* struct <classname> {
struct objc_class *isa;
...
}; */
static tree
build_private_template (class)
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 = build_ivar_chain (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;
}
instance_type
= groktypename (build_tree_list (build_tree_list (NULL_TREE,
uprivate_record),
build1 (INDIRECT_REF, NULL_TREE,
NULL_TREE)));
return ivar_context;
}
/* 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 ()
{
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 (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
/* char *protocol_name; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_name"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* struct objc_protocol **protocol_list; */
decl_specs = build_tree_list (NULL_TREE, template);
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list"));
field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl);
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* struct objc_method_list *instance_methods; */
decl_specs
= build_tree_list (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* struct objc_method_list *class_methods; */
decl_specs
= build_tree_list (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
return finish_struct (template, field_decl_chain, NULL_TREE);
}
static tree
build_descriptor_table_initializer (type, entries)
tree type;
tree entries;
{
tree initlist = NULL_TREE;
do
{
tree eltlist = NULL_TREE;
eltlist
= tree_cons (NULL_TREE,
build_selector (METHOD_SEL_NAME (entries)), NULL_TREE);
eltlist
= tree_cons (NULL_TREE,
add_objc_string (METHOD_ENCODING (entries),
meth_var_types),
eltlist);
initlist
= tree_cons (NULL_TREE,
build_constructor (type, nreverse (eltlist)), initlist);
entries = TREE_CHAIN (entries);
}
while (entries);
return build_constructor (build_array_type (type, 0), nreverse (initlist));
}
/* struct objc_method_prototype_list {
int count;
struct objc_method_prototype {
SEL name;
char *types;
} list[1];
}; */
static tree
build_method_prototype_list_template (list_type, size)
tree list_type;
int size;
{
tree objc_ivar_list_record;
tree decl_specs, field_decl, field_decl_chain;
/* Generate an unnamed struct definition. */
objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
/* int method_count; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]);
field_decl = get_identifier ("method_count");
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
/* struct objc_method method_list[]; */
decl_specs = build_tree_list (NULL_TREE, list_type);
field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
build_int_2 (size, 0));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE);
return objc_ivar_list_record;
}
static tree
build_method_prototype_template ()
{
tree proto_record;
tree decl_specs, field_decl, field_decl_chain;
proto_record
= start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE));
#ifdef OBJC_INT_SELECTORS
/* unsigned int _cmd; */
decl_specs
= tree_cons (NULL_TREE, ridpointers[(int) RID_UNSIGNED], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_INT], decl_specs);
field_decl = get_identifier ("_cmd");
#else /* OBJC_INT_SELECTORS */
/* struct objc_selector *_cmd; */
decl_specs = tree_cons (NULL_TREE, xref_tag (RECORD_TYPE,
get_identifier (TAG_SELECTOR)), NULL_TREE);
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_cmd"));
#endif /* OBJC_INT_SELECTORS */
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], NULL_TREE);
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_types"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
finish_struct (proto_record, field_decl_chain, NULL_TREE);
return proto_record;
}
/* True if last call to forwarding_offset yielded a register offset. */
static int offset_is_register;
static int
forwarding_offset (parm)
tree parm;
{
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))));
return offset_in_bytes;
}
static tree
encode_method_prototype (method_decl, func_decl)
tree method_decl;
tree func_decl;
{
tree parms;
int stack_size, i;
tree user_args;
int max_parm_end = 0;
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)),
obstack_object_size (&util_obstack),
OBJC_ENCODE_INLINE_DEFS);
/* Stack size. */
for (parms = DECL_ARGUMENTS (func_decl); parms;
parms = TREE_CHAIN (parms))
{
int parm_end = (forwarding_offset (parms)
+ (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (parms)))
/ BITS_PER_UNIT));
if (!offset_is_register && max_parm_end < parm_end)
max_parm_end = parm_end;
}
stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET;
sprintf (buf, "%d", stack_size);
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++)
{
/* 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);
}
/* Type. */
encode_type (TREE_TYPE (parms),
obstack_object_size (&util_obstack),
OBJC_ENCODE_INLINE_DEFS);
/* Compute offset. */
sprintf (buf, "%d", forwarding_offset (parms));
/* Indicate register. */
if (offset_is_register)
obstack_1grow (&util_obstack, '+');
obstack_grow (&util_obstack, buf, strlen (buf));
}
obstack_1grow (&util_obstack, '\0');
result = get_identifier (obstack_finish (&util_obstack));
obstack_free (&util_obstack, util_firstobj);
return result;
}
static tree
generate_descriptor_table (type, name, size, list, proto)
tree type;
char *name;
int size;
tree list;
tree proto;
{
tree sc_spec, decl_specs, decl, initlist;
sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
decl_specs = tree_cons (NULL_TREE, type, sc_spec);
decl = start_decl (synth_id_with_class_suffix (name, proto),
decl_specs, 1, NULL_TREE, NULL_TREE);
initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0));
initlist = tree_cons (NULL_TREE, list, initlist);
finish_decl (decl, build_constructor (type, nreverse (initlist)),
NULL_TREE);
return decl;
}
static void
generate_method_descriptors (protocol) /* generate_dispatch_tables */
tree protocol;
{
static tree objc_method_prototype_template;
tree initlist, chain, method_list_template;
tree cast, variable_length_type;
int size;
if (!objc_method_prototype_template)
objc_method_prototype_template = build_method_prototype_template ();
cast = build_tree_list (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
get_identifier (UTAG_METHOD_PROTOTYPE_LIST))),
NULL_TREE);
variable_length_type = groktypename (cast);
chain = PROTOCOL_CLS_METHODS (protocol);
if (chain)
{
size = list_length (chain);
method_list_template
= build_method_prototype_list_template (objc_method_prototype_template,
size);
initlist
= build_descriptor_table_initializer (objc_method_prototype_template,
chain);
UOBJC_CLASS_METHODS_decl
= generate_descriptor_table (method_list_template,
"_OBJC_PROTOCOL_CLASS_METHODS",
size, initlist, protocol);
TREE_TYPE (UOBJC_CLASS_METHODS_decl) = variable_length_type;
}
else
UOBJC_CLASS_METHODS_decl = 0;
chain = PROTOCOL_NST_METHODS (protocol);
if (chain)
{
size = list_length (chain);
method_list_template
= build_method_prototype_list_template (objc_method_prototype_template,
size);
initlist
= build_descriptor_table_initializer (objc_method_prototype_template,
chain);
UOBJC_INSTANCE_METHODS_decl
= generate_descriptor_table (method_list_template,
"_OBJC_PROTOCOL_INSTANCE_METHODS",
size, initlist, protocol);
TREE_TYPE (UOBJC_INSTANCE_METHODS_decl) = variable_length_type;
}
else
UOBJC_INSTANCE_METHODS_decl = 0;
}
static tree
build_tmp_function_decl ()
{
tree decl_specs, expr_decl, parms;
static int xxx = 0;
char buffer[80];
/* 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)),
build_tree_list (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),
build_tree_list (NULL_TREE, 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", xxx++);
expr_decl = build_nt (CALL_EXPR, get_identifier (buffer), parms, NULL_TREE);
expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl);
return define_decl (expr_decl, decl_specs);
}
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) == (tree) 1)
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);
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, "objc-act", 0);
/* Typically called from expand_function_start for function definitions. */
assign_parms (tmp_decl, 0);
/* install return type */
TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods));
}
static void
generate_protocol_references (plist)
tree plist;
{
tree lproto;
/* Forward declare protocols referenced. */
for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
{
tree proto = TREE_VALUE (lproto);
if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE
&& PROTOCOL_NAME (proto))
{
if (! PROTOCOL_FORWARD_DECL (proto))
build_protocol_reference (proto);
if (PROTOCOL_LIST (proto))
generate_protocol_references (PROTOCOL_LIST (proto));
}
}
}
static void
generate_protocols ()
{
tree p, tmp_decl, encoding;
tree sc_spec, decl_specs, decl;
tree initlist, protocol_name_expr, refs_decl, refs_expr;
tree cast_type2 = 0;
tmp_decl = build_tmp_function_decl ();
if (! objc_protocol_template)
objc_protocol_template = build_protocol_template ();
/* If a protocol was directly referenced, pull in indirect references. */
for (p = protocol_chain; p; p = TREE_CHAIN (p))
if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p))
generate_protocol_references (PROTOCOL_LIST (p));
for (p = protocol_chain; p; p = TREE_CHAIN (p))
{
tree nst_methods = PROTOCOL_NST_METHODS (p);
tree cls_methods = PROTOCOL_CLS_METHODS (p);
/* If protocol wasn't referenced, don't generate any code. */
if (! PROTOCOL_FORWARD_DECL (p))
continue;
/* Make sure we link in the Protocol class. */
add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
while (nst_methods)
{
if (! METHOD_ENCODING (nst_methods))
{
hack_method_prototype (nst_methods, tmp_decl);
encoding = encode_method_prototype (nst_methods, tmp_decl);
METHOD_ENCODING (nst_methods) = encoding;
}
nst_methods = TREE_CHAIN (nst_methods);
}
while (cls_methods)
{
if (! METHOD_ENCODING (cls_methods))
{
hack_method_prototype (cls_methods, tmp_decl);
encoding = encode_method_prototype (cls_methods, tmp_decl);
METHOD_ENCODING (cls_methods) = encoding;
}
cls_methods = TREE_CHAIN (cls_methods);
}
generate_method_descriptors (p);
if (PROTOCOL_LIST (p))
refs_decl = generate_protocol_list (p);
else
refs_decl = 0;
/* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */
sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC],
NULL_TREE);
decl_specs = tree_cons (NULL_TREE, objc_protocol_template, sc_spec);
decl = start_decl (synth_id_with_class_suffix ("_OBJC_PROTOCOL", p),
decl_specs, 1, NULL_TREE, NULL_TREE);
protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names);
if (refs_decl)
{
if (!cast_type2)
cast_type2
= groktypename
(build_tree_list (build_tree_list (NULL_TREE,
objc_protocol_template),
build1 (INDIRECT_REF, NULL_TREE,
build1 (INDIRECT_REF, NULL_TREE,
NULL_TREE))));
refs_expr = build_unary_op (ADDR_EXPR, refs_decl, 0);
TREE_TYPE (refs_expr) = cast_type2;
}
else
refs_expr = build_int_2 (0, 0);
/* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set
by generate_method_descriptors, which is called above. */
initlist = build_protocol_initializer (TREE_TYPE (decl),
protocol_name_expr, refs_expr,
UOBJC_INSTANCE_METHODS_decl,
UOBJC_CLASS_METHODS_decl);
finish_decl (decl, initlist, NULL_TREE);
/* Mark the decl as used to avoid "defined but not used" warning. */
TREE_USED (decl) = 1;
}
}
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;
{
tree initlist = NULL_TREE, expr;
static tree cast_type = 0;
if (!cast_type)
cast_type
= groktypename
(build_tree_list
(build_tree_list (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_CLASS))),
build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)));
/* 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;
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);
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);
else
{
expr = build_unary_op (ADDR_EXPR, class_methods, 0);
initlist = tree_cons (NULL_TREE, expr, initlist);
}
return build_constructor (type, nreverse (initlist));
}
/* struct objc_category {
char *category_name;
char *class_name;
struct objc_method_list *instance_methods;
struct objc_method_list *class_methods;
struct objc_protocol_list *protocols;
}; */
static void
build_category_template ()
{
tree decl_specs, field_decl, field_decl_chain;
objc_category_template = start_struct (RECORD_TYPE,
get_identifier (UTAG_CATEGORY));
/* char *category_name; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("category_name"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
/* char *class_name; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_name"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* struct objc_method_list *instance_methods; */
decl_specs = build_tree_list (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_METHOD_LIST)));
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* struct objc_method_list *class_methods; */
decl_specs = build_tree_list (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_METHOD_LIST)));
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* struct objc_protocol **protocol_list; */
decl_specs = build_tree_list (NULL_TREE,
xref_tag (RECORD_TYPE,
get_identifier (UTAG_PROTOCOL)));
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list"));
field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl);
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
finish_struct (objc_category_template, field_decl_chain, NULL_TREE);
}
/* struct objc_selector {
void *sel_id;
char *sel_type;
}; */
static void
build_selector_template ()
{
tree decl_specs, field_decl, field_decl_chain;
objc_selector_template
= start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR));
/* 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 (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
/* char *sel_type; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_type"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
finish_struct (objc_selector_template, field_decl_chain, NULL_TREE);
}
/* struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list *methods;
if (flag_next_runtime)
struct objc_cache *cache;
else {
struct sarray *dtable;
struct objc_class *subclass_list;
struct objc_class *sibling_class;
}
struct objc_protocol_list *protocols;
}; */
static void
build_class_template ()
{
tree decl_specs, field_decl, field_decl_chain;
objc_class_template
= start_struct (RECORD_TYPE, get_identifier (UTAG_CLASS));
/* struct objc_class *isa; */
decl_specs = build_tree_list (NULL_TREE, objc_class_template);
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
field_decl_chain = field_decl;
/* struct objc_class *super_class; */
decl_specs = build_tree_list (NULL_TREE, objc_class_template);
field_decl
= build1 (INDIRECT_REF, NULL_TREE, get_identifier ("super_class"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* char *name; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name"));
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);
/* long version; */
decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
field_decl = get_identifier ("version");
field_decl
= grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
chainon (field_decl_chain, field_decl);