OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [objc/] [objc-act.c] - Diff between revs 816 and 826

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 826
/* Implement classes and message passing for Objective C.
/* Implement classes and message passing for Objective C.
   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
   2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
   2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
   Contributed by Steve Naroff.
   Contributed by Steve Naroff.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
the Free Software Foundation; either version 3, or (at your option)
any later version.
any later version.
 
 
GCC is distributed in the hope that it will be useful,
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
 
 
/* Purpose: This module implements the Objective-C 4.0 language.
/* Purpose: This module implements the Objective-C 4.0 language.
 
 
   compatibility issues (with the Stepstone translator):
   compatibility issues (with the Stepstone translator):
 
 
   - does not recognize the following 3.3 constructs.
   - does not recognize the following 3.3 constructs.
     @requires, @classes, @messages, = (...)
     @requires, @classes, @messages, = (...)
   - methods with variable arguments must conform to ANSI standard.
   - methods with variable arguments must conform to ANSI standard.
   - tagged structure definitions that appear in BOTH the interface
   - tagged structure definitions that appear in BOTH the interface
     and implementation are not allowed.
     and implementation are not allowed.
   - public/private: all instance variables are public within the
   - public/private: all instance variables are public within the
     context of the implementation...I consider this to be a bug in
     context of the implementation...I consider this to be a bug in
     the translator.
     the translator.
   - statically allocated objects are not supported. the user will
   - statically allocated objects are not supported. the user will
     receive an error if this service is requested.
     receive an error if this service is requested.
 
 
   code generation `options':
   code generation `options':
 
 
   */
   */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "tree.h"
#include "tree.h"
#include "rtl.h"
#include "rtl.h"
#include "tm_p.h"
#include "tm_p.h"
#include "expr.h"
#include "expr.h"
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
#include "cp-tree.h"
#include "cp-tree.h"
#else
#else
#include "c-tree.h"
#include "c-tree.h"
#include "c-lang.h"
#include "c-lang.h"
#endif
#endif
 
 
#include "c-common.h"
#include "c-common.h"
#include "c-pragma.h"
#include "c-pragma.h"
#include "flags.h"
#include "flags.h"
#include "langhooks.h"
#include "langhooks.h"
#include "objc-act.h"
#include "objc-act.h"
#include "input.h"
#include "input.h"
#include "except.h"
#include "except.h"
#include "function.h"
#include "function.h"
#include "output.h"
#include "output.h"
#include "toplev.h"
#include "toplev.h"
#include "ggc.h"
#include "ggc.h"
#include "varray.h"
#include "varray.h"
#include "debug.h"
#include "debug.h"
#include "target.h"
#include "target.h"
#include "diagnostic.h"
#include "diagnostic.h"
#include "intl.h"
#include "intl.h"
#include "cgraph.h"
#include "cgraph.h"
#include "tree-iterator.h"
#include "tree-iterator.h"
#include "libfuncs.h"
#include "libfuncs.h"
#include "hashtab.h"
#include "hashtab.h"
#include "langhooks-def.h"
#include "langhooks-def.h"
 
 
#define OBJC_VOID_AT_END        void_list_node
#define OBJC_VOID_AT_END        void_list_node
 
 
static unsigned int should_call_super_dealloc = 0;
static unsigned int should_call_super_dealloc = 0;
 
 
/* When building Objective-C++, we need in_late_binary_op.  */
/* When building Objective-C++, we need in_late_binary_op.  */
#ifdef OBJCPLUS
#ifdef OBJCPLUS
bool in_late_binary_op = false;
bool in_late_binary_op = false;
#endif  /* OBJCPLUS */
#endif  /* OBJCPLUS */
 
 
/* When building Objective-C++, we are not linking against the C front-end
/* When building Objective-C++, we are not linking against the C front-end
   and so need to replicate the C tree-construction functions in some way.  */
   and so need to replicate the C tree-construction functions in some way.  */
#ifdef OBJCPLUS
#ifdef OBJCPLUS
#define OBJCP_REMAP_FUNCTIONS
#define OBJCP_REMAP_FUNCTIONS
#include "objcp-decl.h"
#include "objcp-decl.h"
#endif  /* OBJCPLUS */
#endif  /* OBJCPLUS */
 
 
/* This is the default way of generating a method name.  */
/* This is the default way of generating a method name.  */
/* I am not sure it is really correct.
/* I am not sure it is really correct.
   Perhaps there's a danger that it will make name conflicts
   Perhaps there's a danger that it will make name conflicts
   if method names contain underscores. -- rms.  */
   if method names contain underscores. -- rms.  */
#ifndef OBJC_GEN_METHOD_LABEL
#ifndef OBJC_GEN_METHOD_LABEL
#define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \
#define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \
  do {                                      \
  do {                                      \
    char *temp;                             \
    char *temp;                             \
    sprintf ((BUF), "_%s_%s_%s_%s",         \
    sprintf ((BUF), "_%s_%s_%s_%s",         \
             ((IS_INST) ? "i" : "c"),       \
             ((IS_INST) ? "i" : "c"),       \
             (CLASS_NAME),                  \
             (CLASS_NAME),                  \
             ((CAT_NAME)? (CAT_NAME) : ""), \
             ((CAT_NAME)? (CAT_NAME) : ""), \
             (SEL_NAME));                   \
             (SEL_NAME));                   \
    for (temp = (BUF); *temp; temp++)       \
    for (temp = (BUF); *temp; temp++)       \
      if (*temp == ':') *temp = '_';        \
      if (*temp == ':') *temp = '_';        \
  } while (0)
  } while (0)
#endif
#endif
 
 
/* These need specifying.  */
/* These need specifying.  */
#ifndef OBJC_FORWARDING_STACK_OFFSET
#ifndef OBJC_FORWARDING_STACK_OFFSET
#define OBJC_FORWARDING_STACK_OFFSET 0
#define OBJC_FORWARDING_STACK_OFFSET 0
#endif
#endif
 
 
#ifndef OBJC_FORWARDING_MIN_OFFSET
#ifndef OBJC_FORWARDING_MIN_OFFSET
#define OBJC_FORWARDING_MIN_OFFSET 0
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
#endif


/* Set up for use of obstacks.  */
/* Set up for use of obstacks.  */
 
 
#include "obstack.h"
#include "obstack.h"
 
 
/* This obstack is used to accumulate the encoding of a data type.  */
/* This obstack is used to accumulate the encoding of a data type.  */
static struct obstack util_obstack;
static struct obstack util_obstack;
 
 
/* This points to the beginning of obstack contents, so we can free
/* This points to the beginning of obstack contents, so we can free
   the whole contents.  */
   the whole contents.  */
char *util_firstobj;
char *util_firstobj;
 
 
/* The version identifies which language generation and runtime
/* The version identifies which language generation and runtime
   the module (file) was compiled for, and is recorded in the
   the module (file) was compiled for, and is recorded in the
   module descriptor.  */
   module descriptor.  */
 
 
#define OBJC_VERSION    (flag_next_runtime ? 6 : 8)
#define OBJC_VERSION    (flag_next_runtime ? 6 : 8)
#define PROTOCOL_VERSION 2
#define PROTOCOL_VERSION 2
 
 
/* (Decide if these can ever be validly changed.) */
/* (Decide if these can ever be validly changed.) */
#define OBJC_ENCODE_INLINE_DEFS         0
#define OBJC_ENCODE_INLINE_DEFS         0
#define OBJC_ENCODE_DONT_INLINE_DEFS    1
#define OBJC_ENCODE_DONT_INLINE_DEFS    1
 
 
/*** Private Interface (procedures) ***/
/*** Private Interface (procedures) ***/
 
 
/* Used by compile_file.  */
/* Used by compile_file.  */
 
 
static void init_objc (void);
static void init_objc (void);
static void finish_objc (void);
static void finish_objc (void);
 
 
/* Code generation.  */
/* Code generation.  */
 
 
static tree objc_build_constructor (tree, tree);
static tree objc_build_constructor (tree, tree);
static tree build_objc_method_call (location_t, int, tree, tree, tree, tree);
static tree build_objc_method_call (location_t, int, tree, tree, tree, tree);
static tree get_proto_encoding (tree);
static tree get_proto_encoding (tree);
static tree lookup_interface (tree);
static tree lookup_interface (tree);
static tree objc_add_static_instance (tree, tree);
static tree objc_add_static_instance (tree, tree);
 
 
static tree start_class (enum tree_code, tree, tree, tree);
static tree start_class (enum tree_code, tree, tree, tree);
static tree continue_class (tree);
static tree continue_class (tree);
static void finish_class (tree);
static void finish_class (tree);
static void start_method_def (tree);
static void start_method_def (tree);
#ifdef OBJCPLUS
#ifdef OBJCPLUS
static void objc_start_function (tree, tree, tree, tree);
static void objc_start_function (tree, tree, tree, tree);
#else
#else
static void objc_start_function (tree, tree, tree, struct c_arg_info *);
static void objc_start_function (tree, tree, tree, struct c_arg_info *);
#endif
#endif
static tree start_protocol (enum tree_code, tree, tree);
static tree start_protocol (enum tree_code, tree, tree);
static tree build_method_decl (enum tree_code, tree, tree, tree, bool);
static tree build_method_decl (enum tree_code, tree, tree, tree, bool);
static tree objc_add_method (tree, tree, int);
static tree objc_add_method (tree, tree, int);
static tree add_instance_variable (tree, int, tree);
static tree add_instance_variable (tree, int, tree);
static tree build_ivar_reference (tree);
static tree build_ivar_reference (tree);
static tree is_ivar (tree, tree);
static tree is_ivar (tree, tree);
 
 
static void build_objc_exception_stuff (void);
static void build_objc_exception_stuff (void);
static void build_next_objc_exception_stuff (void);
static void build_next_objc_exception_stuff (void);
 
 
/* We only need the following for ObjC; ObjC++ will use C++'s definition
/* We only need the following for ObjC; ObjC++ will use C++'s definition
   of DERIVED_FROM_P.  */
   of DERIVED_FROM_P.  */
#ifndef OBJCPLUS
#ifndef OBJCPLUS
static bool objc_derived_from_p (tree, tree);
static bool objc_derived_from_p (tree, tree);
#define DERIVED_FROM_P(PARENT, CHILD) objc_derived_from_p (PARENT, CHILD)
#define DERIVED_FROM_P(PARENT, CHILD) objc_derived_from_p (PARENT, CHILD)
#endif
#endif
static void objc_xref_basetypes (tree, tree);
static void objc_xref_basetypes (tree, tree);
 
 
static void build_class_template (void);
static void build_class_template (void);
static void build_selector_template (void);
static void build_selector_template (void);
static void build_category_template (void);
static void build_category_template (void);
static void build_super_template (void);
static void build_super_template (void);
static tree build_protocol_initializer (tree, tree, tree, tree, tree);
static tree build_protocol_initializer (tree, tree, tree, tree, tree);
static tree get_class_ivars (tree, bool);
static tree get_class_ivars (tree, bool);
static tree generate_protocol_list (tree);
static tree generate_protocol_list (tree);
static void build_protocol_reference (tree);
static void build_protocol_reference (tree);
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
static void objc_generate_cxx_cdtors (void);
static void objc_generate_cxx_cdtors (void);
#endif
#endif
 
 
static const char *synth_id_with_class_suffix (const char *, tree);
static const char *synth_id_with_class_suffix (const char *, tree);
 
 
/* Hash tables to manage the global pool of method prototypes.  */
/* Hash tables to manage the global pool of method prototypes.  */
 
 
hash *nst_method_hash_list = 0;
hash *nst_method_hash_list = 0;
hash *cls_method_hash_list = 0;
hash *cls_method_hash_list = 0;
 
 
static hash hash_lookup (hash *, tree);
static hash hash_lookup (hash *, tree);
static tree lookup_method (tree, tree);
static tree lookup_method (tree, tree);
static tree lookup_method_static (tree, tree, int);
static tree lookup_method_static (tree, tree, int);
 
 
enum string_section
enum string_section
{
{
  class_names,          /* class, category, protocol, module names */
  class_names,          /* class, category, protocol, module names */
  meth_var_names,       /* method and variable names */
  meth_var_names,       /* method and variable names */
  meth_var_types        /* method and variable type descriptors */
  meth_var_types        /* method and variable type descriptors */
};
};
 
 
static tree add_objc_string (tree, enum string_section);
static tree add_objc_string (tree, enum string_section);
static tree build_objc_string_decl (enum string_section);
static tree build_objc_string_decl (enum string_section);
static void build_selector_table_decl (void);
static void build_selector_table_decl (void);
 
 
/* Protocol additions.  */
/* Protocol additions.  */
 
 
static tree lookup_protocol (tree);
static tree lookup_protocol (tree);
static tree lookup_and_install_protocols (tree);
static tree lookup_and_install_protocols (tree);
 
 
/* Type encoding.  */
/* Type encoding.  */
 
 
static void encode_type_qualifiers (tree);
static void encode_type_qualifiers (tree);
static void encode_type (tree, int, int);
static void encode_type (tree, int, int);
static void encode_field_decl (tree, int, int);
static void encode_field_decl (tree, int, int);
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
static void really_start_method (tree, tree);
static void really_start_method (tree, tree);
#else
#else
static void really_start_method (tree, struct c_arg_info *);
static void really_start_method (tree, struct c_arg_info *);
#endif
#endif
static int comp_proto_with_proto (tree, tree, int);
static int comp_proto_with_proto (tree, tree, int);
static void objc_push_parm (tree);
static void objc_push_parm (tree);
#ifdef OBJCPLUS
#ifdef OBJCPLUS
static tree objc_get_parm_info (int);
static tree objc_get_parm_info (int);
#else
#else
static struct c_arg_info *objc_get_parm_info (int);
static struct c_arg_info *objc_get_parm_info (int);
#endif
#endif
 
 
/* Utilities for debugging and error diagnostics.  */
/* Utilities for debugging and error diagnostics.  */
 
 
static char *gen_type_name (tree);
static char *gen_type_name (tree);
static char *gen_type_name_0 (tree);
static char *gen_type_name_0 (tree);
static char *gen_method_decl (tree);
static char *gen_method_decl (tree);
static char *gen_declaration (tree);
static char *gen_declaration (tree);
 
 
/* Everything else.  */
/* Everything else.  */
 
 
static tree create_field_decl (tree, const char *);
static tree create_field_decl (tree, const char *);
static void add_class_reference (tree);
static void add_class_reference (tree);
static void build_protocol_template (void);
static void build_protocol_template (void);
static tree encode_method_prototype (tree);
static tree encode_method_prototype (tree);
static void generate_classref_translation_entry (tree);
static void generate_classref_translation_entry (tree);
static void handle_class_ref (tree);
static void handle_class_ref (tree);
static void generate_struct_by_value_array (void)
static void generate_struct_by_value_array (void)
     ATTRIBUTE_NORETURN;
     ATTRIBUTE_NORETURN;
static void mark_referenced_methods (void);
static void mark_referenced_methods (void);
static void generate_objc_image_info (void);
static void generate_objc_image_info (void);
 
 
/*** Private Interface (data) ***/
/*** Private Interface (data) ***/
 
 
/* Reserved tag definitions.  */
/* Reserved tag definitions.  */
 
 
#define OBJECT_TYPEDEF_NAME             "id"
#define OBJECT_TYPEDEF_NAME             "id"
#define CLASS_TYPEDEF_NAME              "Class"
#define CLASS_TYPEDEF_NAME              "Class"
 
 
#define TAG_OBJECT                      "objc_object"
#define TAG_OBJECT                      "objc_object"
#define TAG_CLASS                       "objc_class"
#define TAG_CLASS                       "objc_class"
#define TAG_SUPER                       "objc_super"
#define TAG_SUPER                       "objc_super"
#define TAG_SELECTOR                    "objc_selector"
#define TAG_SELECTOR                    "objc_selector"
 
 
#define UTAG_CLASS                      "_objc_class"
#define UTAG_CLASS                      "_objc_class"
#define UTAG_IVAR                       "_objc_ivar"
#define UTAG_IVAR                       "_objc_ivar"
#define UTAG_IVAR_LIST                  "_objc_ivar_list"
#define UTAG_IVAR_LIST                  "_objc_ivar_list"
#define UTAG_METHOD                     "_objc_method"
#define UTAG_METHOD                     "_objc_method"
#define UTAG_METHOD_LIST                "_objc_method_list"
#define UTAG_METHOD_LIST                "_objc_method_list"
#define UTAG_CATEGORY                   "_objc_category"
#define UTAG_CATEGORY                   "_objc_category"
#define UTAG_MODULE                     "_objc_module"
#define UTAG_MODULE                     "_objc_module"
#define UTAG_SYMTAB                     "_objc_symtab"
#define UTAG_SYMTAB                     "_objc_symtab"
#define UTAG_SUPER                      "_objc_super"
#define UTAG_SUPER                      "_objc_super"
#define UTAG_SELECTOR                   "_objc_selector"
#define UTAG_SELECTOR                   "_objc_selector"
 
 
#define UTAG_PROTOCOL                   "_objc_protocol"
#define UTAG_PROTOCOL                   "_objc_protocol"
#define UTAG_METHOD_PROTOTYPE           "_objc_method_prototype"
#define UTAG_METHOD_PROTOTYPE           "_objc_method_prototype"
#define UTAG_METHOD_PROTOTYPE_LIST      "_objc__method_prototype_list"
#define UTAG_METHOD_PROTOTYPE_LIST      "_objc__method_prototype_list"
 
 
/* Note that the string object global name is only needed for the
/* Note that the string object global name is only needed for the
   NeXT runtime.  */
   NeXT runtime.  */
#define STRING_OBJECT_GLOBAL_FORMAT     "_%sClassReference"
#define STRING_OBJECT_GLOBAL_FORMAT     "_%sClassReference"
 
 
#define PROTOCOL_OBJECT_CLASS_NAME      "Protocol"
#define PROTOCOL_OBJECT_CLASS_NAME      "Protocol"
 
 
static const char *TAG_GETCLASS;
static const char *TAG_GETCLASS;
static const char *TAG_GETMETACLASS;
static const char *TAG_GETMETACLASS;
static const char *TAG_MSGSEND;
static const char *TAG_MSGSEND;
static const char *TAG_MSGSENDSUPER;
static const char *TAG_MSGSENDSUPER;
/* The NeXT Objective-C messenger may have two extra entry points, for use
/* The NeXT Objective-C messenger may have two extra entry points, for use
   when returning a structure. */
   when returning a structure. */
static const char *TAG_MSGSEND_STRET;
static const char *TAG_MSGSEND_STRET;
static const char *TAG_MSGSENDSUPER_STRET;
static const char *TAG_MSGSENDSUPER_STRET;
static const char *default_constant_string_class_name;
static const char *default_constant_string_class_name;
 
 
/* Runtime metadata flags.  */
/* Runtime metadata flags.  */
#define CLS_FACTORY                     0x0001L
#define CLS_FACTORY                     0x0001L
#define CLS_META                        0x0002L
#define CLS_META                        0x0002L
#define CLS_HAS_CXX_STRUCTORS           0x2000L
#define CLS_HAS_CXX_STRUCTORS           0x2000L
 
 
#define OBJC_MODIFIER_STATIC            0x00000001
#define OBJC_MODIFIER_STATIC            0x00000001
#define OBJC_MODIFIER_FINAL             0x00000002
#define OBJC_MODIFIER_FINAL             0x00000002
#define OBJC_MODIFIER_PUBLIC            0x00000004
#define OBJC_MODIFIER_PUBLIC            0x00000004
#define OBJC_MODIFIER_PRIVATE           0x00000008
#define OBJC_MODIFIER_PRIVATE           0x00000008
#define OBJC_MODIFIER_PROTECTED         0x00000010
#define OBJC_MODIFIER_PROTECTED         0x00000010
#define OBJC_MODIFIER_NATIVE            0x00000020
#define OBJC_MODIFIER_NATIVE            0x00000020
#define OBJC_MODIFIER_SYNCHRONIZED      0x00000040
#define OBJC_MODIFIER_SYNCHRONIZED      0x00000040
#define OBJC_MODIFIER_ABSTRACT          0x00000080
#define OBJC_MODIFIER_ABSTRACT          0x00000080
#define OBJC_MODIFIER_VOLATILE          0x00000100
#define OBJC_MODIFIER_VOLATILE          0x00000100
#define OBJC_MODIFIER_TRANSIENT         0x00000200
#define OBJC_MODIFIER_TRANSIENT         0x00000200
#define OBJC_MODIFIER_NONE_SPECIFIED    0x80000000
#define OBJC_MODIFIER_NONE_SPECIFIED    0x80000000
 
 
/* NeXT-specific tags.  */
/* NeXT-specific tags.  */
 
 
#define TAG_MSGSEND_NONNIL              "objc_msgSendNonNil"
#define TAG_MSGSEND_NONNIL              "objc_msgSendNonNil"
#define TAG_MSGSEND_NONNIL_STRET        "objc_msgSendNonNil_stret"
#define TAG_MSGSEND_NONNIL_STRET        "objc_msgSendNonNil_stret"
#define TAG_EXCEPTIONEXTRACT            "objc_exception_extract"
#define TAG_EXCEPTIONEXTRACT            "objc_exception_extract"
#define TAG_EXCEPTIONTRYENTER           "objc_exception_try_enter"
#define TAG_EXCEPTIONTRYENTER           "objc_exception_try_enter"
#define TAG_EXCEPTIONTRYEXIT            "objc_exception_try_exit"
#define TAG_EXCEPTIONTRYEXIT            "objc_exception_try_exit"
#define TAG_EXCEPTIONMATCH              "objc_exception_match"
#define TAG_EXCEPTIONMATCH              "objc_exception_match"
#define TAG_EXCEPTIONTHROW              "objc_exception_throw"
#define TAG_EXCEPTIONTHROW              "objc_exception_throw"
#define TAG_SYNCENTER                   "objc_sync_enter"
#define TAG_SYNCENTER                   "objc_sync_enter"
#define TAG_SYNCEXIT                    "objc_sync_exit"
#define TAG_SYNCEXIT                    "objc_sync_exit"
#define TAG_SETJMP                      "_setjmp"
#define TAG_SETJMP                      "_setjmp"
#define UTAG_EXCDATA                    "_objc_exception_data"
#define UTAG_EXCDATA                    "_objc_exception_data"
 
 
#define TAG_ASSIGNIVAR                  "objc_assign_ivar"
#define TAG_ASSIGNIVAR                  "objc_assign_ivar"
#define TAG_ASSIGNGLOBAL                "objc_assign_global"
#define TAG_ASSIGNGLOBAL                "objc_assign_global"
#define TAG_ASSIGNSTRONGCAST            "objc_assign_strongCast"
#define TAG_ASSIGNSTRONGCAST            "objc_assign_strongCast"
 
 
/* Branch entry points.  All that matters here are the addresses;
/* Branch entry points.  All that matters here are the addresses;
   functions with these names do not really exist in libobjc.  */
   functions with these names do not really exist in libobjc.  */
 
 
#define TAG_MSGSEND_FAST                "objc_msgSend_Fast"
#define TAG_MSGSEND_FAST                "objc_msgSend_Fast"
#define TAG_ASSIGNIVAR_FAST             "objc_assign_ivar_Fast"
#define TAG_ASSIGNIVAR_FAST             "objc_assign_ivar_Fast"
 
 
#define TAG_CXX_CONSTRUCT               ".cxx_construct"
#define TAG_CXX_CONSTRUCT               ".cxx_construct"
#define TAG_CXX_DESTRUCT                ".cxx_destruct"
#define TAG_CXX_DESTRUCT                ".cxx_destruct"
 
 
/* GNU-specific tags.  */
/* GNU-specific tags.  */
 
 
#define TAG_EXECCLASS                   "__objc_exec_class"
#define TAG_EXECCLASS                   "__objc_exec_class"
#define TAG_GNUINIT                     "__objc_gnu_init"
#define TAG_GNUINIT                     "__objc_gnu_init"
 
 
/* Flags for lookup_method_static().  */
/* Flags for lookup_method_static().  */
#define OBJC_LOOKUP_CLASS       1       /* Look for class methods.  */
#define OBJC_LOOKUP_CLASS       1       /* Look for class methods.  */
#define OBJC_LOOKUP_NO_SUPER    2       /* Do not examine superclasses.  */
#define OBJC_LOOKUP_NO_SUPER    2       /* Do not examine superclasses.  */
 
 
/* The OCTI_... enumeration itself is in objc/objc-act.h.  */
/* The OCTI_... enumeration itself is in objc/objc-act.h.  */
tree objc_global_trees[OCTI_MAX];
tree objc_global_trees[OCTI_MAX];
 
 
static void handle_impent (struct imp_entry *);
static void handle_impent (struct imp_entry *);
 
 
struct imp_entry *imp_list = 0;
struct imp_entry *imp_list = 0;
int imp_count = 0;       /* `@implementation' */
int imp_count = 0;       /* `@implementation' */
int cat_count = 0;       /* `@category' */
int cat_count = 0;       /* `@category' */
 
 
enum tree_code objc_inherit_code;
enum tree_code objc_inherit_code;
int objc_public_flag;
int objc_public_flag;
 
 
/* Use to generate method labels.  */
/* Use to generate method labels.  */
static int method_slot = 0;
static int method_slot = 0;
 
 
#define BUFSIZE         1024
#define BUFSIZE         1024
 
 
static char *errbuf;    /* Buffer for error diagnostics */
static char *errbuf;    /* Buffer for error diagnostics */
 
 
/* Data imported from tree.c.  */
/* Data imported from tree.c.  */
 
 
extern enum debug_info_type write_symbols;
extern enum debug_info_type write_symbols;
 
 
/* Data imported from toplev.c.  */
/* Data imported from toplev.c.  */
 
 
extern const char *dump_base_name;
extern const char *dump_base_name;


static int flag_typed_selectors;
static int flag_typed_selectors;
 
 
/* Store all constructed constant strings in a hash table so that
/* Store all constructed constant strings in a hash table so that
   they get uniqued properly.  */
   they get uniqued properly.  */
 
 
struct GTY(()) string_descriptor {
struct GTY(()) string_descriptor {
  /* The literal argument .  */
  /* The literal argument .  */
  tree literal;
  tree literal;
 
 
  /* The resulting constant string.  */
  /* The resulting constant string.  */
  tree constructor;
  tree constructor;
};
};
 
 
static GTY((param_is (struct string_descriptor))) htab_t string_htab;
static GTY((param_is (struct string_descriptor))) htab_t string_htab;
 
 
/* Store the EH-volatilized types in a hash table, for easy retrieval.  */
/* Store the EH-volatilized types in a hash table, for easy retrieval.  */
struct GTY(()) volatilized_type {
struct GTY(()) volatilized_type {
  tree type;
  tree type;
};
};
 
 
static GTY((param_is (struct volatilized_type))) htab_t volatilized_htab;
static GTY((param_is (struct volatilized_type))) htab_t volatilized_htab;
 
 
FILE *gen_declaration_file;
FILE *gen_declaration_file;
 
 
/* Tells "encode_pointer/encode_aggregate" whether we are generating
/* Tells "encode_pointer/encode_aggregate" whether we are generating
   type descriptors for instance variables (as opposed to methods).
   type descriptors for instance variables (as opposed to methods).
   Type descriptors for instance variables contain more information
   Type descriptors for instance variables contain more information
   than methods (for static typing and embedded structures).  */
   than methods (for static typing and embedded structures).  */
 
 
static int generating_instance_variables = 0;
static int generating_instance_variables = 0;
 
 
/* For building an objc struct.  These may not be used when this file
/* For building an objc struct.  These may not be used when this file
   is compiled as part of obj-c++.  */
   is compiled as part of obj-c++.  */
 
 
static bool objc_building_struct;
static bool objc_building_struct;
static struct c_struct_parse_info *objc_struct_info ATTRIBUTE_UNUSED;
static struct c_struct_parse_info *objc_struct_info ATTRIBUTE_UNUSED;
 
 
/* Start building a struct for objc.  */
/* Start building a struct for objc.  */
 
 
static tree
static tree
objc_start_struct (tree name)
objc_start_struct (tree name)
{
{
  gcc_assert (!objc_building_struct);
  gcc_assert (!objc_building_struct);
  objc_building_struct = true;
  objc_building_struct = true;
  return start_struct (input_location, RECORD_TYPE, name, &objc_struct_info);
  return start_struct (input_location, RECORD_TYPE, name, &objc_struct_info);
}
}
 
 
/* Finish building a struct for objc.  */
/* Finish building a struct for objc.  */
 
 
static tree
static tree
objc_finish_struct (tree type, tree fieldlist)
objc_finish_struct (tree type, tree fieldlist)
{
{
  gcc_assert (objc_building_struct);
  gcc_assert (objc_building_struct);
  objc_building_struct = false;
  objc_building_struct = false;
  return finish_struct (input_location, type, fieldlist, NULL_TREE,
  return finish_struct (input_location, type, fieldlist, NULL_TREE,
                        objc_struct_info);
                        objc_struct_info);
}
}
 
 
/* Some platforms pass small structures through registers versus
/* Some platforms pass small structures through registers versus
   through an invisible pointer.  Determine at what size structure is
   through an invisible pointer.  Determine at what size structure is
   the transition point between the two possibilities.  */
   the transition point between the two possibilities.  */
 
 
static void
static void
generate_struct_by_value_array (void)
generate_struct_by_value_array (void)
{
{
  tree type;
  tree type;
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
  int i, j;
  int i, j;
  int aggregate_in_mem[32];
  int aggregate_in_mem[32];
  int found = 0;
  int found = 0;
 
 
  /* Presumably no platform passes 32 byte structures in a register.  */
  /* Presumably no platform passes 32 byte structures in a register.  */
  for (i = 1; i < 32; i++)
  for (i = 1; i < 32; i++)
    {
    {
      char buffer[5];
      char buffer[5];
 
 
      /* Create an unnamed struct that has `i' character components */
      /* Create an unnamed struct that has `i' character components */
      type = objc_start_struct (NULL_TREE);
      type = objc_start_struct (NULL_TREE);
 
 
      strcpy (buffer, "c1");
      strcpy (buffer, "c1");
      field_decl = create_field_decl (char_type_node,
      field_decl = create_field_decl (char_type_node,
                                      buffer);
                                      buffer);
      field_decl_chain = field_decl;
      field_decl_chain = field_decl;
 
 
      for (j = 1; j < i; j++)
      for (j = 1; j < i; j++)
        {
        {
          sprintf (buffer, "c%d", j + 1);
          sprintf (buffer, "c%d", j + 1);
          field_decl = create_field_decl (char_type_node,
          field_decl = create_field_decl (char_type_node,
                                          buffer);
                                          buffer);
          chainon (field_decl_chain, field_decl);
          chainon (field_decl_chain, field_decl);
        }
        }
      objc_finish_struct (type, field_decl_chain);
      objc_finish_struct (type, field_decl_chain);
 
 
      aggregate_in_mem[i] = aggregate_value_p (type, 0);
      aggregate_in_mem[i] = aggregate_value_p (type, 0);
      if (!aggregate_in_mem[i])
      if (!aggregate_in_mem[i])
        found = 1;
        found = 1;
    }
    }
 
 
  /* We found some structures that are returned in registers instead of memory
  /* We found some structures that are returned in registers instead of memory
     so output the necessary data.  */
     so output the necessary data.  */
  if (found)
  if (found)
    {
    {
      for (i = 31; i >= 0;  i--)
      for (i = 31; i >= 0;  i--)
        if (!aggregate_in_mem[i])
        if (!aggregate_in_mem[i])
          break;
          break;
      printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n\n", i);
      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
      /* The first member of the structure is always 0 because we don't handle
         structures with 0 members */
         structures with 0 members */
      printf ("static int struct_forward_array[] = {\n  0");
      printf ("static int struct_forward_array[] = {\n  0");
 
 
      for (j = 1; j <= i; j++)
      for (j = 1; j <= i; j++)
        printf (", %d", aggregate_in_mem[j]);
        printf (", %d", aggregate_in_mem[j]);
      printf ("\n};\n");
      printf ("\n};\n");
    }
    }
 
 
  exit (0);
  exit (0);
}
}
 
 
bool
bool
objc_init (void)
objc_init (void)
{
{
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (cxx_init () == false)
  if (cxx_init () == false)
#else
#else
  if (c_objc_common_init () == false)
  if (c_objc_common_init () == false)
#endif
#endif
    return false;
    return false;
 
 
  /* If gen_declaration desired, open the output file.  */
  /* If gen_declaration desired, open the output file.  */
  if (flag_gen_declaration)
  if (flag_gen_declaration)
    {
    {
      register char * const dumpname = concat (dump_base_name, ".decl", NULL);
      register char * const dumpname = concat (dump_base_name, ".decl", NULL);
      gen_declaration_file = fopen (dumpname, "w");
      gen_declaration_file = fopen (dumpname, "w");
      if (gen_declaration_file == 0)
      if (gen_declaration_file == 0)
        fatal_error ("can't open %s: %m", dumpname);
        fatal_error ("can't open %s: %m", dumpname);
      free (dumpname);
      free (dumpname);
    }
    }
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      TAG_GETCLASS = "objc_getClass";
      TAG_GETCLASS = "objc_getClass";
      TAG_GETMETACLASS = "objc_getMetaClass";
      TAG_GETMETACLASS = "objc_getMetaClass";
      TAG_MSGSEND = "objc_msgSend";
      TAG_MSGSEND = "objc_msgSend";
      TAG_MSGSENDSUPER = "objc_msgSendSuper";
      TAG_MSGSENDSUPER = "objc_msgSendSuper";
      TAG_MSGSEND_STRET = "objc_msgSend_stret";
      TAG_MSGSEND_STRET = "objc_msgSend_stret";
      TAG_MSGSENDSUPER_STRET = "objc_msgSendSuper_stret";
      TAG_MSGSENDSUPER_STRET = "objc_msgSendSuper_stret";
      default_constant_string_class_name = "NSConstantString";
      default_constant_string_class_name = "NSConstantString";
    }
    }
  else
  else
    {
    {
      TAG_GETCLASS = "objc_get_class";
      TAG_GETCLASS = "objc_get_class";
      TAG_GETMETACLASS = "objc_get_meta_class";
      TAG_GETMETACLASS = "objc_get_meta_class";
      TAG_MSGSEND = "objc_msg_lookup";
      TAG_MSGSEND = "objc_msg_lookup";
      TAG_MSGSENDSUPER = "objc_msg_lookup_super";
      TAG_MSGSENDSUPER = "objc_msg_lookup_super";
      /* GNU runtime does not provide special functions to support
      /* GNU runtime does not provide special functions to support
         structure-returning methods.  */
         structure-returning methods.  */
      default_constant_string_class_name = "NXConstantString";
      default_constant_string_class_name = "NXConstantString";
      flag_typed_selectors = 1;
      flag_typed_selectors = 1;
      /* GNU runtime does not need the compiler to change code
      /* GNU runtime does not need the compiler to change code
         in order to do GC. */
         in order to do GC. */
      if (flag_objc_gc)
      if (flag_objc_gc)
        {
        {
          warning_at (0, 0, "%<-fobjc-gc%> is ignored for %<-fgnu-runtime%>");
          warning_at (0, 0, "%<-fobjc-gc%> is ignored for %<-fgnu-runtime%>");
          flag_objc_gc=0;
          flag_objc_gc=0;
        }
        }
    }
    }
 
 
  init_objc ();
  init_objc ();
 
 
  if (print_struct_values && !flag_compare_debug)
  if (print_struct_values && !flag_compare_debug)
    generate_struct_by_value_array ();
    generate_struct_by_value_array ();
 
 
  return true;
  return true;
}
}
 
 
void
void
objc_finish_file (void)
objc_finish_file (void)
{
{
  mark_referenced_methods ();
  mark_referenced_methods ();
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  /* We need to instantiate templates _before_ we emit ObjC metadata;
  /* We need to instantiate templates _before_ we emit ObjC metadata;
     if we do not, some metadata (such as selectors) may go missing.  */
     if we do not, some metadata (such as selectors) may go missing.  */
  at_eof = 1;
  at_eof = 1;
  instantiate_pending_templates (0);
  instantiate_pending_templates (0);
#endif
#endif
 
 
  /* Finalize Objective-C runtime data.  No need to generate tables
  /* Finalize Objective-C runtime data.  No need to generate tables
     and code if only checking syntax, or if generating a PCH file.  */
     and code if only checking syntax, or if generating a PCH file.  */
  if (!flag_syntax_only && !pch_file)
  if (!flag_syntax_only && !pch_file)
    finish_objc ();
    finish_objc ();
 
 
  if (gen_declaration_file)
  if (gen_declaration_file)
    fclose (gen_declaration_file);
    fclose (gen_declaration_file);
}
}


/* Return the first occurrence of a method declaration corresponding
/* Return the first occurrence of a method declaration corresponding
   to sel_name in rproto_list.  Search rproto_list recursively.
   to sel_name in rproto_list.  Search rproto_list recursively.
   If is_class is 0, search for instance methods, otherwise for class
   If is_class is 0, search for instance methods, otherwise for class
   methods.  */
   methods.  */
static tree
static tree
lookup_method_in_protocol_list (tree rproto_list, tree sel_name,
lookup_method_in_protocol_list (tree rproto_list, tree sel_name,
                                int is_class)
                                int is_class)
{
{
   tree rproto, p;
   tree rproto, p;
   tree fnd = 0;
   tree fnd = 0;
 
 
   for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
   for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
     {
     {
        p = TREE_VALUE (rproto);
        p = TREE_VALUE (rproto);
 
 
        if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
        if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
          {
          {
            if ((fnd = lookup_method (is_class
            if ((fnd = lookup_method (is_class
                                      ? PROTOCOL_CLS_METHODS (p)
                                      ? PROTOCOL_CLS_METHODS (p)
                                      : PROTOCOL_NST_METHODS (p), sel_name)))
                                      : PROTOCOL_NST_METHODS (p), sel_name)))
              ;
              ;
            else if (PROTOCOL_LIST (p))
            else if (PROTOCOL_LIST (p))
              fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
              fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
                                                    sel_name, is_class);
                                                    sel_name, is_class);
          }
          }
        else
        else
          {
          {
            ; /* An identifier...if we could not find a protocol.  */
            ; /* An identifier...if we could not find a protocol.  */
          }
          }
 
 
        if (fnd)
        if (fnd)
          return fnd;
          return fnd;
     }
     }
 
 
   return 0;
   return 0;
}
}
 
 
static tree
static tree
lookup_protocol_in_reflist (tree rproto_list, tree lproto)
lookup_protocol_in_reflist (tree rproto_list, tree lproto)
{
{
  tree rproto, p;
  tree rproto, p;
 
 
  /* Make sure the protocol is supported by the object on the rhs.  */
  /* Make sure the protocol is supported by the object on the rhs.  */
  if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE)
  if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE)
    {
    {
      tree fnd = 0;
      tree fnd = 0;
      for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
      for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
        {
        {
          p = TREE_VALUE (rproto);
          p = TREE_VALUE (rproto);
 
 
          if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
          if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
            {
            {
              if (lproto == p)
              if (lproto == p)
                fnd = lproto;
                fnd = lproto;
 
 
              else if (PROTOCOL_LIST (p))
              else if (PROTOCOL_LIST (p))
                fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto);
                fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto);
            }
            }
 
 
          if (fnd)
          if (fnd)
            return fnd;
            return fnd;
        }
        }
    }
    }
  else
  else
    {
    {
      ; /* An identifier...if we could not find a protocol.  */
      ; /* An identifier...if we could not find a protocol.  */
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
void
void
objc_start_class_interface (tree klass, tree super_class, tree protos)
objc_start_class_interface (tree klass, tree super_class, tree protos)
{
{
  objc_interface_context
  objc_interface_context
    = objc_ivar_context
    = objc_ivar_context
    = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos);
    = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos);
  objc_public_flag = 0;
  objc_public_flag = 0;
}
}
 
 
void
void
objc_start_category_interface (tree klass, tree categ, tree protos)
objc_start_category_interface (tree klass, tree categ, tree protos)
{
{
  objc_interface_context
  objc_interface_context
    = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos);
    = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos);
  objc_ivar_chain
  objc_ivar_chain
    = continue_class (objc_interface_context);
    = continue_class (objc_interface_context);
}
}
 
 
void
void
objc_start_protocol (tree name, tree protos)
objc_start_protocol (tree name, tree protos)
{
{
  objc_interface_context
  objc_interface_context
    = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos);
    = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos);
}
}
 
 
void
void
objc_continue_interface (void)
objc_continue_interface (void)
{
{
  objc_ivar_chain
  objc_ivar_chain
    = continue_class (objc_interface_context);
    = continue_class (objc_interface_context);
}
}
 
 
void
void
objc_finish_interface (void)
objc_finish_interface (void)
{
{
  finish_class (objc_interface_context);
  finish_class (objc_interface_context);
  objc_interface_context = NULL_TREE;
  objc_interface_context = NULL_TREE;
}
}
 
 
void
void
objc_start_class_implementation (tree klass, tree super_class)
objc_start_class_implementation (tree klass, tree super_class)
{
{
  objc_implementation_context
  objc_implementation_context
    = objc_ivar_context
    = objc_ivar_context
    = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE);
    = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE);
  objc_public_flag = 0;
  objc_public_flag = 0;
}
}
 
 
void
void
objc_start_category_implementation (tree klass, tree categ)
objc_start_category_implementation (tree klass, tree categ)
{
{
  objc_implementation_context
  objc_implementation_context
    = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE);
    = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE);
  objc_ivar_chain
  objc_ivar_chain
    = continue_class (objc_implementation_context);
    = continue_class (objc_implementation_context);
}
}
 
 
void
void
objc_continue_implementation (void)
objc_continue_implementation (void)
{
{
  objc_ivar_chain
  objc_ivar_chain
    = continue_class (objc_implementation_context);
    = continue_class (objc_implementation_context);
}
}
 
 
void
void
objc_finish_implementation (void)
objc_finish_implementation (void)
{
{
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (flag_objc_call_cxx_cdtors)
  if (flag_objc_call_cxx_cdtors)
    objc_generate_cxx_cdtors ();
    objc_generate_cxx_cdtors ();
#endif
#endif
 
 
  if (objc_implementation_context)
  if (objc_implementation_context)
    {
    {
      finish_class (objc_implementation_context);
      finish_class (objc_implementation_context);
      objc_ivar_chain = NULL_TREE;
      objc_ivar_chain = NULL_TREE;
      objc_implementation_context = NULL_TREE;
      objc_implementation_context = NULL_TREE;
    }
    }
  else
  else
    warning (0, "%<@end%> must appear in an @implementation context");
    warning (0, "%<@end%> must appear in an @implementation context");
}
}
 
 
void
void
objc_set_visibility (int visibility)
objc_set_visibility (int visibility)
{
{
  objc_public_flag = visibility;
  objc_public_flag = visibility;
}
}
 
 
void
void
objc_set_method_type (enum tree_code type)
objc_set_method_type (enum tree_code type)
{
{
  objc_inherit_code = (type == PLUS_EXPR
  objc_inherit_code = (type == PLUS_EXPR
                       ? CLASS_METHOD_DECL
                       ? CLASS_METHOD_DECL
                       : INSTANCE_METHOD_DECL);
                       : INSTANCE_METHOD_DECL);
}
}
 
 
tree
tree
objc_build_method_signature (tree rettype, tree selector,
objc_build_method_signature (tree rettype, tree selector,
                             tree optparms, bool ellipsis)
                             tree optparms, bool ellipsis)
{
{
  return build_method_decl (objc_inherit_code, rettype, selector,
  return build_method_decl (objc_inherit_code, rettype, selector,
                            optparms, ellipsis);
                            optparms, ellipsis);
}
}
 
 
void
void
objc_add_method_declaration (tree decl)
objc_add_method_declaration (tree decl)
{
{
  if (!objc_interface_context)
  if (!objc_interface_context)
    fatal_error ("method declaration not in @interface context");
    fatal_error ("method declaration not in @interface context");
 
 
  objc_add_method (objc_interface_context,
  objc_add_method (objc_interface_context,
                   decl,
                   decl,
                   objc_inherit_code == CLASS_METHOD_DECL);
                   objc_inherit_code == CLASS_METHOD_DECL);
}
}
 
 
void
void
objc_start_method_definition (tree decl)
objc_start_method_definition (tree decl)
{
{
  if (!objc_implementation_context)
  if (!objc_implementation_context)
    fatal_error ("method definition not in @implementation context");
    fatal_error ("method definition not in @implementation context");
 
 
  objc_add_method (objc_implementation_context,
  objc_add_method (objc_implementation_context,
                   decl,
                   decl,
                   objc_inherit_code == CLASS_METHOD_DECL);
                   objc_inherit_code == CLASS_METHOD_DECL);
  start_method_def (decl);
  start_method_def (decl);
}
}
 
 
void
void
objc_add_instance_variable (tree decl)
objc_add_instance_variable (tree decl)
{
{
  (void) add_instance_variable (objc_ivar_context,
  (void) add_instance_variable (objc_ivar_context,
                                objc_public_flag,
                                objc_public_flag,
                                decl);
                                decl);
}
}
 
 
/* Return 1 if IDENT is an ObjC/ObjC++ reserved keyword in the context of
/* Return 1 if IDENT is an ObjC/ObjC++ reserved keyword in the context of
   an '@'.  */
   an '@'.  */
 
 
int
int
objc_is_reserved_word (tree ident)
objc_is_reserved_word (tree ident)
{
{
  unsigned char code = C_RID_CODE (ident);
  unsigned char code = C_RID_CODE (ident);
 
 
  return (OBJC_IS_AT_KEYWORD (code)
  return (OBJC_IS_AT_KEYWORD (code)
          || code == RID_CLASS || code == RID_PUBLIC
          || code == RID_CLASS || code == RID_PUBLIC
          || code == RID_PROTECTED || code == RID_PRIVATE
          || code == RID_PROTECTED || code == RID_PRIVATE
          || code == RID_TRY || code == RID_THROW || code == RID_CATCH);
          || code == RID_TRY || code == RID_THROW || code == RID_CATCH);
}
}
 
 
/* Return true if TYPE is 'id'.  */
/* Return true if TYPE is 'id'.  */
 
 
static bool
static bool
objc_is_object_id (tree type)
objc_is_object_id (tree type)
{
{
  return OBJC_TYPE_NAME (type) == objc_object_id;
  return OBJC_TYPE_NAME (type) == objc_object_id;
}
}
 
 
static bool
static bool
objc_is_class_id (tree type)
objc_is_class_id (tree type)
{
{
  return OBJC_TYPE_NAME (type) == objc_class_id;
  return OBJC_TYPE_NAME (type) == objc_class_id;
}
}
 
 
/* Construct a C struct with same name as KLASS, a base struct with tag
/* Construct a C struct with same name as KLASS, a base struct with tag
   SUPER_NAME (if any), and FIELDS indicated.  */
   SUPER_NAME (if any), and FIELDS indicated.  */
 
 
static tree
static tree
objc_build_struct (tree klass, tree fields, tree super_name)
objc_build_struct (tree klass, tree fields, tree super_name)
{
{
  tree name = CLASS_NAME (klass);
  tree name = CLASS_NAME (klass);
  tree s = objc_start_struct (name);
  tree s = objc_start_struct (name);
  tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE);
  tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE);
  tree t, objc_info = NULL_TREE;
  tree t, objc_info = NULL_TREE;
 
 
  if (super)
  if (super)
    {
    {
      /* Prepend a packed variant of the base class into the layout.  This
      /* Prepend a packed variant of the base class into the layout.  This
         is necessary to preserve ObjC ABI compatibility.  */
         is necessary to preserve ObjC ABI compatibility.  */
      tree base = build_decl (input_location,
      tree base = build_decl (input_location,
                              FIELD_DECL, NULL_TREE, super);
                              FIELD_DECL, NULL_TREE, super);
      tree field = TYPE_FIELDS (super);
      tree field = TYPE_FIELDS (super);
 
 
      while (field && TREE_CHAIN (field)
      while (field && TREE_CHAIN (field)
             && TREE_CODE (TREE_CHAIN (field)) == FIELD_DECL)
             && TREE_CODE (TREE_CHAIN (field)) == FIELD_DECL)
        field = TREE_CHAIN (field);
        field = TREE_CHAIN (field);
 
 
      /* For ObjC ABI purposes, the "packed" size of a base class is
      /* For ObjC ABI purposes, the "packed" size of a base class is
         the sum of the offset and the size (in bits) of the last field
         the sum of the offset and the size (in bits) of the last field
         in the class.  */
         in the class.  */
      DECL_SIZE (base)
      DECL_SIZE (base)
        = (field && TREE_CODE (field) == FIELD_DECL
        = (field && TREE_CODE (field) == FIELD_DECL
           ? size_binop (PLUS_EXPR,
           ? size_binop (PLUS_EXPR,
                         size_binop (PLUS_EXPR,
                         size_binop (PLUS_EXPR,
                                     size_binop
                                     size_binop
                                     (MULT_EXPR,
                                     (MULT_EXPR,
                                      convert (bitsizetype,
                                      convert (bitsizetype,
                                               DECL_FIELD_OFFSET (field)),
                                               DECL_FIELD_OFFSET (field)),
                                      bitsize_int (BITS_PER_UNIT)),
                                      bitsize_int (BITS_PER_UNIT)),
                                     DECL_FIELD_BIT_OFFSET (field)),
                                     DECL_FIELD_BIT_OFFSET (field)),
                         DECL_SIZE (field))
                         DECL_SIZE (field))
           : bitsize_zero_node);
           : bitsize_zero_node);
      DECL_SIZE_UNIT (base)
      DECL_SIZE_UNIT (base)
        = size_binop (FLOOR_DIV_EXPR, convert (sizetype, DECL_SIZE (base)),
        = size_binop (FLOOR_DIV_EXPR, convert (sizetype, DECL_SIZE (base)),
                      size_int (BITS_PER_UNIT));
                      size_int (BITS_PER_UNIT));
      DECL_ARTIFICIAL (base) = 1;
      DECL_ARTIFICIAL (base) = 1;
      DECL_ALIGN (base) = 1;
      DECL_ALIGN (base) = 1;
      DECL_FIELD_CONTEXT (base) = s;
      DECL_FIELD_CONTEXT (base) = s;
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      DECL_FIELD_IS_BASE (base) = 1;
      DECL_FIELD_IS_BASE (base) = 1;
 
 
      if (fields)
      if (fields)
        TREE_NO_WARNING (fields) = 1;   /* Suppress C++ ABI warnings -- we   */
        TREE_NO_WARNING (fields) = 1;   /* Suppress C++ ABI warnings -- we   */
#endif                                  /* are following the ObjC ABI here.  */
#endif                                  /* are following the ObjC ABI here.  */
      TREE_CHAIN (base) = fields;
      TREE_CHAIN (base) = fields;
      fields = base;
      fields = base;
    }
    }
 
 
  /* NB: Calling finish_struct() may cause type TYPE_LANG_SPECIFIC fields
  /* NB: Calling finish_struct() may cause type TYPE_LANG_SPECIFIC fields
     in all variants of this RECORD_TYPE to be clobbered, but it is therein
     in all variants of this RECORD_TYPE to be clobbered, but it is therein
     that we store protocol conformance info (e.g., 'NSObject <MyProtocol>').
     that we store protocol conformance info (e.g., 'NSObject <MyProtocol>').
     Hence, we must squirrel away the ObjC-specific information before calling
     Hence, we must squirrel away the ObjC-specific information before calling
     finish_struct(), and then reinstate it afterwards.  */
     finish_struct(), and then reinstate it afterwards.  */
 
 
  for (t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t))
  for (t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t))
    {
    {
      if (!TYPE_HAS_OBJC_INFO (t))
      if (!TYPE_HAS_OBJC_INFO (t))
        {
        {
          INIT_TYPE_OBJC_INFO (t);
          INIT_TYPE_OBJC_INFO (t);
          TYPE_OBJC_INTERFACE (t) = klass;
          TYPE_OBJC_INTERFACE (t) = klass;
        }
        }
      objc_info
      objc_info
        = chainon (objc_info,
        = chainon (objc_info,
                   build_tree_list (NULL_TREE, TYPE_OBJC_INFO (t)));
                   build_tree_list (NULL_TREE, TYPE_OBJC_INFO (t)));
    }
    }
 
 
  /* Point the struct at its related Objective-C class.  */
  /* Point the struct at its related Objective-C class.  */
  INIT_TYPE_OBJC_INFO (s);
  INIT_TYPE_OBJC_INFO (s);
  TYPE_OBJC_INTERFACE (s) = klass;
  TYPE_OBJC_INTERFACE (s) = klass;
 
 
  s = objc_finish_struct (s, fields);
  s = objc_finish_struct (s, fields);
 
 
  for (t = TYPE_NEXT_VARIANT (s); t;
  for (t = TYPE_NEXT_VARIANT (s); t;
       t = TYPE_NEXT_VARIANT (t), objc_info = TREE_CHAIN (objc_info))
       t = TYPE_NEXT_VARIANT (t), objc_info = TREE_CHAIN (objc_info))
    {
    {
      TYPE_OBJC_INFO (t) = TREE_VALUE (objc_info);
      TYPE_OBJC_INFO (t) = TREE_VALUE (objc_info);
      /* Replace the IDENTIFIER_NODE with an actual @interface.  */
      /* Replace the IDENTIFIER_NODE with an actual @interface.  */
      TYPE_OBJC_INTERFACE (t) = klass;
      TYPE_OBJC_INTERFACE (t) = klass;
    }
    }
 
 
  /* Use TYPE_BINFO structures to point at the super class, if any.  */
  /* Use TYPE_BINFO structures to point at the super class, if any.  */
  objc_xref_basetypes (s, super);
  objc_xref_basetypes (s, super);
 
 
  /* Mark this struct as a class template.  */
  /* Mark this struct as a class template.  */
  CLASS_STATIC_TEMPLATE (klass) = s;
  CLASS_STATIC_TEMPLATE (klass) = s;
 
 
  return s;
  return s;
}
}
 
 
/* Build a type differing from TYPE only in that TYPE_VOLATILE is set.
/* Build a type differing from TYPE only in that TYPE_VOLATILE is set.
   Unlike tree.c:build_qualified_type(), preserve TYPE_LANG_SPECIFIC in the
   Unlike tree.c:build_qualified_type(), preserve TYPE_LANG_SPECIFIC in the
   process.  */
   process.  */
static tree
static tree
objc_build_volatilized_type (tree type)
objc_build_volatilized_type (tree type)
{
{
  tree t;
  tree t;
 
 
  /* Check if we have not constructed the desired variant already.  */
  /* Check if we have not constructed the desired variant already.  */
  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
    {
    {
      /* The type qualifiers must (obviously) match up.  */
      /* The type qualifiers must (obviously) match up.  */
      if (!TYPE_VOLATILE (t)
      if (!TYPE_VOLATILE (t)
          || (TYPE_READONLY (t) != TYPE_READONLY (type))
          || (TYPE_READONLY (t) != TYPE_READONLY (type))
          || (TYPE_RESTRICT (t) != TYPE_RESTRICT (type)))
          || (TYPE_RESTRICT (t) != TYPE_RESTRICT (type)))
        continue;
        continue;
 
 
      /* For pointer types, the pointees (and hence their TYPE_LANG_SPECIFIC
      /* For pointer types, the pointees (and hence their TYPE_LANG_SPECIFIC
         info, if any) must match up.  */
         info, if any) must match up.  */
      if (POINTER_TYPE_P (t)
      if (POINTER_TYPE_P (t)
          && (TREE_TYPE (t) != TREE_TYPE (type)))
          && (TREE_TYPE (t) != TREE_TYPE (type)))
        continue;
        continue;
 
 
      /* Everything matches up!  */
      /* Everything matches up!  */
      return t;
      return t;
    }
    }
 
 
  /* Ok, we could not re-use any of the pre-existing variants.  Create
  /* Ok, we could not re-use any of the pre-existing variants.  Create
     a new one.  */
     a new one.  */
  t = build_variant_type_copy (type);
  t = build_variant_type_copy (type);
  TYPE_VOLATILE (t) = 1;
  TYPE_VOLATILE (t) = 1;
 
 
  /* Set up the canonical type information. */
  /* Set up the canonical type information. */
  if (TYPE_STRUCTURAL_EQUALITY_P (type))
  if (TYPE_STRUCTURAL_EQUALITY_P (type))
    SET_TYPE_STRUCTURAL_EQUALITY (t);
    SET_TYPE_STRUCTURAL_EQUALITY (t);
  else if (TYPE_CANONICAL (type) != type)
  else if (TYPE_CANONICAL (type) != type)
    TYPE_CANONICAL (t) = objc_build_volatilized_type (TYPE_CANONICAL (type));
    TYPE_CANONICAL (t) = objc_build_volatilized_type (TYPE_CANONICAL (type));
  else
  else
    TYPE_CANONICAL (t) = t;
    TYPE_CANONICAL (t) = t;
 
 
  return t;
  return t;
}
}
 
 
/* Mark DECL as being 'volatile' for purposes of Darwin
/* Mark DECL as being 'volatile' for purposes of Darwin
   _setjmp()/_longjmp() exception handling.  Called from
   _setjmp()/_longjmp() exception handling.  Called from
   objc_mark_locals_volatile().  */
   objc_mark_locals_volatile().  */
void
void
objc_volatilize_decl (tree decl)
objc_volatilize_decl (tree decl)
{
{
  /* Do not mess with variables that are 'static' or (already)
  /* Do not mess with variables that are 'static' or (already)
     'volatile'.  */
     'volatile'.  */
  if (!TREE_THIS_VOLATILE (decl) && !TREE_STATIC (decl)
  if (!TREE_THIS_VOLATILE (decl) && !TREE_STATIC (decl)
      && (TREE_CODE (decl) == VAR_DECL
      && (TREE_CODE (decl) == VAR_DECL
          || TREE_CODE (decl) == PARM_DECL))
          || TREE_CODE (decl) == PARM_DECL))
    {
    {
      tree t = TREE_TYPE (decl);
      tree t = TREE_TYPE (decl);
      struct volatilized_type key;
      struct volatilized_type key;
      void **loc;
      void **loc;
 
 
      t = objc_build_volatilized_type (t);
      t = objc_build_volatilized_type (t);
      key.type = t;
      key.type = t;
      loc = htab_find_slot (volatilized_htab, &key, INSERT);
      loc = htab_find_slot (volatilized_htab, &key, INSERT);
 
 
      if (!*loc)
      if (!*loc)
        {
        {
          *loc = ggc_alloc (sizeof (key));
          *loc = ggc_alloc (sizeof (key));
          ((struct volatilized_type *) *loc)->type = t;
          ((struct volatilized_type *) *loc)->type = t;
        }
        }
 
 
      TREE_TYPE (decl) = t;
      TREE_TYPE (decl) = t;
      TREE_THIS_VOLATILE (decl) = 1;
      TREE_THIS_VOLATILE (decl) = 1;
      TREE_SIDE_EFFECTS (decl) = 1;
      TREE_SIDE_EFFECTS (decl) = 1;
      DECL_REGISTER (decl) = 0;
      DECL_REGISTER (decl) = 0;
#ifndef OBJCPLUS
#ifndef OBJCPLUS
      C_DECL_REGISTER (decl) = 0;
      C_DECL_REGISTER (decl) = 0;
#endif
#endif
    }
    }
}
}
 
 
/* Check if protocol PROTO is adopted (directly or indirectly) by class CLS
/* Check if protocol PROTO is adopted (directly or indirectly) by class CLS
   (including its categories and superclasses) or by object type TYP.
   (including its categories and superclasses) or by object type TYP.
   Issue a warning if PROTO is not adopted anywhere and WARN is set.  */
   Issue a warning if PROTO is not adopted anywhere and WARN is set.  */
 
 
static bool
static bool
objc_lookup_protocol (tree proto, tree cls, tree typ, bool warn)
objc_lookup_protocol (tree proto, tree cls, tree typ, bool warn)
{
{
  bool class_type = (cls != NULL_TREE);
  bool class_type = (cls != NULL_TREE);
 
 
  while (cls)
  while (cls)
    {
    {
      tree c;
      tree c;
 
 
      /* Check protocols adopted by the class and its categories.  */
      /* Check protocols adopted by the class and its categories.  */
      for (c = cls; c; c = CLASS_CATEGORY_LIST (c))
      for (c = cls; c; c = CLASS_CATEGORY_LIST (c))
        {
        {
          if (lookup_protocol_in_reflist (CLASS_PROTOCOL_LIST (c), proto))
          if (lookup_protocol_in_reflist (CLASS_PROTOCOL_LIST (c), proto))
            return true;
            return true;
        }
        }
 
 
      /* Repeat for superclasses.  */
      /* Repeat for superclasses.  */
      cls = lookup_interface (CLASS_SUPER_NAME (cls));
      cls = lookup_interface (CLASS_SUPER_NAME (cls));
    }
    }
 
 
  /* Check for any protocols attached directly to the object type.  */
  /* Check for any protocols attached directly to the object type.  */
  if (TYPE_HAS_OBJC_INFO (typ))
  if (TYPE_HAS_OBJC_INFO (typ))
    {
    {
      if (lookup_protocol_in_reflist (TYPE_OBJC_PROTOCOL_LIST (typ), proto))
      if (lookup_protocol_in_reflist (TYPE_OBJC_PROTOCOL_LIST (typ), proto))
        return true;
        return true;
    }
    }
 
 
  if (warn)
  if (warn)
    {
    {
      *errbuf = 0;
      *errbuf = 0;
      gen_type_name_0 (class_type ? typ : TYPE_POINTER_TO (typ));
      gen_type_name_0 (class_type ? typ : TYPE_POINTER_TO (typ));
      /* NB: Types 'id' and 'Class' cannot reasonably be described as
      /* NB: Types 'id' and 'Class' cannot reasonably be described as
         "implementing" a given protocol, since they do not have an
         "implementing" a given protocol, since they do not have an
         implementation.  */
         implementation.  */
      if (class_type)
      if (class_type)
        warning (0, "class %qs does not implement the %qE protocol",
        warning (0, "class %qs does not implement the %qE protocol",
                 identifier_to_locale (errbuf), PROTOCOL_NAME (proto));
                 identifier_to_locale (errbuf), PROTOCOL_NAME (proto));
      else
      else
        warning (0, "type %qs does not conform to the %qE protocol",
        warning (0, "type %qs does not conform to the %qE protocol",
                 identifier_to_locale (errbuf), PROTOCOL_NAME (proto));
                 identifier_to_locale (errbuf), PROTOCOL_NAME (proto));
    }
    }
 
 
  return false;
  return false;
}
}
 
 
/* Check if class RCLS and instance struct type RTYP conform to at least the
/* Check if class RCLS and instance struct type RTYP conform to at least the
   same protocols that LCLS and LTYP conform to.  */
   same protocols that LCLS and LTYP conform to.  */
 
 
static bool
static bool
objc_compare_protocols (tree lcls, tree ltyp, tree rcls, tree rtyp, bool warn)
objc_compare_protocols (tree lcls, tree ltyp, tree rcls, tree rtyp, bool warn)
{
{
  tree p;
  tree p;
  bool have_lproto = false;
  bool have_lproto = false;
 
 
  while (lcls)
  while (lcls)
    {
    {
      /* NB: We do _not_ look at categories defined for LCLS; these may or
      /* NB: We do _not_ look at categories defined for LCLS; these may or
         may not get loaded in, and therefore it is unreasonable to require
         may not get loaded in, and therefore it is unreasonable to require
         that RCLS/RTYP must implement any of their protocols.  */
         that RCLS/RTYP must implement any of their protocols.  */
      for (p = CLASS_PROTOCOL_LIST (lcls); p; p = TREE_CHAIN (p))
      for (p = CLASS_PROTOCOL_LIST (lcls); p; p = TREE_CHAIN (p))
        {
        {
          have_lproto = true;
          have_lproto = true;
 
 
          if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn))
          if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn))
            return warn;
            return warn;
        }
        }
 
 
      /* Repeat for superclasses.  */
      /* Repeat for superclasses.  */
      lcls = lookup_interface (CLASS_SUPER_NAME (lcls));
      lcls = lookup_interface (CLASS_SUPER_NAME (lcls));
    }
    }
 
 
  /* Check for any protocols attached directly to the object type.  */
  /* Check for any protocols attached directly to the object type.  */
  if (TYPE_HAS_OBJC_INFO (ltyp))
  if (TYPE_HAS_OBJC_INFO (ltyp))
    {
    {
      for (p = TYPE_OBJC_PROTOCOL_LIST (ltyp); p; p = TREE_CHAIN (p))
      for (p = TYPE_OBJC_PROTOCOL_LIST (ltyp); p; p = TREE_CHAIN (p))
        {
        {
          have_lproto = true;
          have_lproto = true;
 
 
          if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn))
          if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn))
            return warn;
            return warn;
        }
        }
    }
    }
 
 
  /* NB: If LTYP and LCLS have no protocols to search for, return 'true'
  /* NB: If LTYP and LCLS have no protocols to search for, return 'true'
     vacuously, _unless_ RTYP is a protocol-qualified 'id'.  We can get
     vacuously, _unless_ RTYP is a protocol-qualified 'id'.  We can get
     away with simply checking for 'id' or 'Class' (!RCLS), since this
     away with simply checking for 'id' or 'Class' (!RCLS), since this
     routine will not get called in other cases.  */
     routine will not get called in other cases.  */
  return have_lproto || (rcls != NULL_TREE);
  return have_lproto || (rcls != NULL_TREE);
}
}
 
 
/* Determine if it is permissible to assign (if ARGNO is greater than -3)
/* Determine if it is permissible to assign (if ARGNO is greater than -3)
   an instance of RTYP to an instance of LTYP or to compare the two
   an instance of RTYP to an instance of LTYP or to compare the two
   (if ARGNO is equal to -3), per ObjC type system rules.  Before
   (if ARGNO is equal to -3), per ObjC type system rules.  Before
   returning 'true', this routine may issue warnings related to, e.g.,
   returning 'true', this routine may issue warnings related to, e.g.,
   protocol conformance.  When returning 'false', the routine must
   protocol conformance.  When returning 'false', the routine must
   produce absolutely no warnings; the C or C++ front-end will do so
   produce absolutely no warnings; the C or C++ front-end will do so
   instead, if needed.  If either LTYP or RTYP is not an Objective-C type,
   instead, if needed.  If either LTYP or RTYP is not an Objective-C type,
   the routine must return 'false'.
   the routine must return 'false'.
 
 
   The ARGNO parameter is encoded as follows:
   The ARGNO parameter is encoded as follows:
     >= 1       Parameter number (CALLEE contains function being called);
     >= 1       Parameter number (CALLEE contains function being called);
     0          Return value;
     0          Return value;
     -1         Assignment;
     -1         Assignment;
     -2         Initialization;
     -2         Initialization;
     -3         Comparison (LTYP and RTYP may match in either direction).  */
     -3         Comparison (LTYP and RTYP may match in either direction).  */
 
 
bool
bool
objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
{
{
  tree lcls, rcls, lproto, rproto;
  tree lcls, rcls, lproto, rproto;
  bool pointers_compatible;
  bool pointers_compatible;
 
 
  /* We must be dealing with pointer types */
  /* We must be dealing with pointer types */
  if (!POINTER_TYPE_P (ltyp) || !POINTER_TYPE_P (rtyp))
  if (!POINTER_TYPE_P (ltyp) || !POINTER_TYPE_P (rtyp))
    return false;
    return false;
 
 
  do
  do
    {
    {
      ltyp = TREE_TYPE (ltyp);  /* Remove indirections.  */
      ltyp = TREE_TYPE (ltyp);  /* Remove indirections.  */
      rtyp = TREE_TYPE (rtyp);
      rtyp = TREE_TYPE (rtyp);
    }
    }
  while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp));
  while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp));
 
 
  /* Past this point, we are only interested in ObjC class instances,
  /* Past this point, we are only interested in ObjC class instances,
     or 'id' or 'Class'.  */
     or 'id' or 'Class'.  */
  if (TREE_CODE (ltyp) != RECORD_TYPE || TREE_CODE (rtyp) != RECORD_TYPE)
  if (TREE_CODE (ltyp) != RECORD_TYPE || TREE_CODE (rtyp) != RECORD_TYPE)
    return false;
    return false;
 
 
  if (!objc_is_object_id (ltyp) && !objc_is_class_id (ltyp)
  if (!objc_is_object_id (ltyp) && !objc_is_class_id (ltyp)
      && !TYPE_HAS_OBJC_INFO (ltyp))
      && !TYPE_HAS_OBJC_INFO (ltyp))
    return false;
    return false;
 
 
  if (!objc_is_object_id (rtyp) && !objc_is_class_id (rtyp)
  if (!objc_is_object_id (rtyp) && !objc_is_class_id (rtyp)
      && !TYPE_HAS_OBJC_INFO (rtyp))
      && !TYPE_HAS_OBJC_INFO (rtyp))
    return false;
    return false;
 
 
  /* Past this point, we are committed to returning 'true' to the caller.
  /* Past this point, we are committed to returning 'true' to the caller.
     However, we can still warn about type and/or protocol mismatches.  */
     However, we can still warn about type and/or protocol mismatches.  */
 
 
  if (TYPE_HAS_OBJC_INFO (ltyp))
  if (TYPE_HAS_OBJC_INFO (ltyp))
    {
    {
      lcls = TYPE_OBJC_INTERFACE (ltyp);
      lcls = TYPE_OBJC_INTERFACE (ltyp);
      lproto = TYPE_OBJC_PROTOCOL_LIST (ltyp);
      lproto = TYPE_OBJC_PROTOCOL_LIST (ltyp);
    }
    }
  else
  else
    lcls = lproto = NULL_TREE;
    lcls = lproto = NULL_TREE;
 
 
  if (TYPE_HAS_OBJC_INFO (rtyp))
  if (TYPE_HAS_OBJC_INFO (rtyp))
    {
    {
      rcls = TYPE_OBJC_INTERFACE (rtyp);
      rcls = TYPE_OBJC_INTERFACE (rtyp);
      rproto = TYPE_OBJC_PROTOCOL_LIST (rtyp);
      rproto = TYPE_OBJC_PROTOCOL_LIST (rtyp);
    }
    }
  else
  else
    rcls = rproto = NULL_TREE;
    rcls = rproto = NULL_TREE;
 
 
  /* If we could not find an @interface declaration, we must have
  /* If we could not find an @interface declaration, we must have
     only seen a @class declaration; for purposes of type comparison,
     only seen a @class declaration; for purposes of type comparison,
     treat it as a stand-alone (root) class.  */
     treat it as a stand-alone (root) class.  */
 
 
  if (lcls && TREE_CODE (lcls) == IDENTIFIER_NODE)
  if (lcls && TREE_CODE (lcls) == IDENTIFIER_NODE)
    lcls = NULL_TREE;
    lcls = NULL_TREE;
 
 
  if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE)
  if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE)
    rcls = NULL_TREE;
    rcls = NULL_TREE;
 
 
  /* If either type is an unqualified 'id', we're done.  */
  /* If either type is an unqualified 'id', we're done.  */
  if ((!lproto && objc_is_object_id (ltyp))
  if ((!lproto && objc_is_object_id (ltyp))
      || (!rproto && objc_is_object_id (rtyp)))
      || (!rproto && objc_is_object_id (rtyp)))
    return true;
    return true;
 
 
  pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp));
  pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp));
 
 
  /* If the underlying types are the same, and at most one of them has
  /* If the underlying types are the same, and at most one of them has
     a protocol list, we do not need to issue any diagnostics.  */
     a protocol list, we do not need to issue any diagnostics.  */
  if (pointers_compatible && (!lproto || !rproto))
  if (pointers_compatible && (!lproto || !rproto))
    return true;
    return true;
 
 
  /* If exactly one of the types is 'Class', issue a diagnostic; any
  /* If exactly one of the types is 'Class', issue a diagnostic; any
     exceptions of this rule have already been handled.  */
     exceptions of this rule have already been handled.  */
  if (objc_is_class_id (ltyp) ^ objc_is_class_id (rtyp))
  if (objc_is_class_id (ltyp) ^ objc_is_class_id (rtyp))
    pointers_compatible = false;
    pointers_compatible = false;
  /* Otherwise, check for inheritance relations.  */
  /* Otherwise, check for inheritance relations.  */
  else
  else
    {
    {
      if (!pointers_compatible)
      if (!pointers_compatible)
        pointers_compatible
        pointers_compatible
          = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
          = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
 
 
      if (!pointers_compatible)
      if (!pointers_compatible)
        pointers_compatible = DERIVED_FROM_P (ltyp, rtyp);
        pointers_compatible = DERIVED_FROM_P (ltyp, rtyp);
 
 
      if (!pointers_compatible && argno == -3)
      if (!pointers_compatible && argno == -3)
        pointers_compatible = DERIVED_FROM_P (rtyp, ltyp);
        pointers_compatible = DERIVED_FROM_P (rtyp, ltyp);
    }
    }
 
 
  /* If the pointers match modulo protocols, check for protocol conformance
  /* If the pointers match modulo protocols, check for protocol conformance
     mismatches.  */
     mismatches.  */
  if (pointers_compatible)
  if (pointers_compatible)
    {
    {
      pointers_compatible = objc_compare_protocols (lcls, ltyp, rcls, rtyp,
      pointers_compatible = objc_compare_protocols (lcls, ltyp, rcls, rtyp,
                                                    argno != -3);
                                                    argno != -3);
 
 
      if (!pointers_compatible && argno == -3)
      if (!pointers_compatible && argno == -3)
        pointers_compatible = objc_compare_protocols (rcls, rtyp, lcls, ltyp,
        pointers_compatible = objc_compare_protocols (rcls, rtyp, lcls, ltyp,
                                                      argno != -3);
                                                      argno != -3);
    }
    }
 
 
  if (!pointers_compatible)
  if (!pointers_compatible)
    {
    {
      /* NB: For the time being, we shall make our warnings look like their
      /* NB: For the time being, we shall make our warnings look like their
         C counterparts.  In the future, we may wish to make them more
         C counterparts.  In the future, we may wish to make them more
         ObjC-specific.  */
         ObjC-specific.  */
      switch (argno)
      switch (argno)
        {
        {
        case -3:
        case -3:
          warning (0, "comparison of distinct Objective-C types lacks a cast");
          warning (0, "comparison of distinct Objective-C types lacks a cast");
          break;
          break;
 
 
        case -2:
        case -2:
          warning (0, "initialization from distinct Objective-C type");
          warning (0, "initialization from distinct Objective-C type");
          break;
          break;
 
 
        case -1:
        case -1:
          warning (0, "assignment from distinct Objective-C type");
          warning (0, "assignment from distinct Objective-C type");
          break;
          break;
 
 
        case 0:
        case 0:
          warning (0, "distinct Objective-C type in return");
          warning (0, "distinct Objective-C type in return");
          break;
          break;
 
 
        default:
        default:
          warning (0, "passing argument %d of %qE from distinct "
          warning (0, "passing argument %d of %qE from distinct "
                   "Objective-C type", argno, callee);
                   "Objective-C type", argno, callee);
          break;
          break;
        }
        }
    }
    }
 
 
  return true;
  return true;
}
}
 
 
/* Check if LTYP and RTYP have the same type qualifiers.  If either type
/* Check if LTYP and RTYP have the same type qualifiers.  If either type
   lives in the volatilized hash table, ignore the 'volatile' bit when
   lives in the volatilized hash table, ignore the 'volatile' bit when
   making the comparison.  */
   making the comparison.  */
 
 
bool
bool
objc_type_quals_match (tree ltyp, tree rtyp)
objc_type_quals_match (tree ltyp, tree rtyp)
{
{
  int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp);
  int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp);
  struct volatilized_type key;
  struct volatilized_type key;
 
 
  key.type = ltyp;
  key.type = ltyp;
 
 
  if (htab_find_slot (volatilized_htab, &key, NO_INSERT))
  if (htab_find_slot (volatilized_htab, &key, NO_INSERT))
    lquals &= ~TYPE_QUAL_VOLATILE;
    lquals &= ~TYPE_QUAL_VOLATILE;
 
 
  key.type = rtyp;
  key.type = rtyp;
 
 
  if (htab_find_slot (volatilized_htab, &key, NO_INSERT))
  if (htab_find_slot (volatilized_htab, &key, NO_INSERT))
    rquals &= ~TYPE_QUAL_VOLATILE;
    rquals &= ~TYPE_QUAL_VOLATILE;
 
 
  return (lquals == rquals);
  return (lquals == rquals);
}
}
 
 
#ifndef OBJCPLUS
#ifndef OBJCPLUS
/* Determine if CHILD is derived from PARENT.  The routine assumes that
/* Determine if CHILD is derived from PARENT.  The routine assumes that
   both parameters are RECORD_TYPEs, and is non-reflexive.  */
   both parameters are RECORD_TYPEs, and is non-reflexive.  */
 
 
static bool
static bool
objc_derived_from_p (tree parent, tree child)
objc_derived_from_p (tree parent, tree child)
{
{
  parent = TYPE_MAIN_VARIANT (parent);
  parent = TYPE_MAIN_VARIANT (parent);
 
 
  for (child = TYPE_MAIN_VARIANT (child);
  for (child = TYPE_MAIN_VARIANT (child);
       TYPE_BINFO (child) && BINFO_N_BASE_BINFOS (TYPE_BINFO (child));)
       TYPE_BINFO (child) && BINFO_N_BASE_BINFOS (TYPE_BINFO (child));)
    {
    {
      child = TYPE_MAIN_VARIANT (BINFO_TYPE (BINFO_BASE_BINFO
      child = TYPE_MAIN_VARIANT (BINFO_TYPE (BINFO_BASE_BINFO
                                             (TYPE_BINFO (child),
                                             (TYPE_BINFO (child),
                                              0)));
                                              0)));
 
 
      if (child == parent)
      if (child == parent)
        return true;
        return true;
    }
    }
 
 
  return false;
  return false;
}
}
#endif
#endif
 
 
static tree
static tree
objc_build_component_ref (tree datum, tree component)
objc_build_component_ref (tree datum, tree component)
{
{
  /* If COMPONENT is NULL, the caller is referring to the anonymous
  /* If COMPONENT is NULL, the caller is referring to the anonymous
     base class field.  */
     base class field.  */
  if (!component)
  if (!component)
    {
    {
      tree base = TYPE_FIELDS (TREE_TYPE (datum));
      tree base = TYPE_FIELDS (TREE_TYPE (datum));
 
 
      return build3 (COMPONENT_REF, TREE_TYPE (base), datum, base, NULL_TREE);
      return build3 (COMPONENT_REF, TREE_TYPE (base), datum, base, NULL_TREE);
    }
    }
 
 
  /* The 'build_component_ref' routine has been removed from the C++
  /* The 'build_component_ref' routine has been removed from the C++
     front-end, but 'finish_class_member_access_expr' seems to be
     front-end, but 'finish_class_member_access_expr' seems to be
     a worthy substitute.  */
     a worthy substitute.  */
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  return finish_class_member_access_expr (datum, component, false,
  return finish_class_member_access_expr (datum, component, false,
                                          tf_warning_or_error);
                                          tf_warning_or_error);
#else
#else
  return build_component_ref (input_location, datum, component);
  return build_component_ref (input_location, datum, component);
#endif
#endif
}
}
 
 
/* Recursively copy inheritance information rooted at BINFO.  To do this,
/* Recursively copy inheritance information rooted at BINFO.  To do this,
   we emulate the song and dance performed by cp/tree.c:copy_binfo().  */
   we emulate the song and dance performed by cp/tree.c:copy_binfo().  */
 
 
static tree
static tree
objc_copy_binfo (tree binfo)
objc_copy_binfo (tree binfo)
{
{
  tree btype = BINFO_TYPE (binfo);
  tree btype = BINFO_TYPE (binfo);
  tree binfo2 = make_tree_binfo (BINFO_N_BASE_BINFOS (binfo));
  tree binfo2 = make_tree_binfo (BINFO_N_BASE_BINFOS (binfo));
  tree base_binfo;
  tree base_binfo;
  int ix;
  int ix;
 
 
  BINFO_TYPE (binfo2) = btype;
  BINFO_TYPE (binfo2) = btype;
  BINFO_OFFSET (binfo2) = BINFO_OFFSET (binfo);
  BINFO_OFFSET (binfo2) = BINFO_OFFSET (binfo);
  BINFO_BASE_ACCESSES (binfo2) = BINFO_BASE_ACCESSES (binfo);
  BINFO_BASE_ACCESSES (binfo2) = BINFO_BASE_ACCESSES (binfo);
 
 
  /* Recursively copy base binfos of BINFO.  */
  /* Recursively copy base binfos of BINFO.  */
  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
    {
    {
      tree base_binfo2 = objc_copy_binfo (base_binfo);
      tree base_binfo2 = objc_copy_binfo (base_binfo);
 
 
      BINFO_INHERITANCE_CHAIN (base_binfo2) = binfo2;
      BINFO_INHERITANCE_CHAIN (base_binfo2) = binfo2;
      BINFO_BASE_APPEND (binfo2, base_binfo2);
      BINFO_BASE_APPEND (binfo2, base_binfo2);
    }
    }
 
 
  return binfo2;
  return binfo2;
}
}
 
 
/* Record superclass information provided in BASETYPE for ObjC class REF.
/* Record superclass information provided in BASETYPE for ObjC class REF.
   This is loosely based on cp/decl.c:xref_basetypes().  */
   This is loosely based on cp/decl.c:xref_basetypes().  */
 
 
static void
static void
objc_xref_basetypes (tree ref, tree basetype)
objc_xref_basetypes (tree ref, tree basetype)
{
{
  tree binfo = make_tree_binfo (basetype ? 1 : 0);
  tree binfo = make_tree_binfo (basetype ? 1 : 0);
 
 
  TYPE_BINFO (ref) = binfo;
  TYPE_BINFO (ref) = binfo;
  BINFO_OFFSET (binfo) = size_zero_node;
  BINFO_OFFSET (binfo) = size_zero_node;
  BINFO_TYPE (binfo) = ref;
  BINFO_TYPE (binfo) = ref;
 
 
  if (basetype)
  if (basetype)
    {
    {
      tree base_binfo = objc_copy_binfo (TYPE_BINFO (basetype));
      tree base_binfo = objc_copy_binfo (TYPE_BINFO (basetype));
 
 
      BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
      BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
      BINFO_BASE_ACCESSES (binfo) = VEC_alloc (tree, gc, 1);
      BINFO_BASE_ACCESSES (binfo) = VEC_alloc (tree, gc, 1);
      BINFO_BASE_APPEND (binfo, base_binfo);
      BINFO_BASE_APPEND (binfo, base_binfo);
      BINFO_BASE_ACCESS_APPEND (binfo, access_public_node);
      BINFO_BASE_ACCESS_APPEND (binfo, access_public_node);
    }
    }
}
}
 
 
static hashval_t
static hashval_t
volatilized_hash (const void *ptr)
volatilized_hash (const void *ptr)
{
{
  const_tree const typ = ((const struct volatilized_type *)ptr)->type;
  const_tree const typ = ((const struct volatilized_type *)ptr)->type;
 
 
  return htab_hash_pointer(typ);
  return htab_hash_pointer(typ);
}
}
 
 
static int
static int
volatilized_eq (const void *ptr1, const void *ptr2)
volatilized_eq (const void *ptr1, const void *ptr2)
{
{
  const_tree const typ1 = ((const struct volatilized_type *)ptr1)->type;
  const_tree const typ1 = ((const struct volatilized_type *)ptr1)->type;
  const_tree const typ2 = ((const struct volatilized_type *)ptr2)->type;
  const_tree const typ2 = ((const struct volatilized_type *)ptr2)->type;
 
 
  return typ1 == typ2;
  return typ1 == typ2;
}
}
 
 
/* Called from finish_decl.  */
/* Called from finish_decl.  */
 
 
void
void
objc_check_decl (tree decl)
objc_check_decl (tree decl)
{
{
  tree type = TREE_TYPE (decl);
  tree type = TREE_TYPE (decl);
 
 
  if (TREE_CODE (type) != RECORD_TYPE)
  if (TREE_CODE (type) != RECORD_TYPE)
    return;
    return;
  if (OBJC_TYPE_NAME (type) && (type = objc_is_class_name (OBJC_TYPE_NAME (type))))
  if (OBJC_TYPE_NAME (type) && (type = objc_is_class_name (OBJC_TYPE_NAME (type))))
    error ("statically allocated instance of Objective-C class %qE",
    error ("statically allocated instance of Objective-C class %qE",
           type);
           type);
}
}
 
 
/* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may
/* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may
   either name an Objective-C class, or refer to the special 'id' or 'Class'
   either name an Objective-C class, or refer to the special 'id' or 'Class'
   types.  If INTERFACE is not a valid ObjC type, just return it unchanged.  */
   types.  If INTERFACE is not a valid ObjC type, just return it unchanged.  */
 
 
tree
tree
objc_get_protocol_qualified_type (tree interface, tree protocols)
objc_get_protocol_qualified_type (tree interface, tree protocols)
{
{
  /* If INTERFACE is not provided, default to 'id'.  */
  /* If INTERFACE is not provided, default to 'id'.  */
  tree type = (interface ? objc_is_id (interface) : objc_object_type);
  tree type = (interface ? objc_is_id (interface) : objc_object_type);
  bool is_ptr = (type != NULL_TREE);
  bool is_ptr = (type != NULL_TREE);
 
 
  if (!is_ptr)
  if (!is_ptr)
    {
    {
      type = objc_is_class_name (interface);
      type = objc_is_class_name (interface);
 
 
      if (type)
      if (type)
        type = xref_tag (RECORD_TYPE, type);
        type = xref_tag (RECORD_TYPE, type);
      else
      else
        return interface;
        return interface;
    }
    }
 
 
  if (protocols)
  if (protocols)
    {
    {
      type = build_variant_type_copy (type);
      type = build_variant_type_copy (type);
 
 
      /* For pointers (i.e., 'id' or 'Class'), attach the protocol(s)
      /* For pointers (i.e., 'id' or 'Class'), attach the protocol(s)
         to the pointee.  */
         to the pointee.  */
      if (is_ptr)
      if (is_ptr)
        {
        {
          tree orig_pointee_type = TREE_TYPE (type);
          tree orig_pointee_type = TREE_TYPE (type);
          TREE_TYPE (type) = build_variant_type_copy (orig_pointee_type);
          TREE_TYPE (type) = build_variant_type_copy (orig_pointee_type);
 
 
          /* Set up the canonical type information. */
          /* Set up the canonical type information. */
          TYPE_CANONICAL (type)
          TYPE_CANONICAL (type)
            = TYPE_CANONICAL (TYPE_POINTER_TO (orig_pointee_type));
            = TYPE_CANONICAL (TYPE_POINTER_TO (orig_pointee_type));
 
 
          TYPE_POINTER_TO (TREE_TYPE (type)) = type;
          TYPE_POINTER_TO (TREE_TYPE (type)) = type;
          type = TREE_TYPE (type);
          type = TREE_TYPE (type);
        }
        }
 
 
      /* Look up protocols and install in lang specific list.  */
      /* Look up protocols and install in lang specific list.  */
      DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type));
      DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type));
      TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols (protocols);
      TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols (protocols);
 
 
      /* For RECORD_TYPEs, point to the @interface; for 'id' and 'Class',
      /* For RECORD_TYPEs, point to the @interface; for 'id' and 'Class',
         return the pointer to the new pointee variant.  */
         return the pointer to the new pointee variant.  */
      if (is_ptr)
      if (is_ptr)
        type = TYPE_POINTER_TO (type);
        type = TYPE_POINTER_TO (type);
      else
      else
        TYPE_OBJC_INTERFACE (type)
        TYPE_OBJC_INTERFACE (type)
          = TYPE_OBJC_INTERFACE (TYPE_MAIN_VARIANT (type));
          = TYPE_OBJC_INTERFACE (TYPE_MAIN_VARIANT (type));
    }
    }
 
 
  return type;
  return type;
}
}
 
 
/* Check for circular dependencies in protocols.  The arguments are
/* Check for circular dependencies in protocols.  The arguments are
   PROTO, the protocol to check, and LIST, a list of protocol it
   PROTO, the protocol to check, and LIST, a list of protocol it
   conforms to.  */
   conforms to.  */
 
 
static void
static void
check_protocol_recursively (tree proto, tree list)
check_protocol_recursively (tree proto, tree list)
{
{
  tree p;
  tree p;
 
 
  for (p = list; p; p = TREE_CHAIN (p))
  for (p = list; p; p = TREE_CHAIN (p))
    {
    {
      tree pp = TREE_VALUE (p);
      tree pp = TREE_VALUE (p);
 
 
      if (TREE_CODE (pp) == IDENTIFIER_NODE)
      if (TREE_CODE (pp) == IDENTIFIER_NODE)
        pp = lookup_protocol (pp);
        pp = lookup_protocol (pp);
 
 
      if (pp == proto)
      if (pp == proto)
        fatal_error ("protocol %qE has circular dependency",
        fatal_error ("protocol %qE has circular dependency",
                     PROTOCOL_NAME (pp));
                     PROTOCOL_NAME (pp));
      if (pp)
      if (pp)
        check_protocol_recursively (proto, PROTOCOL_LIST (pp));
        check_protocol_recursively (proto, PROTOCOL_LIST (pp));
    }
    }
}
}
 
 
/* Look up PROTOCOLS, and return a list of those that are found.
/* Look up PROTOCOLS, and return a list of those that are found.
   If none are found, return NULL.  */
   If none are found, return NULL.  */
 
 
static tree
static tree
lookup_and_install_protocols (tree protocols)
lookup_and_install_protocols (tree protocols)
{
{
  tree proto;
  tree proto;
  tree return_value = NULL_TREE;
  tree return_value = NULL_TREE;
 
 
  for (proto = protocols; proto; proto = TREE_CHAIN (proto))
  for (proto = protocols; proto; proto = TREE_CHAIN (proto))
    {
    {
      tree ident = TREE_VALUE (proto);
      tree ident = TREE_VALUE (proto);
      tree p = lookup_protocol (ident);
      tree p = lookup_protocol (ident);
 
 
      if (p)
      if (p)
        return_value = chainon (return_value,
        return_value = chainon (return_value,
                                build_tree_list (NULL_TREE, p));
                                build_tree_list (NULL_TREE, p));
      else if (ident != error_mark_node)
      else if (ident != error_mark_node)
        error ("cannot find protocol declaration for %qE",
        error ("cannot find protocol declaration for %qE",
               ident);
               ident);
    }
    }
 
 
  return return_value;
  return return_value;
}
}
 
 
/* Create a declaration for field NAME of a given TYPE.  */
/* Create a declaration for field NAME of a given TYPE.  */
 
 
static tree
static tree
create_field_decl (tree type, const char *name)
create_field_decl (tree type, const char *name)
{
{
  return build_decl (input_location,
  return build_decl (input_location,
                     FIELD_DECL, get_identifier (name), type);
                     FIELD_DECL, get_identifier (name), type);
}
}
 
 
/* Create a global, static declaration for variable NAME of a given TYPE.  The
/* Create a global, static declaration for variable NAME of a given TYPE.  The
   finish_var_decl() routine will need to be called on it afterwards.  */
   finish_var_decl() routine will need to be called on it afterwards.  */
 
 
static tree
static tree
start_var_decl (tree type, const char *name)
start_var_decl (tree type, const char *name)
{
{
  tree var = build_decl (input_location,
  tree var = build_decl (input_location,
                         VAR_DECL, get_identifier (name), type);
                         VAR_DECL, get_identifier (name), type);
 
 
  TREE_STATIC (var) = 1;
  TREE_STATIC (var) = 1;
  DECL_INITIAL (var) = error_mark_node;  /* A real initializer is coming... */
  DECL_INITIAL (var) = error_mark_node;  /* A real initializer is coming... */
  DECL_IGNORED_P (var) = 1;
  DECL_IGNORED_P (var) = 1;
  DECL_ARTIFICIAL (var) = 1;
  DECL_ARTIFICIAL (var) = 1;
  DECL_CONTEXT (var) = NULL_TREE;
  DECL_CONTEXT (var) = NULL_TREE;
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  DECL_THIS_STATIC (var) = 1; /* squash redeclaration errors */
  DECL_THIS_STATIC (var) = 1; /* squash redeclaration errors */
#endif
#endif
 
 
  return var;
  return var;
}
}
 
 
/* Finish off the variable declaration created by start_var_decl().  */
/* Finish off the variable declaration created by start_var_decl().  */
 
 
static void
static void
finish_var_decl (tree var, tree initializer)
finish_var_decl (tree var, tree initializer)
{
{
  finish_decl (var, input_location, initializer, NULL_TREE, NULL_TREE);
  finish_decl (var, input_location, initializer, NULL_TREE, NULL_TREE);
  /* Ensure that the variable actually gets output.  */
  /* Ensure that the variable actually gets output.  */
  mark_decl_referenced (var);
  mark_decl_referenced (var);
  /* Mark the decl to avoid "defined but not used" warning.  */
  /* Mark the decl to avoid "defined but not used" warning.  */
  TREE_USED (var) = 1;
  TREE_USED (var) = 1;
  /* We reserve the right for the runtime to use/modify these variables
  /* We reserve the right for the runtime to use/modify these variables
     in ways that are opaque to us.  */
     in ways that are opaque to us.  */
  DECL_PRESERVE_P (var) = 1;
  DECL_PRESERVE_P (var) = 1;
}
}
 
 
/* Find the decl for the constant string class reference.  This is only
/* Find the decl for the constant string class reference.  This is only
   used for the NeXT runtime.  */
   used for the NeXT runtime.  */
 
 
static tree
static tree
setup_string_decl (void)
setup_string_decl (void)
{
{
  char *name;
  char *name;
  size_t length;
  size_t length;
 
 
  /* %s in format will provide room for terminating null */
  /* %s in format will provide room for terminating null */
  length = strlen (STRING_OBJECT_GLOBAL_FORMAT)
  length = strlen (STRING_OBJECT_GLOBAL_FORMAT)
           + strlen (constant_string_class_name);
           + strlen (constant_string_class_name);
  name = XNEWVEC (char, length);
  name = XNEWVEC (char, length);
  sprintf (name, STRING_OBJECT_GLOBAL_FORMAT,
  sprintf (name, STRING_OBJECT_GLOBAL_FORMAT,
           constant_string_class_name);
           constant_string_class_name);
  constant_string_global_id = get_identifier (name);
  constant_string_global_id = get_identifier (name);
  string_class_decl = lookup_name (constant_string_global_id);
  string_class_decl = lookup_name (constant_string_global_id);
 
 
  return string_class_decl;
  return string_class_decl;
}
}
 
 
/* Purpose: "play" parser, creating/installing representations
/* Purpose: "play" parser, creating/installing representations
   of the declarations that are required by Objective-C.
   of the declarations that are required by Objective-C.
 
 
   Model:
   Model:
 
 
        type_spec--------->sc_spec
        type_spec--------->sc_spec
        (tree_list)        (tree_list)
        (tree_list)        (tree_list)
            |                  |
            |                  |
            |                  |
            |                  |
        identifier_node    identifier_node  */
        identifier_node    identifier_node  */
 
 
static void
static void
synth_module_prologue (void)
synth_module_prologue (void)
{
{
  tree type;
  tree type;
  enum debug_info_type save_write_symbols = write_symbols;
  enum debug_info_type save_write_symbols = write_symbols;
  const struct gcc_debug_hooks *const save_hooks = debug_hooks;
  const struct gcc_debug_hooks *const save_hooks = debug_hooks;
 
 
  /* Suppress outputting debug symbols, because
  /* Suppress outputting debug symbols, because
     dbxout_init hasn't been called yet.  */
     dbxout_init hasn't been called yet.  */
  write_symbols = NO_DEBUG;
  write_symbols = NO_DEBUG;
  debug_hooks = &do_nothing_debug_hooks;
  debug_hooks = &do_nothing_debug_hooks;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  push_lang_context (lang_name_c); /* extern "C" */
  push_lang_context (lang_name_c); /* extern "C" */
#endif
#endif
 
 
  /* The following are also defined in <objc/objc.h> and friends.  */
  /* The following are also defined in <objc/objc.h> and friends.  */
 
 
  objc_object_id = get_identifier (TAG_OBJECT);
  objc_object_id = get_identifier (TAG_OBJECT);
  objc_class_id = get_identifier (TAG_CLASS);
  objc_class_id = get_identifier (TAG_CLASS);
 
 
  objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id);
  objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id);
  objc_class_reference = xref_tag (RECORD_TYPE, objc_class_id);
  objc_class_reference = xref_tag (RECORD_TYPE, objc_class_id);
 
 
  objc_object_type = build_pointer_type (objc_object_reference);
  objc_object_type = build_pointer_type (objc_object_reference);
  objc_class_type = build_pointer_type (objc_class_reference);
  objc_class_type = build_pointer_type (objc_class_reference);
 
 
  objc_object_name = get_identifier (OBJECT_TYPEDEF_NAME);
  objc_object_name = get_identifier (OBJECT_TYPEDEF_NAME);
  objc_class_name = get_identifier (CLASS_TYPEDEF_NAME);
  objc_class_name = get_identifier (CLASS_TYPEDEF_NAME);
 
 
  /* Declare the 'id' and 'Class' typedefs.  */
  /* Declare the 'id' and 'Class' typedefs.  */
 
 
  type = lang_hooks.decls.pushdecl (build_decl (input_location,
  type = lang_hooks.decls.pushdecl (build_decl (input_location,
                                                TYPE_DECL,
                                                TYPE_DECL,
                                                objc_object_name,
                                                objc_object_name,
                                                objc_object_type));
                                                objc_object_type));
  TREE_NO_WARNING (type) = 1;
  TREE_NO_WARNING (type) = 1;
  type = lang_hooks.decls.pushdecl (build_decl (input_location,
  type = lang_hooks.decls.pushdecl (build_decl (input_location,
                                                TYPE_DECL,
                                                TYPE_DECL,
                                                objc_class_name,
                                                objc_class_name,
                                                objc_class_type));
                                                objc_class_type));
  TREE_NO_WARNING (type) = 1;
  TREE_NO_WARNING (type) = 1;
 
 
  /* Forward-declare '@interface Protocol'.  */
  /* Forward-declare '@interface Protocol'.  */
 
 
  type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME);
  type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME);
  objc_declare_class (tree_cons (NULL_TREE, type, NULL_TREE));
  objc_declare_class (tree_cons (NULL_TREE, type, NULL_TREE));
  objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE,
  objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE,
                                type));
                                type));
 
 
  /* Declare type of selector-objects that represent an operation name.  */
  /* Declare type of selector-objects that represent an operation name.  */
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    /* `struct objc_selector *' */
    /* `struct objc_selector *' */
    objc_selector_type
    objc_selector_type
      = build_pointer_type (xref_tag (RECORD_TYPE,
      = build_pointer_type (xref_tag (RECORD_TYPE,
                                      get_identifier (TAG_SELECTOR)));
                                      get_identifier (TAG_SELECTOR)));
  else
  else
    /* `const struct objc_selector *' */
    /* `const struct objc_selector *' */
    objc_selector_type
    objc_selector_type
      = build_pointer_type
      = build_pointer_type
        (build_qualified_type (xref_tag (RECORD_TYPE,
        (build_qualified_type (xref_tag (RECORD_TYPE,
                                         get_identifier (TAG_SELECTOR)),
                                         get_identifier (TAG_SELECTOR)),
                               TYPE_QUAL_CONST));
                               TYPE_QUAL_CONST));
 
 
  /* Declare receiver type used for dispatching messages to 'super'.  */
  /* Declare receiver type used for dispatching messages to 'super'.  */
 
 
  /* `struct objc_super *' */
  /* `struct objc_super *' */
  objc_super_type = build_pointer_type (xref_tag (RECORD_TYPE,
  objc_super_type = build_pointer_type (xref_tag (RECORD_TYPE,
                                                  get_identifier (TAG_SUPER)));
                                                  get_identifier (TAG_SUPER)));
 
 
  /* Declare pointers to method and ivar lists.  */
  /* Declare pointers to method and ivar lists.  */
  objc_method_list_ptr = build_pointer_type
  objc_method_list_ptr = build_pointer_type
                         (xref_tag (RECORD_TYPE,
                         (xref_tag (RECORD_TYPE,
                                    get_identifier (UTAG_METHOD_LIST)));
                                    get_identifier (UTAG_METHOD_LIST)));
  objc_method_proto_list_ptr
  objc_method_proto_list_ptr
    = build_pointer_type (xref_tag (RECORD_TYPE,
    = build_pointer_type (xref_tag (RECORD_TYPE,
                                    get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
                                    get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
  objc_ivar_list_ptr = build_pointer_type
  objc_ivar_list_ptr = build_pointer_type
                       (xref_tag (RECORD_TYPE,
                       (xref_tag (RECORD_TYPE,
                                  get_identifier (UTAG_IVAR_LIST)));
                                  get_identifier (UTAG_IVAR_LIST)));
 
 
  /* TREE_NOTHROW is cleared for the message-sending functions,
  /* TREE_NOTHROW is cleared for the message-sending functions,
     because the function that gets called can throw in Obj-C++, or
     because the function that gets called can throw in Obj-C++, or
     could itself call something that can throw even in Obj-C.  */
     could itself call something that can throw even in Obj-C.  */
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      /* NB: In order to call one of the ..._stret (struct-returning)
      /* NB: In order to call one of the ..._stret (struct-returning)
      functions, the function *MUST* first be cast to a signature that
      functions, the function *MUST* first be cast to a signature that
      corresponds to the actual ObjC method being invoked.  This is
      corresponds to the actual ObjC method being invoked.  This is
      what is done by the build_objc_method_call() routine below.  */
      what is done by the build_objc_method_call() routine below.  */
 
 
      /* id objc_msgSend (id, SEL, ...); */
      /* id objc_msgSend (id, SEL, ...); */
      /* id objc_msgSendNonNil (id, SEL, ...); */
      /* id objc_msgSendNonNil (id, SEL, ...); */
      /* id objc_msgSend_stret (id, SEL, ...); */
      /* id objc_msgSend_stret (id, SEL, ...); */
      /* id objc_msgSendNonNil_stret (id, SEL, ...); */
      /* id objc_msgSendNonNil_stret (id, SEL, ...); */
      type
      type
        = build_function_type (objc_object_type,
        = build_function_type (objc_object_type,
                               tree_cons (NULL_TREE, objc_object_type,
                               tree_cons (NULL_TREE, objc_object_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                                     NULL_TREE)));
                                                     NULL_TREE)));
      umsg_decl = add_builtin_function (TAG_MSGSEND,
      umsg_decl = add_builtin_function (TAG_MSGSEND,
                                        type, 0, NOT_BUILT_IN,
                                        type, 0, NOT_BUILT_IN,
                                        NULL, NULL_TREE);
                                        NULL, NULL_TREE);
      umsg_nonnil_decl = add_builtin_function (TAG_MSGSEND_NONNIL,
      umsg_nonnil_decl = add_builtin_function (TAG_MSGSEND_NONNIL,
                                               type, 0, NOT_BUILT_IN,
                                               type, 0, NOT_BUILT_IN,
                                               NULL, NULL_TREE);
                                               NULL, NULL_TREE);
      umsg_stret_decl = add_builtin_function (TAG_MSGSEND_STRET,
      umsg_stret_decl = add_builtin_function (TAG_MSGSEND_STRET,
                                              type, 0, NOT_BUILT_IN,
                                              type, 0, NOT_BUILT_IN,
                                              NULL, NULL_TREE);
                                              NULL, NULL_TREE);
      umsg_nonnil_stret_decl = add_builtin_function (TAG_MSGSEND_NONNIL_STRET,
      umsg_nonnil_stret_decl = add_builtin_function (TAG_MSGSEND_NONNIL_STRET,
                                                     type, 0, NOT_BUILT_IN,
                                                     type, 0, NOT_BUILT_IN,
                                                     NULL, NULL_TREE);
                                                     NULL, NULL_TREE);
 
 
      /* These can throw, because the function that gets called can throw
      /* These can throw, because the function that gets called can throw
         in Obj-C++, or could itself call something that can throw even
         in Obj-C++, or could itself call something that can throw even
         in Obj-C.  */
         in Obj-C.  */
      TREE_NOTHROW (umsg_decl) = 0;
      TREE_NOTHROW (umsg_decl) = 0;
      TREE_NOTHROW (umsg_nonnil_decl) = 0;
      TREE_NOTHROW (umsg_nonnil_decl) = 0;
      TREE_NOTHROW (umsg_stret_decl) = 0;
      TREE_NOTHROW (umsg_stret_decl) = 0;
      TREE_NOTHROW (umsg_nonnil_stret_decl) = 0;
      TREE_NOTHROW (umsg_nonnil_stret_decl) = 0;
 
 
      /* id objc_msgSend_Fast (id, SEL, ...)
      /* id objc_msgSend_Fast (id, SEL, ...)
           __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */
           __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */
#ifdef OFFS_MSGSEND_FAST
#ifdef OFFS_MSGSEND_FAST
      umsg_fast_decl = add_builtin_function (TAG_MSGSEND_FAST,
      umsg_fast_decl = add_builtin_function (TAG_MSGSEND_FAST,
                                             type, 0, NOT_BUILT_IN,
                                             type, 0, NOT_BUILT_IN,
                                             NULL, NULL_TREE);
                                             NULL, NULL_TREE);
      TREE_NOTHROW (umsg_fast_decl) = 0;
      TREE_NOTHROW (umsg_fast_decl) = 0;
      DECL_ATTRIBUTES (umsg_fast_decl)
      DECL_ATTRIBUTES (umsg_fast_decl)
        = tree_cons (get_identifier ("hard_coded_address"),
        = tree_cons (get_identifier ("hard_coded_address"),
                     build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST),
                     build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST),
                     NULL_TREE);
                     NULL_TREE);
#else
#else
      /* No direct dispatch available.  */
      /* No direct dispatch available.  */
      umsg_fast_decl = umsg_decl;
      umsg_fast_decl = umsg_decl;
#endif
#endif
 
 
      /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
      /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
      /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */
      /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */
      type
      type
        = build_function_type (objc_object_type,
        = build_function_type (objc_object_type,
                               tree_cons (NULL_TREE, objc_super_type,
                               tree_cons (NULL_TREE, objc_super_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                                     NULL_TREE)));
                                                     NULL_TREE)));
      umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER,
      umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER,
                                              type, 0, NOT_BUILT_IN,
                                              type, 0, NOT_BUILT_IN,
                                              NULL, NULL_TREE);
                                              NULL, NULL_TREE);
      umsg_super_stret_decl = add_builtin_function (TAG_MSGSENDSUPER_STRET,
      umsg_super_stret_decl = add_builtin_function (TAG_MSGSENDSUPER_STRET,
                                                    type, 0, NOT_BUILT_IN, 0,
                                                    type, 0, NOT_BUILT_IN, 0,
                                                    NULL_TREE);
                                                    NULL_TREE);
      TREE_NOTHROW (umsg_super_decl) = 0;
      TREE_NOTHROW (umsg_super_decl) = 0;
      TREE_NOTHROW (umsg_super_stret_decl) = 0;
      TREE_NOTHROW (umsg_super_stret_decl) = 0;
    }
    }
  else
  else
    {
    {
      /* GNU runtime messenger entry points.  */
      /* GNU runtime messenger entry points.  */
 
 
      /* typedef id (*IMP)(id, SEL, ...); */
      /* typedef id (*IMP)(id, SEL, ...); */
      tree IMP_type
      tree IMP_type
        = build_pointer_type
        = build_pointer_type
          (build_function_type (objc_object_type,
          (build_function_type (objc_object_type,
                                tree_cons (NULL_TREE, objc_object_type,
                                tree_cons (NULL_TREE, objc_object_type,
                                           tree_cons (NULL_TREE, objc_selector_type,
                                           tree_cons (NULL_TREE, objc_selector_type,
                                                      NULL_TREE))));
                                                      NULL_TREE))));
 
 
      /* IMP objc_msg_lookup (id, SEL); */
      /* IMP objc_msg_lookup (id, SEL); */
      type
      type
        = build_function_type (IMP_type,
        = build_function_type (IMP_type,
                               tree_cons (NULL_TREE, objc_object_type,
                               tree_cons (NULL_TREE, objc_object_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                                     OBJC_VOID_AT_END)));
                                                     OBJC_VOID_AT_END)));
      umsg_decl = add_builtin_function (TAG_MSGSEND,
      umsg_decl = add_builtin_function (TAG_MSGSEND,
                                        type, 0, NOT_BUILT_IN,
                                        type, 0, NOT_BUILT_IN,
                                        NULL, NULL_TREE);
                                        NULL, NULL_TREE);
      TREE_NOTHROW (umsg_decl) = 0;
      TREE_NOTHROW (umsg_decl) = 0;
 
 
      /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */
      /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */
      type
      type
        = build_function_type (IMP_type,
        = build_function_type (IMP_type,
                               tree_cons (NULL_TREE, objc_super_type,
                               tree_cons (NULL_TREE, objc_super_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                          tree_cons (NULL_TREE, objc_selector_type,
                                                     OBJC_VOID_AT_END)));
                                                     OBJC_VOID_AT_END)));
      umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER,
      umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER,
                                              type, 0, NOT_BUILT_IN,
                                              type, 0, NOT_BUILT_IN,
                                              NULL, NULL_TREE);
                                              NULL, NULL_TREE);
      TREE_NOTHROW (umsg_super_decl) = 0;
      TREE_NOTHROW (umsg_super_decl) = 0;
 
 
      /* The following GNU runtime entry point is called to initialize
      /* The following GNU runtime entry point is called to initialize
         each module:
         each module:
 
 
         __objc_exec_class (void *); */
         __objc_exec_class (void *); */
      type
      type
        = build_function_type (void_type_node,
        = build_function_type (void_type_node,
                               tree_cons (NULL_TREE, ptr_type_node,
                               tree_cons (NULL_TREE, ptr_type_node,
                                          OBJC_VOID_AT_END));
                                          OBJC_VOID_AT_END));
      execclass_decl = add_builtin_function (TAG_EXECCLASS,
      execclass_decl = add_builtin_function (TAG_EXECCLASS,
                                             type, 0, NOT_BUILT_IN,
                                             type, 0, NOT_BUILT_IN,
                                             NULL, NULL_TREE);
                                             NULL, NULL_TREE);
    }
    }
 
 
  /* id objc_getClass (const char *); */
  /* id objc_getClass (const char *); */
 
 
  type = build_function_type (objc_object_type,
  type = build_function_type (objc_object_type,
                                   tree_cons (NULL_TREE,
                                   tree_cons (NULL_TREE,
                                              const_string_type_node,
                                              const_string_type_node,
                                              OBJC_VOID_AT_END));
                                              OBJC_VOID_AT_END));
 
 
  objc_get_class_decl
  objc_get_class_decl
    = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN,
    = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN,
                            NULL, NULL_TREE);
                            NULL, NULL_TREE);
 
 
  /* id objc_getMetaClass (const char *); */
  /* id objc_getMetaClass (const char *); */
 
 
  objc_get_meta_class_decl
  objc_get_meta_class_decl
    = add_builtin_function (TAG_GETMETACLASS, type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
    = add_builtin_function (TAG_GETMETACLASS, type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
 
 
  build_class_template ();
  build_class_template ();
  build_super_template ();
  build_super_template ();
  build_protocol_template ();
  build_protocol_template ();
  build_category_template ();
  build_category_template ();
  build_objc_exception_stuff ();
  build_objc_exception_stuff ();
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    build_next_objc_exception_stuff ();
    build_next_objc_exception_stuff ();
 
 
  /* static SEL _OBJC_SELECTOR_TABLE[]; */
  /* static SEL _OBJC_SELECTOR_TABLE[]; */
 
 
  if (! flag_next_runtime)
  if (! flag_next_runtime)
    build_selector_table_decl ();
    build_selector_table_decl ();
 
 
  /* Forward declare constant_string_id and constant_string_type.  */
  /* Forward declare constant_string_id and constant_string_type.  */
  if (!constant_string_class_name)
  if (!constant_string_class_name)
    constant_string_class_name = default_constant_string_class_name;
    constant_string_class_name = default_constant_string_class_name;
 
 
  constant_string_id = get_identifier (constant_string_class_name);
  constant_string_id = get_identifier (constant_string_class_name);
  objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE));
  objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE));
 
 
  /* Pre-build the following entities - for speed/convenience.  */
  /* Pre-build the following entities - for speed/convenience.  */
  self_id = get_identifier ("self");
  self_id = get_identifier ("self");
  ucmd_id = get_identifier ("_cmd");
  ucmd_id = get_identifier ("_cmd");
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  pop_lang_context ();
  pop_lang_context ();
#endif
#endif
 
 
  write_symbols = save_write_symbols;
  write_symbols = save_write_symbols;
  debug_hooks = save_hooks;
  debug_hooks = save_hooks;
}
}
 
 
/* Ensure that the ivar list for NSConstantString/NXConstantString
/* Ensure that the ivar list for NSConstantString/NXConstantString
   (or whatever was specified via `-fconstant-string-class')
   (or whatever was specified via `-fconstant-string-class')
   contains fields at least as large as the following three, so that
   contains fields at least as large as the following three, so that
   the runtime can stomp on them with confidence:
   the runtime can stomp on them with confidence:
 
 
   struct STRING_OBJECT_CLASS_NAME
   struct STRING_OBJECT_CLASS_NAME
   {
   {
     Object isa;
     Object isa;
     char *cString;
     char *cString;
     unsigned int length;
     unsigned int length;
   }; */
   }; */
 
 
static int
static int
check_string_class_template (void)
check_string_class_template (void)
{
{
  tree field_decl = objc_get_class_ivars (constant_string_id);
  tree field_decl = objc_get_class_ivars (constant_string_id);
 
 
#define AT_LEAST_AS_LARGE_AS(F, T) \
#define AT_LEAST_AS_LARGE_AS(F, T) \
  (F && TREE_CODE (F) == FIELD_DECL \
  (F && TREE_CODE (F) == FIELD_DECL \
     && (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (F))) \
     && (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (F))) \
         >= TREE_INT_CST_LOW (TYPE_SIZE (T))))
         >= TREE_INT_CST_LOW (TYPE_SIZE (T))))
 
 
  if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node))
  if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node))
    return 0;
    return 0;
 
 
  field_decl = TREE_CHAIN (field_decl);
  field_decl = TREE_CHAIN (field_decl);
  if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node))
  if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node))
    return 0;
    return 0;
 
 
  field_decl = TREE_CHAIN (field_decl);
  field_decl = TREE_CHAIN (field_decl);
  return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node);
  return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node);
 
 
#undef AT_LEAST_AS_LARGE_AS
#undef AT_LEAST_AS_LARGE_AS
}
}
 
 
/* Avoid calling `check_string_class_template ()' more than once.  */
/* Avoid calling `check_string_class_template ()' more than once.  */
static GTY(()) int string_layout_checked;
static GTY(()) int string_layout_checked;
 
 
/* Construct an internal string layout to be used as a template for
/* Construct an internal string layout to be used as a template for
   creating NSConstantString/NXConstantString instances.  */
   creating NSConstantString/NXConstantString instances.  */
 
 
static tree
static tree
objc_build_internal_const_str_type (void)
objc_build_internal_const_str_type (void)
{
{
  tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
  tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
  tree fields = build_decl (input_location,
  tree fields = build_decl (input_location,
                            FIELD_DECL, NULL_TREE, ptr_type_node);
                            FIELD_DECL, NULL_TREE, ptr_type_node);
  tree field = build_decl (input_location,
  tree field = build_decl (input_location,
                           FIELD_DECL, NULL_TREE, ptr_type_node);
                           FIELD_DECL, NULL_TREE, ptr_type_node);
 
 
  TREE_CHAIN (field) = fields; fields = field;
  TREE_CHAIN (field) = fields; fields = field;
  field = build_decl (input_location,
  field = build_decl (input_location,
                      FIELD_DECL, NULL_TREE, unsigned_type_node);
                      FIELD_DECL, NULL_TREE, unsigned_type_node);
  TREE_CHAIN (field) = fields; fields = field;
  TREE_CHAIN (field) = fields; fields = field;
  /* NB: The finish_builtin_struct() routine expects FIELD_DECLs in
  /* NB: The finish_builtin_struct() routine expects FIELD_DECLs in
     reverse order!  */
     reverse order!  */
  finish_builtin_struct (type, "__builtin_ObjCString",
  finish_builtin_struct (type, "__builtin_ObjCString",
                         fields, NULL_TREE);
                         fields, NULL_TREE);
 
 
  return type;
  return type;
}
}
 
 
/* Custom build_string which sets TREE_TYPE!  */
/* Custom build_string which sets TREE_TYPE!  */
 
 
static tree
static tree
my_build_string (int len, const char *str)
my_build_string (int len, const char *str)
{
{
  return fix_string_type (build_string (len, str));
  return fix_string_type (build_string (len, str));
}
}
 
 
/* Build a string with contents STR and length LEN and convert it to a
/* Build a string with contents STR and length LEN and convert it to a
   pointer.  */
   pointer.  */
 
 
static tree
static tree
my_build_string_pointer (int len, const char *str)
my_build_string_pointer (int len, const char *str)
{
{
  tree string = my_build_string (len, str);
  tree string = my_build_string (len, str);
  tree ptrtype = build_pointer_type (TREE_TYPE (TREE_TYPE (string)));
  tree ptrtype = build_pointer_type (TREE_TYPE (TREE_TYPE (string)));
  return build1 (ADDR_EXPR, ptrtype, string);
  return build1 (ADDR_EXPR, ptrtype, string);
}
}
 
 
static hashval_t
static hashval_t
string_hash (const void *ptr)
string_hash (const void *ptr)
{
{
  const_tree const str = ((const struct string_descriptor *)ptr)->literal;
  const_tree const str = ((const struct string_descriptor *)ptr)->literal;
  const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str);
  const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str);
  int i, len = TREE_STRING_LENGTH (str);
  int i, len = TREE_STRING_LENGTH (str);
  hashval_t h = len;
  hashval_t h = len;
 
 
  for (i = 0; i < len; i++)
  for (i = 0; i < len; i++)
    h = ((h * 613) + p[i]);
    h = ((h * 613) + p[i]);
 
 
  return h;
  return h;
}
}
 
 
static int
static int
string_eq (const void *ptr1, const void *ptr2)
string_eq (const void *ptr1, const void *ptr2)
{
{
  const_tree const str1 = ((const struct string_descriptor *)ptr1)->literal;
  const_tree const str1 = ((const struct string_descriptor *)ptr1)->literal;
  const_tree const str2 = ((const struct string_descriptor *)ptr2)->literal;
  const_tree const str2 = ((const struct string_descriptor *)ptr2)->literal;
  int len1 = TREE_STRING_LENGTH (str1);
  int len1 = TREE_STRING_LENGTH (str1);
 
 
  return (len1 == TREE_STRING_LENGTH (str2)
  return (len1 == TREE_STRING_LENGTH (str2)
          && !memcmp (TREE_STRING_POINTER (str1), TREE_STRING_POINTER (str2),
          && !memcmp (TREE_STRING_POINTER (str1), TREE_STRING_POINTER (str2),
                      len1));
                      len1));
}
}
 
 
/* Given a chain of STRING_CST's, build a static instance of
/* Given a chain of STRING_CST's, build a static instance of
   NXConstantString which points at the concatenation of those
   NXConstantString which points at the concatenation of those
   strings.  We place the string object in the __string_objects
   strings.  We place the string object in the __string_objects
   section of the __OBJC segment.  The Objective-C runtime will
   section of the __OBJC segment.  The Objective-C runtime will
   initialize the isa pointers of the string objects to point at the
   initialize the isa pointers of the string objects to point at the
   NXConstantString class object.  */
   NXConstantString class object.  */
 
 
tree
tree
objc_build_string_object (tree string)
objc_build_string_object (tree string)
{
{
  tree initlist, constructor, constant_string_class;
  tree initlist, constructor, constant_string_class;
  int length;
  int length;
  tree fields, addr;
  tree fields, addr;
  struct string_descriptor *desc, key;
  struct string_descriptor *desc, key;
  void **loc;
  void **loc;
 
 
  /* Prep the string argument.  */
  /* Prep the string argument.  */
  string = fix_string_type (string);
  string = fix_string_type (string);
  TREE_SET_CODE (string, STRING_CST);
  TREE_SET_CODE (string, STRING_CST);
  length = TREE_STRING_LENGTH (string) - 1;
  length = TREE_STRING_LENGTH (string) - 1;
 
 
  /* Check whether the string class being used actually exists and has the
  /* Check whether the string class being used actually exists and has the
     correct ivar layout.  */
     correct ivar layout.  */
  if (!string_layout_checked)
  if (!string_layout_checked)
    {
    {
      string_layout_checked = -1;
      string_layout_checked = -1;
      constant_string_class = lookup_interface (constant_string_id);
      constant_string_class = lookup_interface (constant_string_id);
      internal_const_str_type = objc_build_internal_const_str_type ();
      internal_const_str_type = objc_build_internal_const_str_type ();
 
 
      if (!constant_string_class
      if (!constant_string_class
          || !(constant_string_type
          || !(constant_string_type
               = CLASS_STATIC_TEMPLATE (constant_string_class)))
               = CLASS_STATIC_TEMPLATE (constant_string_class)))
        error ("cannot find interface declaration for %qE",
        error ("cannot find interface declaration for %qE",
               constant_string_id);
               constant_string_id);
      /* The NSConstantString/NXConstantString ivar layout is now known.  */
      /* The NSConstantString/NXConstantString ivar layout is now known.  */
      else if (!check_string_class_template ())
      else if (!check_string_class_template ())
        error ("interface %qE does not have valid constant string layout",
        error ("interface %qE does not have valid constant string layout",
               constant_string_id);
               constant_string_id);
      /* For the NeXT runtime, we can generate a literal reference
      /* For the NeXT runtime, we can generate a literal reference
         to the string class, don't need to run a constructor.  */
         to the string class, don't need to run a constructor.  */
      else if (flag_next_runtime && !setup_string_decl ())
      else if (flag_next_runtime && !setup_string_decl ())
        error ("cannot find reference tag for class %qE",
        error ("cannot find reference tag for class %qE",
               constant_string_id);
               constant_string_id);
      else
      else
        {
        {
          string_layout_checked = 1;  /* Success!  */
          string_layout_checked = 1;  /* Success!  */
          add_class_reference (constant_string_id);
          add_class_reference (constant_string_id);
        }
        }
    }
    }
 
 
  if (string_layout_checked == -1)
  if (string_layout_checked == -1)
    return error_mark_node;
    return error_mark_node;
 
 
  /* Perhaps we already constructed a constant string just like this one? */
  /* Perhaps we already constructed a constant string just like this one? */
  key.literal = string;
  key.literal = string;
  loc = htab_find_slot (string_htab, &key, INSERT);
  loc = htab_find_slot (string_htab, &key, INSERT);
  desc = (struct string_descriptor *) *loc;
  desc = (struct string_descriptor *) *loc;
 
 
  if (!desc)
  if (!desc)
    {
    {
      tree var;
      tree var;
      *loc = desc = GGC_NEW (struct string_descriptor);
      *loc = desc = GGC_NEW (struct string_descriptor);
      desc->literal = string;
      desc->literal = string;
 
 
      /* GNU:    (NXConstantString *) & ((__builtin_ObjCString) { NULL, string, length })  */
      /* GNU:    (NXConstantString *) & ((__builtin_ObjCString) { NULL, string, length })  */
      /* NeXT:   (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length })   */
      /* NeXT:   (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length })   */
      fields = TYPE_FIELDS (internal_const_str_type);
      fields = TYPE_FIELDS (internal_const_str_type);
      initlist
      initlist
        = build_tree_list (fields,
        = build_tree_list (fields,
                           flag_next_runtime
                           flag_next_runtime
                           ? build_unary_op (input_location,
                           ? build_unary_op (input_location,
                                             ADDR_EXPR, string_class_decl, 0)
                                             ADDR_EXPR, string_class_decl, 0)
                           : build_int_cst (NULL_TREE, 0));
                           : build_int_cst (NULL_TREE, 0));
      fields = TREE_CHAIN (fields);
      fields = TREE_CHAIN (fields);
      initlist = tree_cons (fields, build_unary_op (input_location,
      initlist = tree_cons (fields, build_unary_op (input_location,
                                                    ADDR_EXPR, string, 1),
                                                    ADDR_EXPR, string, 1),
                            initlist);
                            initlist);
      fields = TREE_CHAIN (fields);
      fields = TREE_CHAIN (fields);
      initlist = tree_cons (fields, build_int_cst (NULL_TREE, length),
      initlist = tree_cons (fields, build_int_cst (NULL_TREE, length),
                            initlist);
                            initlist);
      constructor = objc_build_constructor (internal_const_str_type,
      constructor = objc_build_constructor (internal_const_str_type,
                                            nreverse (initlist));
                                            nreverse (initlist));
 
 
      if (!flag_next_runtime)
      if (!flag_next_runtime)
        constructor
        constructor
          = objc_add_static_instance (constructor, constant_string_type);
          = objc_add_static_instance (constructor, constant_string_type);
      else
      else
        {
        {
          var = build_decl (input_location,
          var = build_decl (input_location,
                            CONST_DECL, NULL, TREE_TYPE (constructor));
                            CONST_DECL, NULL, TREE_TYPE (constructor));
          DECL_INITIAL (var) = constructor;
          DECL_INITIAL (var) = constructor;
          TREE_STATIC (var) = 1;
          TREE_STATIC (var) = 1;
          pushdecl_top_level (var);
          pushdecl_top_level (var);
          constructor = var;
          constructor = var;
        }
        }
      desc->constructor = constructor;
      desc->constructor = constructor;
    }
    }
 
 
  addr = convert (build_pointer_type (constant_string_type),
  addr = convert (build_pointer_type (constant_string_type),
                  build_unary_op (input_location,
                  build_unary_op (input_location,
                                  ADDR_EXPR, desc->constructor, 1));
                                  ADDR_EXPR, desc->constructor, 1));
 
 
  return addr;
  return addr;
}
}
 
 
/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR.  */
/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR.  */
 
 
static GTY(()) int num_static_inst;
static GTY(()) int num_static_inst;
 
 
static tree
static tree
objc_add_static_instance (tree constructor, tree class_decl)
objc_add_static_instance (tree constructor, tree class_decl)
{
{
  tree *chain, decl;
  tree *chain, decl;
  char buf[256];
  char buf[256];
 
 
  /* Find the list of static instances for the CLASS_DECL.  Create one if
  /* Find the list of static instances for the CLASS_DECL.  Create one if
     not found.  */
     not found.  */
  for (chain = &objc_static_instances;
  for (chain = &objc_static_instances;
       *chain && TREE_VALUE (*chain) != class_decl;
       *chain && TREE_VALUE (*chain) != class_decl;
       chain = &TREE_CHAIN (*chain));
       chain = &TREE_CHAIN (*chain));
  if (!*chain)
  if (!*chain)
    {
    {
      *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE);
      *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE);
      add_objc_string (OBJC_TYPE_NAME (class_decl), class_names);
      add_objc_string (OBJC_TYPE_NAME (class_decl), class_names);
    }
    }
 
 
  sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++);
  sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++);
  decl = build_decl (input_location,
  decl = build_decl (input_location,
                     VAR_DECL, get_identifier (buf), class_decl);
                     VAR_DECL, get_identifier (buf), class_decl);
  TREE_STATIC (decl) = 1;
  TREE_STATIC (decl) = 1;
  DECL_ARTIFICIAL (decl) = 1;
  DECL_ARTIFICIAL (decl) = 1;
  TREE_USED (decl) = 1;
  TREE_USED (decl) = 1;
  DECL_INITIAL (decl) = constructor;
  DECL_INITIAL (decl) = constructor;
 
 
  /* We may be writing something else just now.
  /* We may be writing something else just now.
     Postpone till end of input.  */
     Postpone till end of input.  */
  DECL_DEFER_OUTPUT (decl) = 1;
  DECL_DEFER_OUTPUT (decl) = 1;
  pushdecl_top_level (decl);
  pushdecl_top_level (decl);
  rest_of_decl_compilation (decl, 1, 0);
  rest_of_decl_compilation (decl, 1, 0);
 
 
  /* Add the DECL to the head of this CLASS' list.  */
  /* Add the DECL to the head of this CLASS' list.  */
  TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain));
  TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain));
 
 
  return decl;
  return decl;
}
}
 
 
/* Build a static constant CONSTRUCTOR
/* Build a static constant CONSTRUCTOR
   with type TYPE and elements ELTS.  */
   with type TYPE and elements ELTS.  */
 
 
static tree
static tree
objc_build_constructor (tree type, tree elts)
objc_build_constructor (tree type, tree elts)
{
{
  tree constructor = build_constructor_from_list (type, elts);
  tree constructor = build_constructor_from_list (type, elts);
 
 
  TREE_CONSTANT (constructor) = 1;
  TREE_CONSTANT (constructor) = 1;
  TREE_STATIC (constructor) = 1;
  TREE_STATIC (constructor) = 1;
  TREE_READONLY (constructor) = 1;
  TREE_READONLY (constructor) = 1;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  /* Adjust for impedance mismatch.  We should figure out how to build
  /* Adjust for impedance mismatch.  We should figure out how to build
     CONSTRUCTORs that consistently please both the C and C++ gods.  */
     CONSTRUCTORs that consistently please both the C and C++ gods.  */
  if (!TREE_PURPOSE (elts))
  if (!TREE_PURPOSE (elts))
    TREE_TYPE (constructor) = init_list_type_node;
    TREE_TYPE (constructor) = init_list_type_node;
#endif
#endif
 
 
  return constructor;
  return constructor;
}
}


/* Take care of defining and initializing _OBJC_SYMBOLS.  */
/* Take care of defining and initializing _OBJC_SYMBOLS.  */
 
 
/* Predefine the following data type:
/* Predefine the following data type:
 
 
   struct _objc_symtab
   struct _objc_symtab
   {
   {
     long sel_ref_cnt;
     long sel_ref_cnt;
     SEL *refs;
     SEL *refs;
     short cls_def_cnt;
     short cls_def_cnt;
     short cat_def_cnt;
     short cat_def_cnt;
     void *defs[cls_def_cnt + cat_def_cnt];
     void *defs[cls_def_cnt + cat_def_cnt];
   }; */
   }; */
 
 
static void
static void
build_objc_symtab_template (void)
build_objc_symtab_template (void)
{
{
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB));
  objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB));
 
 
  /* long sel_ref_cnt; */
  /* long sel_ref_cnt; */
  field_decl = create_field_decl (long_integer_type_node, "sel_ref_cnt");
  field_decl = create_field_decl (long_integer_type_node, "sel_ref_cnt");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* SEL *refs; */
  /* SEL *refs; */
  field_decl = create_field_decl (build_pointer_type (objc_selector_type),
  field_decl = create_field_decl (build_pointer_type (objc_selector_type),
                                  "refs");
                                  "refs");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* short cls_def_cnt; */
  /* short cls_def_cnt; */
  field_decl = create_field_decl (short_integer_type_node, "cls_def_cnt");
  field_decl = create_field_decl (short_integer_type_node, "cls_def_cnt");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* short cat_def_cnt; */
  /* short cat_def_cnt; */
  field_decl = create_field_decl (short_integer_type_node,
  field_decl = create_field_decl (short_integer_type_node,
                                  "cat_def_cnt");
                                  "cat_def_cnt");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  if (imp_count || cat_count || !flag_next_runtime)
  if (imp_count || cat_count || !flag_next_runtime)
    {
    {
      /* void *defs[imp_count + cat_count (+ 1)]; */
      /* void *defs[imp_count + cat_count (+ 1)]; */
      /* NB: The index is one less than the size of the array.  */
      /* NB: The index is one less than the size of the array.  */
      int index = imp_count + cat_count
      int index = imp_count + cat_count
                + (flag_next_runtime? -1: 0);
                + (flag_next_runtime? -1: 0);
      field_decl = create_field_decl
      field_decl = create_field_decl
                   (build_array_type
                   (build_array_type
                    (ptr_type_node,
                    (ptr_type_node,
                     build_index_type (build_int_cst (NULL_TREE, index))),
                     build_index_type (build_int_cst (NULL_TREE, index))),
                    "defs");
                    "defs");
      chainon (field_decl_chain, field_decl);
      chainon (field_decl_chain, field_decl);
    }
    }
 
 
  objc_finish_struct (objc_symtab_template, field_decl_chain);
  objc_finish_struct (objc_symtab_template, field_decl_chain);
}
}
 
 
/* Create the initial value for the `defs' field of _objc_symtab.
/* Create the initial value for the `defs' field of _objc_symtab.
   This is a CONSTRUCTOR.  */
   This is a CONSTRUCTOR.  */
 
 
static tree
static tree
init_def_list (tree type)
init_def_list (tree type)
{
{
  tree expr, initlist = NULL_TREE;
  tree expr, initlist = NULL_TREE;
  struct imp_entry *impent;
  struct imp_entry *impent;
 
 
  if (imp_count)
  if (imp_count)
    for (impent = imp_list; impent; impent = impent->next)
    for (impent = imp_list; impent; impent = impent->next)
      {
      {
        if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE)
        if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE)
          {
          {
            expr = build_unary_op (input_location,
            expr = build_unary_op (input_location,
                                   ADDR_EXPR, impent->class_decl, 0);
                                   ADDR_EXPR, impent->class_decl, 0);
            initlist = tree_cons (NULL_TREE, expr, initlist);
            initlist = tree_cons (NULL_TREE, expr, initlist);
          }
          }
      }
      }
 
 
  if (cat_count)
  if (cat_count)
    for (impent = imp_list; impent; impent = impent->next)
    for (impent = imp_list; impent; impent = impent->next)
      {
      {
        if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
        if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
          {
          {
            expr = build_unary_op (input_location,
            expr = build_unary_op (input_location,
                                   ADDR_EXPR, impent->class_decl, 0);
                                   ADDR_EXPR, impent->class_decl, 0);
            initlist = tree_cons (NULL_TREE, expr, initlist);
            initlist = tree_cons (NULL_TREE, expr, initlist);
          }
          }
      }
      }
 
 
  if (!flag_next_runtime)
  if (!flag_next_runtime)
    {
    {
      /* statics = { ..., _OBJC_STATIC_INSTANCES, ... }  */
      /* statics = { ..., _OBJC_STATIC_INSTANCES, ... }  */
      tree expr;
      tree expr;
 
 
      if (static_instances_decl)
      if (static_instances_decl)
        expr = build_unary_op (input_location,
        expr = build_unary_op (input_location,
                               ADDR_EXPR, static_instances_decl, 0);
                               ADDR_EXPR, static_instances_decl, 0);
      else
      else
        expr = build_int_cst (NULL_TREE, 0);
        expr = build_int_cst (NULL_TREE, 0);
 
 
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  return objc_build_constructor (type, nreverse (initlist));
  return objc_build_constructor (type, nreverse (initlist));
}
}
 
 
/* Construct the initial value for all of _objc_symtab.  */
/* Construct the initial value for all of _objc_symtab.  */
 
 
static tree
static tree
init_objc_symtab (tree type)
init_objc_symtab (tree type)
{
{
  tree initlist;
  tree initlist;
 
 
  /* sel_ref_cnt = { ..., 5, ... } */
  /* sel_ref_cnt = { ..., 5, ... } */
 
 
  initlist = build_tree_list (NULL_TREE,
  initlist = build_tree_list (NULL_TREE,
                              build_int_cst (long_integer_type_node, 0));
                              build_int_cst (long_integer_type_node, 0));
 
 
  /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
  /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
 
 
  if (flag_next_runtime || ! sel_ref_chain)
  if (flag_next_runtime || ! sel_ref_chain)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    initlist
    initlist
      = tree_cons (NULL_TREE,
      = tree_cons (NULL_TREE,
                   convert (build_pointer_type (objc_selector_type),
                   convert (build_pointer_type (objc_selector_type),
                            build_unary_op (input_location, ADDR_EXPR,
                            build_unary_op (input_location, ADDR_EXPR,
                                            UOBJC_SELECTOR_TABLE_decl, 1)),
                                            UOBJC_SELECTOR_TABLE_decl, 1)),
                   initlist);
                   initlist);
 
 
  /* cls_def_cnt = { ..., 5, ... } */
  /* cls_def_cnt = { ..., 5, ... } */
 
 
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, imp_count), initlist);
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, imp_count), initlist);
 
 
  /* cat_def_cnt = { ..., 5, ... } */
  /* cat_def_cnt = { ..., 5, ... } */
 
 
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, cat_count), initlist);
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, cat_count), initlist);
 
 
  /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
  /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
 
 
  if (imp_count || cat_count || !flag_next_runtime)
  if (imp_count || cat_count || !flag_next_runtime)
    {
    {
 
 
      tree field = TYPE_FIELDS (type);
      tree field = TYPE_FIELDS (type);
      field = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (field))));
      field = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (field))));
 
 
      initlist = tree_cons (NULL_TREE, init_def_list (TREE_TYPE (field)),
      initlist = tree_cons (NULL_TREE, init_def_list (TREE_TYPE (field)),
                            initlist);
                            initlist);
    }
    }
 
 
  return objc_build_constructor (type, nreverse (initlist));
  return objc_build_constructor (type, nreverse (initlist));
}
}
 
 
/* Generate forward declarations for metadata such as
/* Generate forward declarations for metadata such as
  'OBJC_CLASS_...'.  */
  'OBJC_CLASS_...'.  */
 
 
static tree
static tree
build_metadata_decl (const char *name, tree type)
build_metadata_decl (const char *name, tree type)
{
{
  tree decl;
  tree decl;
 
 
  /* struct TYPE NAME_<name>; */
  /* struct TYPE NAME_<name>; */
  decl = start_var_decl (type, synth_id_with_class_suffix
  decl = start_var_decl (type, synth_id_with_class_suffix
                               (name,
                               (name,
                                objc_implementation_context));
                                objc_implementation_context));
 
 
  return decl;
  return decl;
}
}
 
 
/* Push forward-declarations of all the categories so that
/* Push forward-declarations of all the categories so that
   init_def_list can use them in a CONSTRUCTOR.  */
   init_def_list can use them in a CONSTRUCTOR.  */
 
 
static void
static void
forward_declare_categories (void)
forward_declare_categories (void)
{
{
  struct imp_entry *impent;
  struct imp_entry *impent;
  tree sav = objc_implementation_context;
  tree sav = objc_implementation_context;
 
 
  for (impent = imp_list; impent; impent = impent->next)
  for (impent = imp_list; impent; impent = impent->next)
    {
    {
      if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
      if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
        {
        {
          /* Set an invisible arg to synth_id_with_class_suffix.  */
          /* Set an invisible arg to synth_id_with_class_suffix.  */
          objc_implementation_context = impent->imp_context;
          objc_implementation_context = impent->imp_context;
          /* extern struct objc_category _OBJC_CATEGORY_<name>; */
          /* extern struct objc_category _OBJC_CATEGORY_<name>; */
          impent->class_decl = build_metadata_decl ("_OBJC_CATEGORY",
          impent->class_decl = build_metadata_decl ("_OBJC_CATEGORY",
                                                    objc_category_template);
                                                    objc_category_template);
        }
        }
    }
    }
  objc_implementation_context = sav;
  objc_implementation_context = sav;
}
}
 
 
/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab'
/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab'
   and initialized appropriately.  */
   and initialized appropriately.  */
 
 
static void
static void
generate_objc_symtab_decl (void)
generate_objc_symtab_decl (void)
{
{
  /* forward declare categories */
  /* forward declare categories */
  if (cat_count)
  if (cat_count)
    forward_declare_categories ();
    forward_declare_categories ();
 
 
  build_objc_symtab_template ();
  build_objc_symtab_template ();
  UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS");
  UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS");
  finish_var_decl (UOBJC_SYMBOLS_decl,
  finish_var_decl (UOBJC_SYMBOLS_decl,
                   init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)));
                   init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)));
}
}


static tree
static tree
init_module_descriptor (tree type)
init_module_descriptor (tree type)
{
{
  tree initlist, expr;
  tree initlist, expr;
 
 
  /* version = { 1, ... } */
  /* version = { 1, ... } */
 
 
  expr = build_int_cst (long_integer_type_node, OBJC_VERSION);
  expr = build_int_cst (long_integer_type_node, OBJC_VERSION);
  initlist = build_tree_list (NULL_TREE, expr);
  initlist = build_tree_list (NULL_TREE, expr);
 
 
  /* size = { ..., sizeof (struct _objc_module), ... } */
  /* size = { ..., sizeof (struct _objc_module), ... } */
 
 
  expr = convert (long_integer_type_node,
  expr = convert (long_integer_type_node,
                  size_in_bytes (objc_module_template));
                  size_in_bytes (objc_module_template));
  initlist = tree_cons (NULL_TREE, expr, initlist);
  initlist = tree_cons (NULL_TREE, expr, initlist);
 
 
  /* Don't provide any file name for security reasons. */
  /* Don't provide any file name for security reasons. */
  /* name = { ..., "", ... } */
  /* name = { ..., "", ... } */
 
 
  expr = add_objc_string (get_identifier (""), class_names);
  expr = add_objc_string (get_identifier (""), class_names);
  initlist = tree_cons (NULL_TREE, expr, initlist);
  initlist = tree_cons (NULL_TREE, expr, initlist);
 
 
  /* symtab = { ..., _OBJC_SYMBOLS, ... } */
  /* symtab = { ..., _OBJC_SYMBOLS, ... } */
 
 
  if (UOBJC_SYMBOLS_decl)
  if (UOBJC_SYMBOLS_decl)
    expr = build_unary_op (input_location,
    expr = build_unary_op (input_location,
                           ADDR_EXPR, UOBJC_SYMBOLS_decl, 0);
                           ADDR_EXPR, UOBJC_SYMBOLS_decl, 0);
  else
  else
    expr = build_int_cst (NULL_TREE, 0);
    expr = build_int_cst (NULL_TREE, 0);
  initlist = tree_cons (NULL_TREE, expr, initlist);
  initlist = tree_cons (NULL_TREE, expr, initlist);
 
 
  return objc_build_constructor (type, nreverse (initlist));
  return objc_build_constructor (type, nreverse (initlist));
}
}
 
 
/* Write out the data structures to describe Objective C classes defined.
/* Write out the data structures to describe Objective C classes defined.
 
 
   struct _objc_module { ... } _OBJC_MODULE = { ... };   */
   struct _objc_module { ... } _OBJC_MODULE = { ... };   */
 
 
static void
static void
build_module_descriptor (void)
build_module_descriptor (void)
{
{
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  push_lang_context (lang_name_c); /* extern "C" */
  push_lang_context (lang_name_c); /* extern "C" */
#endif
#endif
 
 
  objc_module_template = objc_start_struct (get_identifier (UTAG_MODULE));
  objc_module_template = objc_start_struct (get_identifier (UTAG_MODULE));
 
 
  /* long version; */
  /* long version; */
  field_decl = create_field_decl (long_integer_type_node, "version");
  field_decl = create_field_decl (long_integer_type_node, "version");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* long size; */
  /* long size; */
  field_decl = create_field_decl (long_integer_type_node, "size");
  field_decl = create_field_decl (long_integer_type_node, "size");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* char *name; */
  /* char *name; */
  field_decl = create_field_decl (string_type_node, "name");
  field_decl = create_field_decl (string_type_node, "name");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc_symtab *symtab; */
  /* struct _objc_symtab *symtab; */
  field_decl
  field_decl
    = create_field_decl (build_pointer_type
    = create_field_decl (build_pointer_type
                         (xref_tag (RECORD_TYPE,
                         (xref_tag (RECORD_TYPE,
                                    get_identifier (UTAG_SYMTAB))),
                                    get_identifier (UTAG_SYMTAB))),
                         "symtab");
                         "symtab");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_module_template, field_decl_chain);
  objc_finish_struct (objc_module_template, field_decl_chain);
 
 
  /* Create an instance of "_objc_module".  */
  /* Create an instance of "_objc_module".  */
  UOBJC_MODULES_decl = start_var_decl (objc_module_template, "_OBJC_MODULES");
  UOBJC_MODULES_decl = start_var_decl (objc_module_template, "_OBJC_MODULES");
  finish_var_decl (UOBJC_MODULES_decl,
  finish_var_decl (UOBJC_MODULES_decl,
                   init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl)));
                   init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl)));
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  pop_lang_context ();
  pop_lang_context ();
#endif
#endif
}
}
 
 
/* The GNU runtime requires us to provide a static initializer function
/* The GNU runtime requires us to provide a static initializer function
   for each module:
   for each module:
 
 
   static void __objc_gnu_init (void) {
   static void __objc_gnu_init (void) {
     __objc_exec_class (&L_OBJC_MODULES);
     __objc_exec_class (&L_OBJC_MODULES);
   }  */
   }  */
 
 
static void
static void
build_module_initializer_routine (void)
build_module_initializer_routine (void)
{
{
  tree body;
  tree body;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  push_lang_context (lang_name_c); /* extern "C" */
  push_lang_context (lang_name_c); /* extern "C" */
#endif
#endif
 
 
  objc_push_parm (build_decl (input_location,
  objc_push_parm (build_decl (input_location,
                              PARM_DECL, NULL_TREE, void_type_node));
                              PARM_DECL, NULL_TREE, void_type_node));
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  objc_start_function (get_identifier (TAG_GNUINIT),
  objc_start_function (get_identifier (TAG_GNUINIT),
                       build_function_type (void_type_node,
                       build_function_type (void_type_node,
                                            OBJC_VOID_AT_END),
                                            OBJC_VOID_AT_END),
                       NULL_TREE, NULL_TREE);
                       NULL_TREE, NULL_TREE);
#else
#else
  objc_start_function (get_identifier (TAG_GNUINIT),
  objc_start_function (get_identifier (TAG_GNUINIT),
                       build_function_type (void_type_node,
                       build_function_type (void_type_node,
                                            OBJC_VOID_AT_END),
                                            OBJC_VOID_AT_END),
                       NULL_TREE, objc_get_parm_info (0));
                       NULL_TREE, objc_get_parm_info (0));
#endif
#endif
  body = c_begin_compound_stmt (true);
  body = c_begin_compound_stmt (true);
  add_stmt (build_function_call
  add_stmt (build_function_call
            (input_location,
            (input_location,
             execclass_decl,
             execclass_decl,
             build_tree_list
             build_tree_list
             (NULL_TREE,
             (NULL_TREE,
              build_unary_op (input_location, ADDR_EXPR,
              build_unary_op (input_location, ADDR_EXPR,
                              UOBJC_MODULES_decl, 0))));
                              UOBJC_MODULES_decl, 0))));
  add_stmt (c_end_compound_stmt (input_location, body, true));
  add_stmt (c_end_compound_stmt (input_location, body, true));
 
 
  TREE_PUBLIC (current_function_decl) = 0;
  TREE_PUBLIC (current_function_decl) = 0;
 
 
#ifndef OBJCPLUS
#ifndef OBJCPLUS
  /* For Objective-C++, we will need to call __objc_gnu_init
  /* For Objective-C++, we will need to call __objc_gnu_init
     from objc_generate_static_init_call() below.  */
     from objc_generate_static_init_call() below.  */
  DECL_STATIC_CONSTRUCTOR (current_function_decl) = 1;
  DECL_STATIC_CONSTRUCTOR (current_function_decl) = 1;
#endif
#endif
 
 
  GNU_INIT_decl = current_function_decl;
  GNU_INIT_decl = current_function_decl;
  finish_function ();
  finish_function ();
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
    pop_lang_context ();
    pop_lang_context ();
#endif
#endif
}
}
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
/* Return 1 if the __objc_gnu_init function has been synthesized and needs
/* Return 1 if the __objc_gnu_init function has been synthesized and needs
   to be called by the module initializer routine.  */
   to be called by the module initializer routine.  */
 
 
int
int
objc_static_init_needed_p (void)
objc_static_init_needed_p (void)
{
{
  return (GNU_INIT_decl != NULL_TREE);
  return (GNU_INIT_decl != NULL_TREE);
}
}
 
 
/* Generate a call to the __objc_gnu_init initializer function.  */
/* Generate a call to the __objc_gnu_init initializer function.  */
 
 
tree
tree
objc_generate_static_init_call (tree ctors ATTRIBUTE_UNUSED)
objc_generate_static_init_call (tree ctors ATTRIBUTE_UNUSED)
{
{
  add_stmt (build_stmt (input_location, EXPR_STMT,
  add_stmt (build_stmt (input_location, EXPR_STMT,
                        build_function_call (input_location,
                        build_function_call (input_location,
                                             GNU_INIT_decl, NULL_TREE)));
                                             GNU_INIT_decl, NULL_TREE)));
 
 
  return ctors;
  return ctors;
}
}
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
/* Return the DECL of the string IDENT in the SECTION.  */
/* Return the DECL of the string IDENT in the SECTION.  */
 
 
static tree
static tree
get_objc_string_decl (tree ident, enum string_section section)
get_objc_string_decl (tree ident, enum string_section section)
{
{
  tree chain;
  tree chain;
 
 
  if (section == class_names)
  if (section == class_names)
    chain = class_names_chain;
    chain = class_names_chain;
  else if (section == meth_var_names)
  else if (section == meth_var_names)
    chain = meth_var_names_chain;
    chain = meth_var_names_chain;
  else if (section == meth_var_types)
  else if (section == meth_var_types)
    chain = meth_var_types_chain;
    chain = meth_var_types_chain;
  else
  else
    abort ();
    abort ();
 
 
  for (; chain != 0; chain = TREE_CHAIN (chain))
  for (; chain != 0; chain = TREE_CHAIN (chain))
    if (TREE_VALUE (chain) == ident)
    if (TREE_VALUE (chain) == ident)
      return (TREE_PURPOSE (chain));
      return (TREE_PURPOSE (chain));
 
 
  abort ();
  abort ();
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Output references to all statically allocated objects.  Return the DECL
/* Output references to all statically allocated objects.  Return the DECL
   for the array built.  */
   for the array built.  */
 
 
static void
static void
generate_static_references (void)
generate_static_references (void)
{
{
  tree decls = NULL_TREE, expr = NULL_TREE;
  tree decls = NULL_TREE, expr = NULL_TREE;
  tree class_name, klass, decl, initlist;
  tree class_name, klass, decl, initlist;
  tree cl_chain, in_chain, type
  tree cl_chain, in_chain, type
    = build_array_type (build_pointer_type (void_type_node), NULL_TREE);
    = build_array_type (build_pointer_type (void_type_node), NULL_TREE);
  int num_inst, num_class;
  int num_inst, num_class;
  char buf[256];
  char buf[256];
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    abort ();
    abort ();
 
 
  for (cl_chain = objc_static_instances, num_class = 0;
  for (cl_chain = objc_static_instances, num_class = 0;
       cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++)
       cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++)
    {
    {
      for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain);
      for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain);
           in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain));
           in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain));
 
 
      sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class);
      sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class);
      decl = start_var_decl (type, buf);
      decl = start_var_decl (type, buf);
 
 
      /* Output {class_name, ...}.  */
      /* Output {class_name, ...}.  */
      klass = TREE_VALUE (cl_chain);
      klass = TREE_VALUE (cl_chain);
      class_name = get_objc_string_decl (OBJC_TYPE_NAME (klass), class_names);
      class_name = get_objc_string_decl (OBJC_TYPE_NAME (klass), class_names);
      initlist = build_tree_list (NULL_TREE,
      initlist = build_tree_list (NULL_TREE,
                                  build_unary_op (input_location,
                                  build_unary_op (input_location,
                                                  ADDR_EXPR, class_name, 1));
                                                  ADDR_EXPR, class_name, 1));
 
 
      /* Output {..., instance, ...}.  */
      /* Output {..., instance, ...}.  */
      for (in_chain = TREE_PURPOSE (cl_chain);
      for (in_chain = TREE_PURPOSE (cl_chain);
           in_chain; in_chain = TREE_CHAIN (in_chain))
           in_chain; in_chain = TREE_CHAIN (in_chain))
        {
        {
          expr = build_unary_op (input_location,
          expr = build_unary_op (input_location,
                                 ADDR_EXPR, TREE_VALUE (in_chain), 1);
                                 ADDR_EXPR, TREE_VALUE (in_chain), 1);
          initlist = tree_cons (NULL_TREE, expr, initlist);
          initlist = tree_cons (NULL_TREE, expr, initlist);
        }
        }
 
 
      /* Output {..., NULL}.  */
      /* Output {..., NULL}.  */
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
 
 
      expr = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist));
      expr = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist));
      finish_var_decl (decl, expr);
      finish_var_decl (decl, expr);
      decls
      decls
        = tree_cons (NULL_TREE, build_unary_op (input_location,
        = tree_cons (NULL_TREE, build_unary_op (input_location,
                                                ADDR_EXPR, decl, 1), decls);
                                                ADDR_EXPR, decl, 1), decls);
    }
    }
 
 
  decls = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), decls);
  decls = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), decls);
  expr = objc_build_constructor (type, nreverse (decls));
  expr = objc_build_constructor (type, nreverse (decls));
  static_instances_decl = start_var_decl (type, "_OBJC_STATIC_INSTANCES");
  static_instances_decl = start_var_decl (type, "_OBJC_STATIC_INSTANCES");
  finish_var_decl (static_instances_decl, expr);
  finish_var_decl (static_instances_decl, expr);
}
}
 
 
static GTY(()) int selector_reference_idx;
static GTY(()) int selector_reference_idx;
 
 
static tree
static tree
build_selector_reference_decl (void)
build_selector_reference_decl (void)
{
{
  tree decl;
  tree decl;
  char buf[256];
  char buf[256];
 
 
  sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", selector_reference_idx++);
  sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", selector_reference_idx++);
  decl = start_var_decl (objc_selector_type, buf);
  decl = start_var_decl (objc_selector_type, buf);
 
 
  return decl;
  return decl;
}
}
 
 
static void
static void
build_selector_table_decl (void)
build_selector_table_decl (void)
{
{
  tree temp;
  tree temp;
 
 
  if (flag_typed_selectors)
  if (flag_typed_selectors)
    {
    {
      build_selector_template ();
      build_selector_template ();
      temp = build_array_type (objc_selector_template, NULL_TREE);
      temp = build_array_type (objc_selector_template, NULL_TREE);
    }
    }
  else
  else
    temp = build_array_type (objc_selector_type, NULL_TREE);
    temp = build_array_type (objc_selector_type, NULL_TREE);
 
 
  UOBJC_SELECTOR_TABLE_decl = start_var_decl (temp, "_OBJC_SELECTOR_TABLE");
  UOBJC_SELECTOR_TABLE_decl = start_var_decl (temp, "_OBJC_SELECTOR_TABLE");
}
}
 
 
/* Just a handy wrapper for add_objc_string.  */
/* Just a handy wrapper for add_objc_string.  */
 
 
static tree
static tree
build_selector (tree ident)
build_selector (tree ident)
{
{
  return convert (objc_selector_type,
  return convert (objc_selector_type,
                  add_objc_string (ident, meth_var_names));
                  add_objc_string (ident, meth_var_names));
}
}
 
 
static void
static void
build_selector_translation_table (void)
build_selector_translation_table (void)
{
{
  tree chain, initlist = NULL_TREE;
  tree chain, initlist = NULL_TREE;
  int offset = 0;
  int offset = 0;
  tree decl = NULL_TREE;
  tree decl = NULL_TREE;
 
 
  for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
  for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
    {
    {
      tree expr;
      tree expr;
 
 
      if (warn_selector && objc_implementation_context)
      if (warn_selector && objc_implementation_context)
      {
      {
        tree method_chain;
        tree method_chain;
        bool found = false;
        bool found = false;
        for (method_chain = meth_var_names_chain;
        for (method_chain = meth_var_names_chain;
             method_chain;
             method_chain;
             method_chain = TREE_CHAIN (method_chain))
             method_chain = TREE_CHAIN (method_chain))
          {
          {
            if (TREE_VALUE (method_chain) == TREE_VALUE (chain))
            if (TREE_VALUE (method_chain) == TREE_VALUE (chain))
              {
              {
                found = true;
                found = true;
                break;
                break;
              }
              }
          }
          }
        if (!found)
        if (!found)
          {
          {
            location_t loc;
            location_t loc;
            if (flag_next_runtime && TREE_PURPOSE (chain))
            if (flag_next_runtime && TREE_PURPOSE (chain))
              loc = DECL_SOURCE_LOCATION (TREE_PURPOSE (chain));
              loc = DECL_SOURCE_LOCATION (TREE_PURPOSE (chain));
            else
            else
              loc = input_location;
              loc = input_location;
            warning_at (loc, 0, "creating selector for nonexistent method %qE",
            warning_at (loc, 0, "creating selector for nonexistent method %qE",
                        TREE_VALUE (chain));
                        TREE_VALUE (chain));
          }
          }
      }
      }
 
 
      expr = build_selector (TREE_VALUE (chain));
      expr = build_selector (TREE_VALUE (chain));
      /* add one for the '\0' character */
      /* add one for the '\0' character */
      offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
      offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
 
 
      if (flag_next_runtime)
      if (flag_next_runtime)
        {
        {
          decl = TREE_PURPOSE (chain);
          decl = TREE_PURPOSE (chain);
          finish_var_decl (decl, expr);
          finish_var_decl (decl, expr);
        }
        }
      else
      else
        {
        {
          if (flag_typed_selectors)
          if (flag_typed_selectors)
            {
            {
              tree eltlist = NULL_TREE;
              tree eltlist = NULL_TREE;
              tree encoding = get_proto_encoding (TREE_PURPOSE (chain));
              tree encoding = get_proto_encoding (TREE_PURPOSE (chain));
              eltlist = tree_cons (NULL_TREE, expr, NULL_TREE);
              eltlist = tree_cons (NULL_TREE, expr, NULL_TREE);
              eltlist = tree_cons (NULL_TREE, encoding, eltlist);
              eltlist = tree_cons (NULL_TREE, encoding, eltlist);
              expr = objc_build_constructor (objc_selector_template,
              expr = objc_build_constructor (objc_selector_template,
                                             nreverse (eltlist));
                                             nreverse (eltlist));
            }
            }
 
 
          initlist = tree_cons (NULL_TREE, expr, initlist);
          initlist = tree_cons (NULL_TREE, expr, initlist);
        }
        }
    }
    }
 
 
  if (! flag_next_runtime)
  if (! flag_next_runtime)
    {
    {
      /* Cause the selector table (previously forward-declared)
      /* Cause the selector table (previously forward-declared)
         to be actually output.  */
         to be actually output.  */
      initlist = tree_cons (NULL_TREE,
      initlist = tree_cons (NULL_TREE,
                            flag_typed_selectors
                            flag_typed_selectors
                            ? objc_build_constructor
                            ? objc_build_constructor
                              (objc_selector_template,
                              (objc_selector_template,
                               tree_cons (NULL_TREE,
                               tree_cons (NULL_TREE,
                                          build_int_cst (NULL_TREE, 0),
                                          build_int_cst (NULL_TREE, 0),
                                          tree_cons (NULL_TREE,
                                          tree_cons (NULL_TREE,
                                                     build_int_cst (NULL_TREE, 0),
                                                     build_int_cst (NULL_TREE, 0),
                                                     NULL_TREE)))
                                                     NULL_TREE)))
                            : build_int_cst (NULL_TREE, 0), initlist);
                            : build_int_cst (NULL_TREE, 0), initlist);
      initlist = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl),
      initlist = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl),
                                         nreverse (initlist));
                                         nreverse (initlist));
      finish_var_decl (UOBJC_SELECTOR_TABLE_decl, initlist);
      finish_var_decl (UOBJC_SELECTOR_TABLE_decl, initlist);
    }
    }
}
}
 
 
static tree
static tree
get_proto_encoding (tree proto)
get_proto_encoding (tree proto)
{
{
  tree encoding;
  tree encoding;
  if (proto)
  if (proto)
    {
    {
      if (! METHOD_ENCODING (proto))
      if (! METHOD_ENCODING (proto))
        {
        {
          encoding = encode_method_prototype (proto);
          encoding = encode_method_prototype (proto);
          METHOD_ENCODING (proto) = encoding;
          METHOD_ENCODING (proto) = encoding;
        }
        }
      else
      else
        encoding = METHOD_ENCODING (proto);
        encoding = METHOD_ENCODING (proto);
 
 
      return add_objc_string (encoding, meth_var_types);
      return add_objc_string (encoding, meth_var_types);
    }
    }
  else
  else
    return build_int_cst (NULL_TREE, 0);
    return build_int_cst (NULL_TREE, 0);
}
}
 
 
/* sel_ref_chain is a list whose "value" fields will be instances of
/* sel_ref_chain is a list whose "value" fields will be instances of
   identifier_node that represent the selector.  LOC is the location of
   identifier_node that represent the selector.  LOC is the location of
   the @selector.  */
   the @selector.  */
 
 
static tree
static tree
build_typed_selector_reference (location_t loc, tree ident, tree prototype)
build_typed_selector_reference (location_t loc, tree ident, tree prototype)
{
{
  tree *chain = &sel_ref_chain;
  tree *chain = &sel_ref_chain;
  tree expr;
  tree expr;
  int index = 0;
  int index = 0;
 
 
  while (*chain)
  while (*chain)
    {
    {
      if (TREE_PURPOSE (*chain) == prototype && TREE_VALUE (*chain) == ident)
      if (TREE_PURPOSE (*chain) == prototype && TREE_VALUE (*chain) == ident)
        goto return_at_index;
        goto return_at_index;
 
 
      index++;
      index++;
      chain = &TREE_CHAIN (*chain);
      chain = &TREE_CHAIN (*chain);
    }
    }
 
 
  *chain = tree_cons (prototype, ident, NULL_TREE);
  *chain = tree_cons (prototype, ident, NULL_TREE);
 
 
 return_at_index:
 return_at_index:
  expr = build_unary_op (loc, ADDR_EXPR,
  expr = build_unary_op (loc, ADDR_EXPR,
                         build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl,
                         build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl,
                                          build_int_cst (NULL_TREE, index)),
                                          build_int_cst (NULL_TREE, index)),
                         1);
                         1);
  return convert (objc_selector_type, expr);
  return convert (objc_selector_type, expr);
}
}
 
 
static tree
static tree
build_selector_reference (location_t loc, tree ident)
build_selector_reference (location_t loc, tree ident)
{
{
  tree *chain = &sel_ref_chain;
  tree *chain = &sel_ref_chain;
  tree expr;
  tree expr;
  int index = 0;
  int index = 0;
 
 
  while (*chain)
  while (*chain)
    {
    {
      if (TREE_VALUE (*chain) == ident)
      if (TREE_VALUE (*chain) == ident)
        return (flag_next_runtime
        return (flag_next_runtime
                ? TREE_PURPOSE (*chain)
                ? TREE_PURPOSE (*chain)
                : build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl,
                : build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl,
                                   build_int_cst (NULL_TREE, index)));
                                   build_int_cst (NULL_TREE, index)));
 
 
      index++;
      index++;
      chain = &TREE_CHAIN (*chain);
      chain = &TREE_CHAIN (*chain);
    }
    }
 
 
  expr = (flag_next_runtime ? build_selector_reference_decl (): NULL_TREE);
  expr = (flag_next_runtime ? build_selector_reference_decl (): NULL_TREE);
 
 
  *chain = tree_cons (expr, ident, NULL_TREE);
  *chain = tree_cons (expr, ident, NULL_TREE);
 
 
  return (flag_next_runtime
  return (flag_next_runtime
          ? expr
          ? expr
          : build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl,
          : build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl,
                             build_int_cst (NULL_TREE, index)));
                             build_int_cst (NULL_TREE, index)));
}
}
 
 
static GTY(()) int class_reference_idx;
static GTY(()) int class_reference_idx;
 
 
static tree
static tree
build_class_reference_decl (void)
build_class_reference_decl (void)
{
{
  tree decl;
  tree decl;
  char buf[256];
  char buf[256];
 
 
  sprintf (buf, "_OBJC_CLASS_REFERENCES_%d", class_reference_idx++);
  sprintf (buf, "_OBJC_CLASS_REFERENCES_%d", class_reference_idx++);
  decl = start_var_decl (objc_class_type, buf);
  decl = start_var_decl (objc_class_type, buf);
 
 
  return decl;
  return decl;
}
}
 
 
/* Create a class reference, but don't create a variable to reference
/* Create a class reference, but don't create a variable to reference
   it.  */
   it.  */
 
 
static void
static void
add_class_reference (tree ident)
add_class_reference (tree ident)
{
{
  tree chain;
  tree chain;
 
 
  if ((chain = cls_ref_chain))
  if ((chain = cls_ref_chain))
    {
    {
      tree tail;
      tree tail;
      do
      do
        {
        {
          if (ident == TREE_VALUE (chain))
          if (ident == TREE_VALUE (chain))
            return;
            return;
 
 
          tail = chain;
          tail = chain;
          chain = TREE_CHAIN (chain);
          chain = TREE_CHAIN (chain);
        }
        }
      while (chain);
      while (chain);
 
 
      /* Append to the end of the list */
      /* Append to the end of the list */
      TREE_CHAIN (tail) = tree_cons (NULL_TREE, ident, NULL_TREE);
      TREE_CHAIN (tail) = tree_cons (NULL_TREE, ident, NULL_TREE);
    }
    }
  else
  else
    cls_ref_chain = tree_cons (NULL_TREE, ident, NULL_TREE);
    cls_ref_chain = tree_cons (NULL_TREE, ident, NULL_TREE);
}
}
 
 
/* Get a class reference, creating it if necessary.  Also create the
/* Get a class reference, creating it if necessary.  Also create the
   reference variable.  */
   reference variable.  */
 
 
tree
tree
objc_get_class_reference (tree ident)
objc_get_class_reference (tree ident)
{
{
  tree orig_ident = (DECL_P (ident)
  tree orig_ident = (DECL_P (ident)
                     ? DECL_NAME (ident)
                     ? DECL_NAME (ident)
                     : TYPE_P (ident)
                     : TYPE_P (ident)
                     ? OBJC_TYPE_NAME (ident)
                     ? OBJC_TYPE_NAME (ident)
                     : ident);
                     : ident);
  bool local_scope = false;
  bool local_scope = false;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (processing_template_decl)
  if (processing_template_decl)
    /* Must wait until template instantiation time.  */
    /* Must wait until template instantiation time.  */
    return build_min_nt (CLASS_REFERENCE_EXPR, ident);
    return build_min_nt (CLASS_REFERENCE_EXPR, ident);
#endif
#endif
 
 
  if (TREE_CODE (ident) == TYPE_DECL)
  if (TREE_CODE (ident) == TYPE_DECL)
    ident = (DECL_ORIGINAL_TYPE (ident)
    ident = (DECL_ORIGINAL_TYPE (ident)
             ? DECL_ORIGINAL_TYPE (ident)
             ? DECL_ORIGINAL_TYPE (ident)
             : TREE_TYPE (ident));
             : TREE_TYPE (ident));
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (TYPE_P (ident) && TYPE_CONTEXT (ident)
  if (TYPE_P (ident) && TYPE_CONTEXT (ident)
      && TYPE_CONTEXT (ident) != global_namespace)
      && TYPE_CONTEXT (ident) != global_namespace)
    local_scope = true;
    local_scope = true;
#endif
#endif
 
 
  if (local_scope || !(ident = objc_is_class_name (ident)))
  if (local_scope || !(ident = objc_is_class_name (ident)))
    {
    {
      error ("%qE is not an Objective-C class name or alias",
      error ("%qE is not an Objective-C class name or alias",
             orig_ident);
             orig_ident);
      return error_mark_node;
      return error_mark_node;
    }
    }
 
 
  if (flag_next_runtime && !flag_zero_link)
  if (flag_next_runtime && !flag_zero_link)
    {
    {
      tree *chain;
      tree *chain;
      tree decl;
      tree decl;
 
 
      for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain))
      for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain))
        if (TREE_VALUE (*chain) == ident)
        if (TREE_VALUE (*chain) == ident)
          {
          {
            if (! TREE_PURPOSE (*chain))
            if (! TREE_PURPOSE (*chain))
              TREE_PURPOSE (*chain) = build_class_reference_decl ();
              TREE_PURPOSE (*chain) = build_class_reference_decl ();
 
 
            return TREE_PURPOSE (*chain);
            return TREE_PURPOSE (*chain);
          }
          }
 
 
      decl = build_class_reference_decl ();
      decl = build_class_reference_decl ();
      *chain = tree_cons (decl, ident, NULL_TREE);
      *chain = tree_cons (decl, ident, NULL_TREE);
      return decl;
      return decl;
    }
    }
  else
  else
    {
    {
      tree params;
      tree params;
 
 
      add_class_reference (ident);
      add_class_reference (ident);
 
 
      params = build_tree_list (NULL_TREE,
      params = build_tree_list (NULL_TREE,
                                my_build_string_pointer
                                my_build_string_pointer
                                (IDENTIFIER_LENGTH (ident) + 1,
                                (IDENTIFIER_LENGTH (ident) + 1,
                                 IDENTIFIER_POINTER (ident)));
                                 IDENTIFIER_POINTER (ident)));
 
 
      assemble_external (objc_get_class_decl);
      assemble_external (objc_get_class_decl);
      return build_function_call (input_location, objc_get_class_decl, params);
      return build_function_call (input_location, objc_get_class_decl, params);
    }
    }
}
}
 
 
/* For each string section we have a chain which maps identifier nodes
/* For each string section we have a chain which maps identifier nodes
   to decls for the strings.  */
   to decls for the strings.  */
 
 
static tree
static tree
add_objc_string (tree ident, enum string_section section)
add_objc_string (tree ident, enum string_section section)
{
{
  tree *chain, decl, type, string_expr;
  tree *chain, decl, type, string_expr;
 
 
  if (section == class_names)
  if (section == class_names)
    chain = &class_names_chain;
    chain = &class_names_chain;
  else if (section == meth_var_names)
  else if (section == meth_var_names)
    chain = &meth_var_names_chain;
    chain = &meth_var_names_chain;
  else if (section == meth_var_types)
  else if (section == meth_var_types)
    chain = &meth_var_types_chain;
    chain = &meth_var_types_chain;
  else
  else
    abort ();
    abort ();
 
 
  while (*chain)
  while (*chain)
    {
    {
      if (TREE_VALUE (*chain) == ident)
      if (TREE_VALUE (*chain) == ident)
        return convert (string_type_node,
        return convert (string_type_node,
                        build_unary_op (input_location,
                        build_unary_op (input_location,
                                        ADDR_EXPR, TREE_PURPOSE (*chain), 1));
                                        ADDR_EXPR, TREE_PURPOSE (*chain), 1));
 
 
      chain = &TREE_CHAIN (*chain);
      chain = &TREE_CHAIN (*chain);
    }
    }
 
 
  decl = build_objc_string_decl (section);
  decl = build_objc_string_decl (section);
 
 
  type = build_array_type
  type = build_array_type
         (char_type_node,
         (char_type_node,
          build_index_type
          build_index_type
          (build_int_cst (NULL_TREE,
          (build_int_cst (NULL_TREE,
                          IDENTIFIER_LENGTH (ident))));
                          IDENTIFIER_LENGTH (ident))));
  decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl)));
  decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl)));
  string_expr = my_build_string (IDENTIFIER_LENGTH (ident) + 1,
  string_expr = my_build_string (IDENTIFIER_LENGTH (ident) + 1,
                                 IDENTIFIER_POINTER (ident));
                                 IDENTIFIER_POINTER (ident));
  finish_var_decl (decl, string_expr);
  finish_var_decl (decl, string_expr);
 
 
  *chain = tree_cons (decl, ident, NULL_TREE);
  *chain = tree_cons (decl, ident, NULL_TREE);
 
 
  return convert (string_type_node, build_unary_op (input_location,
  return convert (string_type_node, build_unary_op (input_location,
                                                    ADDR_EXPR, decl, 1));
                                                    ADDR_EXPR, decl, 1));
}
}
 
 
static GTY(()) int class_names_idx;
static GTY(()) int class_names_idx;
static GTY(()) int meth_var_names_idx;
static GTY(()) int meth_var_names_idx;
static GTY(()) int meth_var_types_idx;
static GTY(()) int meth_var_types_idx;
 
 
static tree
static tree
build_objc_string_decl (enum string_section section)
build_objc_string_decl (enum string_section section)
{
{
  tree decl, ident;
  tree decl, ident;
  char buf[256];
  char buf[256];
 
 
  if (section == class_names)
  if (section == class_names)
    sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
    sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
  else if (section == meth_var_names)
  else if (section == meth_var_names)
    sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
    sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
  else if (section == meth_var_types)
  else if (section == meth_var_types)
    sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
    sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
 
 
  ident = get_identifier (buf);
  ident = get_identifier (buf);
 
 
  decl = build_decl (input_location,
  decl = build_decl (input_location,
                     VAR_DECL, ident, build_array_type (char_type_node, 0));
                     VAR_DECL, ident, build_array_type (char_type_node, 0));
  DECL_EXTERNAL (decl) = 1;
  DECL_EXTERNAL (decl) = 1;
  TREE_PUBLIC (decl) = 0;
  TREE_PUBLIC (decl) = 0;
  TREE_USED (decl) = 1;
  TREE_USED (decl) = 1;
  TREE_CONSTANT (decl) = 1;
  TREE_CONSTANT (decl) = 1;
  DECL_CONTEXT (decl) = 0;
  DECL_CONTEXT (decl) = 0;
  DECL_ARTIFICIAL (decl) = 1;
  DECL_ARTIFICIAL (decl) = 1;
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  DECL_THIS_STATIC (decl) = 1; /* squash redeclaration errors */
  DECL_THIS_STATIC (decl) = 1; /* squash redeclaration errors */
#endif
#endif
 
 
  make_decl_rtl (decl);
  make_decl_rtl (decl);
  pushdecl_top_level (decl);
  pushdecl_top_level (decl);
 
 
  return decl;
  return decl;
}
}
 
 
 
 
void
void
objc_declare_alias (tree alias_ident, tree class_ident)
objc_declare_alias (tree alias_ident, tree class_ident)
{
{
  tree underlying_class;
  tree underlying_class;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (current_namespace != global_namespace) {
  if (current_namespace != global_namespace) {
    error ("Objective-C declarations may only appear in global scope");
    error ("Objective-C declarations may only appear in global scope");
  }
  }
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
  if (!(underlying_class = objc_is_class_name (class_ident)))
  if (!(underlying_class = objc_is_class_name (class_ident)))
    warning (0, "cannot find class %qE", class_ident);
    warning (0, "cannot find class %qE", class_ident);
  else if (objc_is_class_name (alias_ident))
  else if (objc_is_class_name (alias_ident))
    warning (0, "class %qE already exists", alias_ident);
    warning (0, "class %qE already exists", alias_ident);
  else
  else
    {
    {
      /* Implement @compatibility_alias as a typedef.  */
      /* Implement @compatibility_alias as a typedef.  */
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      push_lang_context (lang_name_c); /* extern "C" */
      push_lang_context (lang_name_c); /* extern "C" */
#endif
#endif
      lang_hooks.decls.pushdecl (build_decl
      lang_hooks.decls.pushdecl (build_decl
                                 (input_location,
                                 (input_location,
                                  TYPE_DECL,
                                  TYPE_DECL,
                                  alias_ident,
                                  alias_ident,
                                  xref_tag (RECORD_TYPE, underlying_class)));
                                  xref_tag (RECORD_TYPE, underlying_class)));
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      pop_lang_context ();
      pop_lang_context ();
#endif
#endif
      alias_chain = tree_cons (underlying_class, alias_ident, alias_chain);
      alias_chain = tree_cons (underlying_class, alias_ident, alias_chain);
    }
    }
}
}
 
 
void
void
objc_declare_class (tree ident_list)
objc_declare_class (tree ident_list)
{
{
  tree list;
  tree list;
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (current_namespace != global_namespace) {
  if (current_namespace != global_namespace) {
    error ("Objective-C declarations may only appear in global scope");
    error ("Objective-C declarations may only appear in global scope");
  }
  }
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
  for (list = ident_list; list; list = TREE_CHAIN (list))
  for (list = ident_list; list; list = TREE_CHAIN (list))
    {
    {
      tree ident = TREE_VALUE (list);
      tree ident = TREE_VALUE (list);
 
 
      if (! objc_is_class_name (ident))
      if (! objc_is_class_name (ident))
        {
        {
          tree record = lookup_name (ident), type = record;
          tree record = lookup_name (ident), type = record;
 
 
          if (record)
          if (record)
            {
            {
              if (TREE_CODE (record) == TYPE_DECL)
              if (TREE_CODE (record) == TYPE_DECL)
                type = DECL_ORIGINAL_TYPE (record);
                type = DECL_ORIGINAL_TYPE (record);
 
 
              if (!TYPE_HAS_OBJC_INFO (type)
              if (!TYPE_HAS_OBJC_INFO (type)
                  || !TYPE_OBJC_INTERFACE (type))
                  || !TYPE_OBJC_INTERFACE (type))
                {
                {
                  error ("%qE redeclared as different kind of symbol",
                  error ("%qE redeclared as different kind of symbol",
                         ident);
                         ident);
                  error ("previous declaration of %q+D",
                  error ("previous declaration of %q+D",
                         record);
                         record);
                }
                }
            }
            }
 
 
          record = xref_tag (RECORD_TYPE, ident);
          record = xref_tag (RECORD_TYPE, ident);
          INIT_TYPE_OBJC_INFO (record);
          INIT_TYPE_OBJC_INFO (record);
          TYPE_OBJC_INTERFACE (record) = ident;
          TYPE_OBJC_INTERFACE (record) = ident;
          class_chain = tree_cons (NULL_TREE, ident, class_chain);
          class_chain = tree_cons (NULL_TREE, ident, class_chain);
        }
        }
    }
    }
}
}
 
 
tree
tree
objc_is_class_name (tree ident)
objc_is_class_name (tree ident)
{
{
  tree chain;
  tree chain;
 
 
  if (ident && TREE_CODE (ident) == IDENTIFIER_NODE
  if (ident && TREE_CODE (ident) == IDENTIFIER_NODE
      && identifier_global_value (ident))
      && identifier_global_value (ident))
    ident = identifier_global_value (ident);
    ident = identifier_global_value (ident);
  while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident))
  while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident))
    ident = OBJC_TYPE_NAME (DECL_ORIGINAL_TYPE (ident));
    ident = OBJC_TYPE_NAME (DECL_ORIGINAL_TYPE (ident));
 
 
  if (ident && TREE_CODE (ident) == RECORD_TYPE)
  if (ident && TREE_CODE (ident) == RECORD_TYPE)
    ident = OBJC_TYPE_NAME (ident);
    ident = OBJC_TYPE_NAME (ident);
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (ident && TREE_CODE (ident) == TYPE_DECL)
  if (ident && TREE_CODE (ident) == TYPE_DECL)
    ident = DECL_NAME (ident);
    ident = DECL_NAME (ident);
#endif
#endif
  if (!ident || TREE_CODE (ident) != IDENTIFIER_NODE)
  if (!ident || TREE_CODE (ident) != IDENTIFIER_NODE)
    return NULL_TREE;
    return NULL_TREE;
 
 
  if (lookup_interface (ident))
  if (lookup_interface (ident))
    return ident;
    return ident;
 
 
  for (chain = class_chain; chain; chain = TREE_CHAIN (chain))
  for (chain = class_chain; chain; chain = TREE_CHAIN (chain))
    {
    {
      if (ident == TREE_VALUE (chain))
      if (ident == TREE_VALUE (chain))
        return ident;
        return ident;
    }
    }
 
 
  for (chain = alias_chain; chain; chain = TREE_CHAIN (chain))
  for (chain = alias_chain; chain; chain = TREE_CHAIN (chain))
    {
    {
      if (ident == TREE_VALUE (chain))
      if (ident == TREE_VALUE (chain))
        return TREE_PURPOSE (chain);
        return TREE_PURPOSE (chain);
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
/* Check whether TYPE is either 'id' or 'Class'.  */
/* Check whether TYPE is either 'id' or 'Class'.  */
 
 
tree
tree
objc_is_id (tree type)
objc_is_id (tree type)
{
{
  if (type && TREE_CODE (type) == IDENTIFIER_NODE
  if (type && TREE_CODE (type) == IDENTIFIER_NODE
      && identifier_global_value (type))
      && identifier_global_value (type))
    type = identifier_global_value (type);
    type = identifier_global_value (type);
 
 
  if (type && TREE_CODE (type) == TYPE_DECL)
  if (type && TREE_CODE (type) == TYPE_DECL)
    type = TREE_TYPE (type);
    type = TREE_TYPE (type);
 
 
  /* NB: This function may be called before the ObjC front-end has
  /* NB: This function may be called before the ObjC front-end has
     been initialized, in which case OBJC_OBJECT_TYPE will (still) be NULL.  */
     been initialized, in which case OBJC_OBJECT_TYPE will (still) be NULL.  */
  return (objc_object_type && type
  return (objc_object_type && type
          && (IS_ID (type) || IS_CLASS (type) || IS_SUPER (type))
          && (IS_ID (type) || IS_CLASS (type) || IS_SUPER (type))
          ? type
          ? type
          : NULL_TREE);
          : NULL_TREE);
}
}
 
 
/* Check whether TYPE is either 'id', 'Class', or a pointer to an ObjC
/* 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
   class instance.  This is needed by other parts of the compiler to
   handle ObjC types gracefully.  */
   handle ObjC types gracefully.  */
 
 
tree
tree
objc_is_object_ptr (tree type)
objc_is_object_ptr (tree type)
{
{
  tree ret;
  tree ret;
 
 
  type = TYPE_MAIN_VARIANT (type);
  type = TYPE_MAIN_VARIANT (type);
  if (!POINTER_TYPE_P (type))
  if (!POINTER_TYPE_P (type))
    return 0;
    return 0;
 
 
  ret = objc_is_id (type);
  ret = objc_is_id (type);
  if (!ret)
  if (!ret)
    ret = objc_is_class_name (TREE_TYPE (type));
    ret = objc_is_class_name (TREE_TYPE (type));
 
 
  return ret;
  return ret;
}
}
 
 
static int
static int
objc_is_gcable_type (tree type, int or_strong_p)
objc_is_gcable_type (tree type, int or_strong_p)
{
{
  tree name;
  tree name;
 
 
  if (!TYPE_P (type))
  if (!TYPE_P (type))
    return 0;
    return 0;
  if (objc_is_id (TYPE_MAIN_VARIANT (type)))
  if (objc_is_id (TYPE_MAIN_VARIANT (type)))
    return 1;
    return 1;
  if (or_strong_p && lookup_attribute ("objc_gc", TYPE_ATTRIBUTES (type)))
  if (or_strong_p && lookup_attribute ("objc_gc", TYPE_ATTRIBUTES (type)))
    return 1;
    return 1;
  if (TREE_CODE (type) != POINTER_TYPE && TREE_CODE (type) != INDIRECT_REF)
  if (TREE_CODE (type) != POINTER_TYPE && TREE_CODE (type) != INDIRECT_REF)
    return 0;
    return 0;
  type = TREE_TYPE (type);
  type = TREE_TYPE (type);
  if (TREE_CODE (type) != RECORD_TYPE)
  if (TREE_CODE (type) != RECORD_TYPE)
    return 0;
    return 0;
  name = TYPE_NAME (type);
  name = TYPE_NAME (type);
  return (objc_is_class_name (name) != NULL_TREE);
  return (objc_is_class_name (name) != NULL_TREE);
}
}
 
 
static tree
static tree
objc_substitute_decl (tree expr, tree oldexpr, tree newexpr)
objc_substitute_decl (tree expr, tree oldexpr, tree newexpr)
{
{
  if (expr == oldexpr)
  if (expr == oldexpr)
    return newexpr;
    return newexpr;
 
 
  switch (TREE_CODE (expr))
  switch (TREE_CODE (expr))
    {
    {
    case COMPONENT_REF:
    case COMPONENT_REF:
      return objc_build_component_ref
      return objc_build_component_ref
             (objc_substitute_decl (TREE_OPERAND (expr, 0),
             (objc_substitute_decl (TREE_OPERAND (expr, 0),
                                    oldexpr,
                                    oldexpr,
                                    newexpr),
                                    newexpr),
              DECL_NAME (TREE_OPERAND (expr, 1)));
              DECL_NAME (TREE_OPERAND (expr, 1)));
    case ARRAY_REF:
    case ARRAY_REF:
      return build_array_ref (input_location,
      return build_array_ref (input_location,
                              objc_substitute_decl (TREE_OPERAND (expr, 0),
                              objc_substitute_decl (TREE_OPERAND (expr, 0),
                                                    oldexpr,
                                                    oldexpr,
                                                    newexpr),
                                                    newexpr),
                              TREE_OPERAND (expr, 1));
                              TREE_OPERAND (expr, 1));
    case INDIRECT_REF:
    case INDIRECT_REF:
      return build_indirect_ref (input_location,
      return build_indirect_ref (input_location,
                                 objc_substitute_decl (TREE_OPERAND (expr, 0),
                                 objc_substitute_decl (TREE_OPERAND (expr, 0),
                                                       oldexpr,
                                                       oldexpr,
                                                       newexpr), RO_ARROW);
                                                       newexpr), RO_ARROW);
    default:
    default:
      return expr;
      return expr;
    }
    }
}
}
 
 
static tree
static tree
objc_build_ivar_assignment (tree outervar, tree lhs, tree rhs)
objc_build_ivar_assignment (tree outervar, tree lhs, tree rhs)
{
{
  tree func_params;
  tree func_params;
  /* The LHS parameter contains the expression 'outervar->memberspec';
  /* The LHS parameter contains the expression 'outervar->memberspec';
     we need to transform it into '&((typeof(outervar) *) 0)->memberspec',
     we need to transform it into '&((typeof(outervar) *) 0)->memberspec',
     where memberspec may be arbitrarily complex (e.g., 'g->f.d[2].g[3]').
     where memberspec may be arbitrarily complex (e.g., 'g->f.d[2].g[3]').
  */
  */
  tree offs
  tree offs
    = objc_substitute_decl
    = objc_substitute_decl
      (lhs, outervar, convert (TREE_TYPE (outervar), integer_zero_node));
      (lhs, outervar, convert (TREE_TYPE (outervar), integer_zero_node));
  tree func
  tree func
    = (flag_objc_direct_dispatch
    = (flag_objc_direct_dispatch
       ? objc_assign_ivar_fast_decl
       ? objc_assign_ivar_fast_decl
       : objc_assign_ivar_decl);
       : objc_assign_ivar_decl);
 
 
  offs = convert (integer_type_node, build_unary_op (input_location,
  offs = convert (integer_type_node, build_unary_op (input_location,
                                                     ADDR_EXPR, offs, 0));
                                                     ADDR_EXPR, offs, 0));
  offs = fold (offs);
  offs = fold (offs);
  func_params = tree_cons (NULL_TREE,
  func_params = tree_cons (NULL_TREE,
        convert (objc_object_type, rhs),
        convert (objc_object_type, rhs),
            tree_cons (NULL_TREE, convert (objc_object_type, outervar),
            tree_cons (NULL_TREE, convert (objc_object_type, outervar),
                tree_cons (NULL_TREE, offs,
                tree_cons (NULL_TREE, offs,
                    NULL_TREE)));
                    NULL_TREE)));
 
 
  assemble_external (func);
  assemble_external (func);
  return build_function_call (input_location, func, func_params);
  return build_function_call (input_location, func, func_params);
}
}
 
 
static tree
static tree
objc_build_global_assignment (tree lhs, tree rhs)
objc_build_global_assignment (tree lhs, tree rhs)
{
{
  tree func_params = tree_cons (NULL_TREE,
  tree func_params = tree_cons (NULL_TREE,
        convert (objc_object_type, rhs),
        convert (objc_object_type, rhs),
            tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type),
            tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type),
                      build_unary_op (input_location, ADDR_EXPR, lhs, 0)),
                      build_unary_op (input_location, ADDR_EXPR, lhs, 0)),
                    NULL_TREE));
                    NULL_TREE));
 
 
  assemble_external (objc_assign_global_decl);
  assemble_external (objc_assign_global_decl);
  return build_function_call (input_location,
  return build_function_call (input_location,
                              objc_assign_global_decl, func_params);
                              objc_assign_global_decl, func_params);
}
}
 
 
static tree
static tree
objc_build_strong_cast_assignment (tree lhs, tree rhs)
objc_build_strong_cast_assignment (tree lhs, tree rhs)
{
{
  tree func_params = tree_cons (NULL_TREE,
  tree func_params = tree_cons (NULL_TREE,
        convert (objc_object_type, rhs),
        convert (objc_object_type, rhs),
            tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type),
            tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type),
                      build_unary_op (input_location, ADDR_EXPR, lhs, 0)),
                      build_unary_op (input_location, ADDR_EXPR, lhs, 0)),
                    NULL_TREE));
                    NULL_TREE));
 
 
  assemble_external (objc_assign_strong_cast_decl);
  assemble_external (objc_assign_strong_cast_decl);
  return build_function_call (input_location,
  return build_function_call (input_location,
                              objc_assign_strong_cast_decl, func_params);
                              objc_assign_strong_cast_decl, func_params);
}
}
 
 
static int
static int
objc_is_gcable_p (tree expr)
objc_is_gcable_p (tree expr)
{
{
  return (TREE_CODE (expr) == COMPONENT_REF
  return (TREE_CODE (expr) == COMPONENT_REF
          ? objc_is_gcable_p (TREE_OPERAND (expr, 1))
          ? objc_is_gcable_p (TREE_OPERAND (expr, 1))
          : TREE_CODE (expr) == ARRAY_REF
          : TREE_CODE (expr) == ARRAY_REF
          ? (objc_is_gcable_p (TREE_TYPE (expr))
          ? (objc_is_gcable_p (TREE_TYPE (expr))
             || objc_is_gcable_p (TREE_OPERAND (expr, 0)))
             || objc_is_gcable_p (TREE_OPERAND (expr, 0)))
          : TREE_CODE (expr) == ARRAY_TYPE
          : TREE_CODE (expr) == ARRAY_TYPE
          ? objc_is_gcable_p (TREE_TYPE (expr))
          ? objc_is_gcable_p (TREE_TYPE (expr))
          : TYPE_P (expr)
          : TYPE_P (expr)
          ? objc_is_gcable_type (expr, 1)
          ? objc_is_gcable_type (expr, 1)
          : (objc_is_gcable_p (TREE_TYPE (expr))
          : (objc_is_gcable_p (TREE_TYPE (expr))
             || (DECL_P (expr)
             || (DECL_P (expr)
                 && lookup_attribute ("objc_gc", DECL_ATTRIBUTES (expr)))));
                 && lookup_attribute ("objc_gc", DECL_ATTRIBUTES (expr)))));
}
}
 
 
static int
static int
objc_is_ivar_reference_p (tree expr)
objc_is_ivar_reference_p (tree expr)
{
{
  return (TREE_CODE (expr) == ARRAY_REF
  return (TREE_CODE (expr) == ARRAY_REF
          ? objc_is_ivar_reference_p (TREE_OPERAND (expr, 0))
          ? objc_is_ivar_reference_p (TREE_OPERAND (expr, 0))
          : TREE_CODE (expr) == COMPONENT_REF
          : TREE_CODE (expr) == COMPONENT_REF
          ? TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL
          ? TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL
          : 0);
          : 0);
}
}
 
 
static int
static int
objc_is_global_reference_p (tree expr)
objc_is_global_reference_p (tree expr)
{
{
  return (TREE_CODE (expr) == INDIRECT_REF || TREE_CODE (expr) == PLUS_EXPR
  return (TREE_CODE (expr) == INDIRECT_REF || TREE_CODE (expr) == PLUS_EXPR
          ? objc_is_global_reference_p (TREE_OPERAND (expr, 0))
          ? objc_is_global_reference_p (TREE_OPERAND (expr, 0))
          : DECL_P (expr)
          : DECL_P (expr)
          ? (!DECL_CONTEXT (expr) || TREE_STATIC (expr))
          ? (!DECL_CONTEXT (expr) || TREE_STATIC (expr))
          : 0);
          : 0);
}
}
 
 
tree
tree
objc_generate_write_barrier (tree lhs, enum tree_code modifycode, tree rhs)
objc_generate_write_barrier (tree lhs, enum tree_code modifycode, tree rhs)
{
{
  tree result = NULL_TREE, outer;
  tree result = NULL_TREE, outer;
  int strong_cast_p = 0, outer_gc_p = 0, indirect_p = 0;
  int strong_cast_p = 0, outer_gc_p = 0, indirect_p = 0;
 
 
  /* See if we have any lhs casts, and strip them out.  NB: The lvalue casts
  /* See if we have any lhs casts, and strip them out.  NB: The lvalue casts
     will have been transformed to the form '*(type *)&expr'.  */
     will have been transformed to the form '*(type *)&expr'.  */
  if (TREE_CODE (lhs) == INDIRECT_REF)
  if (TREE_CODE (lhs) == INDIRECT_REF)
    {
    {
      outer = TREE_OPERAND (lhs, 0);
      outer = TREE_OPERAND (lhs, 0);
 
 
      while (!strong_cast_p
      while (!strong_cast_p
             && (CONVERT_EXPR_P (outer)
             && (CONVERT_EXPR_P (outer)
                 || TREE_CODE (outer) == NON_LVALUE_EXPR))
                 || TREE_CODE (outer) == NON_LVALUE_EXPR))
        {
        {
          tree lhstype = TREE_TYPE (outer);
          tree lhstype = TREE_TYPE (outer);
 
 
          /* Descend down the cast chain, and record the first objc_gc
          /* Descend down the cast chain, and record the first objc_gc
             attribute found.  */
             attribute found.  */
          if (POINTER_TYPE_P (lhstype))
          if (POINTER_TYPE_P (lhstype))
            {
            {
              tree attr
              tree attr
                = lookup_attribute ("objc_gc",
                = lookup_attribute ("objc_gc",
                                    TYPE_ATTRIBUTES (TREE_TYPE (lhstype)));
                                    TYPE_ATTRIBUTES (TREE_TYPE (lhstype)));
 
 
              if (attr)
              if (attr)
                strong_cast_p = 1;
                strong_cast_p = 1;
            }
            }
 
 
          outer = TREE_OPERAND (outer, 0);
          outer = TREE_OPERAND (outer, 0);
        }
        }
    }
    }
 
 
  /* If we have a __strong cast, it trumps all else.  */
  /* If we have a __strong cast, it trumps all else.  */
  if (strong_cast_p)
  if (strong_cast_p)
    {
    {
      if (modifycode != NOP_EXPR)
      if (modifycode != NOP_EXPR)
        goto invalid_pointer_arithmetic;
        goto invalid_pointer_arithmetic;
 
 
      if (warn_assign_intercept)
      if (warn_assign_intercept)
        warning (0, "strong-cast assignment has been intercepted");
        warning (0, "strong-cast assignment has been intercepted");
 
 
      result = objc_build_strong_cast_assignment (lhs, rhs);
      result = objc_build_strong_cast_assignment (lhs, rhs);
 
 
      goto exit_point;
      goto exit_point;
    }
    }
 
 
  /* the lhs must be of a suitable type, regardless of its underlying
  /* the lhs must be of a suitable type, regardless of its underlying
     structure.  */
     structure.  */
  if (!objc_is_gcable_p (lhs))
  if (!objc_is_gcable_p (lhs))
    goto exit_point;
    goto exit_point;
 
 
  outer = lhs;
  outer = lhs;
 
 
  while (outer
  while (outer
         && (TREE_CODE (outer) == COMPONENT_REF
         && (TREE_CODE (outer) == COMPONENT_REF
             || TREE_CODE (outer) == ARRAY_REF))
             || TREE_CODE (outer) == ARRAY_REF))
    outer = TREE_OPERAND (outer, 0);
    outer = TREE_OPERAND (outer, 0);
 
 
  if (TREE_CODE (outer) == INDIRECT_REF)
  if (TREE_CODE (outer) == INDIRECT_REF)
    {
    {
      outer = TREE_OPERAND (outer, 0);
      outer = TREE_OPERAND (outer, 0);
      indirect_p = 1;
      indirect_p = 1;
    }
    }
 
 
  outer_gc_p = objc_is_gcable_p (outer);
  outer_gc_p = objc_is_gcable_p (outer);
 
 
  /* Handle ivar assignments. */
  /* Handle ivar assignments. */
  if (objc_is_ivar_reference_p (lhs))
  if (objc_is_ivar_reference_p (lhs))
    {
    {
      /* if the struct to the left of the ivar is not an Objective-C object (__strong
      /* if the struct to the left of the ivar is not an Objective-C object (__strong
         doesn't cut it here), the best we can do here is suggest a cast.  */
         doesn't cut it here), the best we can do here is suggest a cast.  */
      if (!objc_is_gcable_type (TREE_TYPE (outer), 0))
      if (!objc_is_gcable_type (TREE_TYPE (outer), 0))
        {
        {
          /* We may still be able to use the global write barrier... */
          /* We may still be able to use the global write barrier... */
          if (!indirect_p && objc_is_global_reference_p (outer))
          if (!indirect_p && objc_is_global_reference_p (outer))
            goto global_reference;
            goto global_reference;
 
 
         suggest_cast:
         suggest_cast:
          if (modifycode == NOP_EXPR)
          if (modifycode == NOP_EXPR)
            {
            {
              if (warn_assign_intercept)
              if (warn_assign_intercept)
                warning (0, "strong-cast may possibly be needed");
                warning (0, "strong-cast may possibly be needed");
            }
            }
 
 
          goto exit_point;
          goto exit_point;
        }
        }
 
 
      if (modifycode != NOP_EXPR)
      if (modifycode != NOP_EXPR)
        goto invalid_pointer_arithmetic;
        goto invalid_pointer_arithmetic;
 
 
      if (warn_assign_intercept)
      if (warn_assign_intercept)
        warning (0, "instance variable assignment has been intercepted");
        warning (0, "instance variable assignment has been intercepted");
 
 
      result = objc_build_ivar_assignment (outer, lhs, rhs);
      result = objc_build_ivar_assignment (outer, lhs, rhs);
 
 
      goto exit_point;
      goto exit_point;
    }
    }
 
 
  /* Likewise, intercept assignment to global/static variables if their type is
  /* Likewise, intercept assignment to global/static variables if their type is
     GC-marked.  */
     GC-marked.  */
  if (objc_is_global_reference_p (outer))
  if (objc_is_global_reference_p (outer))
    {
    {
      if (indirect_p)
      if (indirect_p)
        goto suggest_cast;
        goto suggest_cast;
 
 
     global_reference:
     global_reference:
      if (modifycode != NOP_EXPR)
      if (modifycode != NOP_EXPR)
        {
        {
         invalid_pointer_arithmetic:
         invalid_pointer_arithmetic:
          if (outer_gc_p)
          if (outer_gc_p)
            warning (0, "pointer arithmetic for garbage-collected objects not allowed");
            warning (0, "pointer arithmetic for garbage-collected objects not allowed");
 
 
          goto exit_point;
          goto exit_point;
        }
        }
 
 
      if (warn_assign_intercept)
      if (warn_assign_intercept)
        warning (0, "global/static variable assignment has been intercepted");
        warning (0, "global/static variable assignment has been intercepted");
 
 
      result = objc_build_global_assignment (lhs, rhs);
      result = objc_build_global_assignment (lhs, rhs);
    }
    }
 
 
  /* In all other cases, fall back to the normal mechanism.  */
  /* In all other cases, fall back to the normal mechanism.  */
 exit_point:
 exit_point:
  return result;
  return result;
}
}
 
 
struct GTY(()) interface_tuple {
struct GTY(()) interface_tuple {
  tree id;
  tree id;
  tree class_name;
  tree class_name;
};
};
 
 
static GTY ((param_is (struct interface_tuple))) htab_t interface_htab;
static GTY ((param_is (struct interface_tuple))) htab_t interface_htab;
 
 
static hashval_t
static hashval_t
hash_interface (const void *p)
hash_interface (const void *p)
{
{
  const struct interface_tuple *d = (const struct interface_tuple *) p;
  const struct interface_tuple *d = (const struct interface_tuple *) p;
  return IDENTIFIER_HASH_VALUE (d->id);
  return IDENTIFIER_HASH_VALUE (d->id);
}
}
 
 
static int
static int
eq_interface (const void *p1, const void *p2)
eq_interface (const void *p1, const void *p2)
{
{
  const struct interface_tuple *d = (const struct interface_tuple *) p1;
  const struct interface_tuple *d = (const struct interface_tuple *) p1;
  return d->id == p2;
  return d->id == p2;
}
}
 
 
static tree
static tree
lookup_interface (tree ident)
lookup_interface (tree ident)
{
{
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (ident && TREE_CODE (ident) == TYPE_DECL)
  if (ident && TREE_CODE (ident) == TYPE_DECL)
    ident = DECL_NAME (ident);
    ident = DECL_NAME (ident);
#endif
#endif
 
 
  if (ident == NULL_TREE || TREE_CODE (ident) != IDENTIFIER_NODE)
  if (ident == NULL_TREE || TREE_CODE (ident) != IDENTIFIER_NODE)
    return NULL_TREE;
    return NULL_TREE;
 
 
  {
  {
    struct interface_tuple **slot;
    struct interface_tuple **slot;
    tree i = NULL_TREE;
    tree i = NULL_TREE;
 
 
    if (interface_htab)
    if (interface_htab)
      {
      {
        slot = (struct interface_tuple **)
        slot = (struct interface_tuple **)
          htab_find_slot_with_hash (interface_htab, ident,
          htab_find_slot_with_hash (interface_htab, ident,
                                    IDENTIFIER_HASH_VALUE (ident),
                                    IDENTIFIER_HASH_VALUE (ident),
                                    NO_INSERT);
                                    NO_INSERT);
        if (slot && *slot)
        if (slot && *slot)
          i = (*slot)->class_name;
          i = (*slot)->class_name;
      }
      }
    return i;
    return i;
  }
  }
}
}
 
 
/* Implement @defs (<classname>) within struct bodies.  */
/* Implement @defs (<classname>) within struct bodies.  */
 
 
tree
tree
objc_get_class_ivars (tree class_name)
objc_get_class_ivars (tree class_name)
{
{
  tree interface = lookup_interface (class_name);
  tree interface = lookup_interface (class_name);
 
 
  if (interface)
  if (interface)
    return get_class_ivars (interface, true);
    return get_class_ivars (interface, true);
 
 
  error ("cannot find interface declaration for %qE",
  error ("cannot find interface declaration for %qE",
         class_name);
         class_name);
 
 
  return error_mark_node;
  return error_mark_node;
}
}
 
 
/* Used by: build_private_template, continue_class,
/* Used by: build_private_template, continue_class,
   and for @defs constructs.  */
   and for @defs constructs.  */
 
 
static tree
static tree
get_class_ivars (tree interface, bool inherited)
get_class_ivars (tree interface, bool inherited)
{
{
  tree ivar_chain = copy_list (CLASS_RAW_IVARS (interface));
  tree ivar_chain = copy_list (CLASS_RAW_IVARS (interface));
 
 
  /* Both CLASS_RAW_IVARS and CLASS_IVARS contain a list of ivars declared
  /* Both CLASS_RAW_IVARS and CLASS_IVARS contain a list of ivars declared
     by the current class (i.e., they do not include super-class ivars).
     by the current class (i.e., they do not include super-class ivars).
     However, the CLASS_IVARS list will be side-effected by a call to
     However, the CLASS_IVARS list will be side-effected by a call to
     finish_struct(), which will fill in field offsets.  */
     finish_struct(), which will fill in field offsets.  */
  if (!CLASS_IVARS (interface))
  if (!CLASS_IVARS (interface))
    CLASS_IVARS (interface) = ivar_chain;
    CLASS_IVARS (interface) = ivar_chain;
 
 
  if (!inherited)
  if (!inherited)
    return ivar_chain;
    return ivar_chain;
 
 
  while (CLASS_SUPER_NAME (interface))
  while (CLASS_SUPER_NAME (interface))
    {
    {
      /* Prepend super-class ivars.  */
      /* Prepend super-class ivars.  */
      interface = lookup_interface (CLASS_SUPER_NAME (interface));
      interface = lookup_interface (CLASS_SUPER_NAME (interface));
      ivar_chain = chainon (copy_list (CLASS_RAW_IVARS (interface)),
      ivar_chain = chainon (copy_list (CLASS_RAW_IVARS (interface)),
                            ivar_chain);
                            ivar_chain);
    }
    }
 
 
  return ivar_chain;
  return ivar_chain;
}
}
 
 
static tree
static tree
objc_create_temporary_var (tree type)
objc_create_temporary_var (tree type)
{
{
  tree decl;
  tree decl;
 
 
  decl = build_decl (input_location,
  decl = build_decl (input_location,
                     VAR_DECL, NULL_TREE, type);
                     VAR_DECL, NULL_TREE, type);
  TREE_USED (decl) = 1;
  TREE_USED (decl) = 1;
  DECL_ARTIFICIAL (decl) = 1;
  DECL_ARTIFICIAL (decl) = 1;
  DECL_IGNORED_P (decl) = 1;
  DECL_IGNORED_P (decl) = 1;
  DECL_CONTEXT (decl) = current_function_decl;
  DECL_CONTEXT (decl) = current_function_decl;
 
 
  return decl;
  return decl;
}
}


/* Exception handling constructs.  We begin by having the parser do most
/* 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
   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're doing "native" exception handling or legacy Darwin setjmp exceptions.
   We abstract all of this in a handful of appropriately named routines.  */
   We abstract all of this in a handful of appropriately named routines.  */
 
 
/* Stack of open try blocks.  */
/* Stack of open try blocks.  */
 
 
struct objc_try_context
struct objc_try_context
{
{
  struct objc_try_context *outer;
  struct objc_try_context *outer;
 
 
  /* Statements (or statement lists) as processed by the parser.  */
  /* Statements (or statement lists) as processed by the parser.  */
  tree try_body;
  tree try_body;
  tree finally_body;
  tree finally_body;
 
 
  /* Some file position locations.  */
  /* Some file position locations.  */
  location_t try_locus;
  location_t try_locus;
  location_t end_try_locus;
  location_t end_try_locus;
  location_t end_catch_locus;
  location_t end_catch_locus;
  location_t finally_locus;
  location_t finally_locus;
  location_t end_finally_locus;
  location_t end_finally_locus;
 
 
  /* A STATEMENT_LIST of CATCH_EXPRs, appropriate for sticking into op1
  /* A STATEMENT_LIST of CATCH_EXPRs, appropriate for sticking into op1
     of a TRY_CATCH_EXPR.  Even when doing Darwin setjmp.  */
     of a TRY_CATCH_EXPR.  Even when doing Darwin setjmp.  */
  tree catch_list;
  tree catch_list;
 
 
  /* The CATCH_EXPR of an open @catch clause.  */
  /* The CATCH_EXPR of an open @catch clause.  */
  tree current_catch;
  tree current_catch;
 
 
  /* The VAR_DECL holding the Darwin equivalent of __builtin_eh_pointer.  */
  /* The VAR_DECL holding the Darwin equivalent of __builtin_eh_pointer.  */
  tree caught_decl;
  tree caught_decl;
  tree stack_decl;
  tree stack_decl;
  tree rethrow_decl;
  tree rethrow_decl;
};
};
 
 
static struct objc_try_context *cur_try_context;
static struct objc_try_context *cur_try_context;
 
 
static GTY(()) tree objc_eh_personality_decl;
static GTY(()) tree objc_eh_personality_decl;
 
 
/* This hook, called via lang_eh_runtime_type, generates a runtime object
/* This hook, called via lang_eh_runtime_type, generates a runtime object
   that represents TYPE.  For Objective-C, this is just the class name.  */
   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?  */
/* ??? Isn't there a class object or some such?  Is it easy to get?  */
 
 
#ifndef OBJCPLUS
#ifndef OBJCPLUS
tree
tree
objc_eh_runtime_type (tree type)
objc_eh_runtime_type (tree type)
{
{
  return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
  return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
}
}
 
 
tree
tree
objc_eh_personality (void)
objc_eh_personality (void)
{
{
  if (!flag_objc_sjlj_exceptions
  if (!flag_objc_sjlj_exceptions
      && !objc_eh_personality_decl)
      && !objc_eh_personality_decl)
    objc_eh_personality_decl
    objc_eh_personality_decl
      = build_personality_function (USING_SJLJ_EXCEPTIONS
      = build_personality_function (USING_SJLJ_EXCEPTIONS
                                    ? "__gnu_objc_personality_sj0"
                                    ? "__gnu_objc_personality_sj0"
                                    : "__gnu_objc_personality_v0");
                                    : "__gnu_objc_personality_v0");
 
 
  return objc_eh_personality_decl;
  return objc_eh_personality_decl;
}
}
#endif
#endif
 
 
/* Build __builtin_eh_pointer, or the moral equivalent.  In the case
/* Build __builtin_eh_pointer, or the moral equivalent.  In the case
   of Darwin, we'll arrange for it to be initialized (and associated
   of Darwin, we'll arrange for it to be initialized (and associated
   with a binding) later.  */
   with a binding) later.  */
 
 
static tree
static tree
objc_build_exc_ptr (void)
objc_build_exc_ptr (void)
{
{
  if (flag_objc_sjlj_exceptions)
  if (flag_objc_sjlj_exceptions)
    {
    {
      tree var = cur_try_context->caught_decl;
      tree var = cur_try_context->caught_decl;
      if (!var)
      if (!var)
        {
        {
          var = objc_create_temporary_var (objc_object_type);
          var = objc_create_temporary_var (objc_object_type);
          cur_try_context->caught_decl = var;
          cur_try_context->caught_decl = var;
        }
        }
      return var;
      return var;
    }
    }
  else
  else
    {
    {
      tree t;
      tree t;
      t = built_in_decls[BUILT_IN_EH_POINTER];
      t = built_in_decls[BUILT_IN_EH_POINTER];
      t = build_call_expr (t, 1, integer_zero_node);
      t = build_call_expr (t, 1, integer_zero_node);
      return fold_convert (objc_object_type, t);
      return fold_convert (objc_object_type, t);
    }
    }
}
}
 
 
/* Build "objc_exception_try_exit(&_stack)".  */
/* Build "objc_exception_try_exit(&_stack)".  */
 
 
static tree
static tree
next_sjlj_build_try_exit (void)
next_sjlj_build_try_exit (void)
{
{
  tree t;
  tree t;
  t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl);
  t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl);
  t = tree_cons (NULL, t, NULL);
  t = tree_cons (NULL, t, NULL);
  t = build_function_call (input_location,
  t = build_function_call (input_location,
                           objc_exception_try_exit_decl, t);
                           objc_exception_try_exit_decl, t);
  return t;
  return t;
}
}
 
 
/* Build
/* Build
        objc_exception_try_enter (&_stack);
        objc_exception_try_enter (&_stack);
        if (_setjmp(&_stack.buf))
        if (_setjmp(&_stack.buf))
          ;
          ;
        else
        else
          ;
          ;
   Return the COND_EXPR.  Note that the THEN and ELSE fields are left
   Return the COND_EXPR.  Note that the THEN and ELSE fields are left
   empty, ready for the caller to fill them in.  */
   empty, ready for the caller to fill them in.  */
 
 
static tree
static tree
next_sjlj_build_enter_and_setjmp (void)
next_sjlj_build_enter_and_setjmp (void)
{
{
  tree t, enter, sj, cond;
  tree t, enter, sj, cond;
 
 
  t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl);
  t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl);
  t = tree_cons (NULL, t, NULL);
  t = tree_cons (NULL, t, NULL);
  enter = build_function_call (input_location,
  enter = build_function_call (input_location,
                               objc_exception_try_enter_decl, t);
                               objc_exception_try_enter_decl, t);
 
 
  t = objc_build_component_ref (cur_try_context->stack_decl,
  t = objc_build_component_ref (cur_try_context->stack_decl,
                                get_identifier ("buf"));
                                get_identifier ("buf"));
  t = build_fold_addr_expr_loc (input_location, t);
  t = build_fold_addr_expr_loc (input_location, t);
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  /* Convert _setjmp argument to type that is expected.  */
  /* Convert _setjmp argument to type that is expected.  */
  if (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl)))
  if (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl)))
    t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t);
    t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t);
  else
  else
    t = convert (ptr_type_node, t);
    t = convert (ptr_type_node, t);
#else
#else
  t = convert (ptr_type_node, t);
  t = convert (ptr_type_node, t);
#endif
#endif
  t = tree_cons (NULL, t, NULL);
  t = tree_cons (NULL, t, NULL);
  sj = build_function_call (input_location,
  sj = build_function_call (input_location,
                            objc_setjmp_decl, t);
                            objc_setjmp_decl, t);
 
 
  cond = build2 (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj);
  cond = build2 (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj);
  cond = c_common_truthvalue_conversion (input_location, cond);
  cond = c_common_truthvalue_conversion (input_location, cond);
 
 
  return build3 (COND_EXPR, void_type_node, cond, NULL, NULL);
  return build3 (COND_EXPR, void_type_node, cond, NULL, NULL);
}
}
 
 
/* Build:
/* Build:
 
 
   DECL = objc_exception_extract(&_stack);  */
   DECL = objc_exception_extract(&_stack);  */
 
 
static tree
static tree
next_sjlj_build_exc_extract (tree decl)
next_sjlj_build_exc_extract (tree decl)
{
{
  tree t;
  tree t;
 
 
  t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl);
  t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl);
  t = tree_cons (NULL, t, NULL);
  t = tree_cons (NULL, t, NULL);
  t = build_function_call (input_location,
  t = build_function_call (input_location,
                           objc_exception_extract_decl, t);
                           objc_exception_extract_decl, t);
  t = convert (TREE_TYPE (decl), t);
  t = convert (TREE_TYPE (decl), t);
  t = build2 (MODIFY_EXPR, void_type_node, decl, t);
  t = build2 (MODIFY_EXPR, void_type_node, decl, t);
 
 
  return t;
  return t;
}
}
 
 
/* Build
/* Build
        if (objc_exception_match(obj_get_class(TYPE), _caught)
        if (objc_exception_match(obj_get_class(TYPE), _caught)
          BODY
          BODY
        else if (...)
        else if (...)
          ...
          ...
        else
        else
          {
          {
            _rethrow = _caught;
            _rethrow = _caught;
            objc_exception_try_exit(&_stack);
            objc_exception_try_exit(&_stack);
          }
          }
   from the sequence of CATCH_EXPRs in the current try context.  */
   from the sequence of CATCH_EXPRs in the current try context.  */
 
 
static tree
static tree
next_sjlj_build_catch_list (void)
next_sjlj_build_catch_list (void)
{
{
  tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
  tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
  tree catch_seq, t;
  tree catch_seq, t;
  tree *last = &catch_seq;
  tree *last = &catch_seq;
  bool saw_id = false;
  bool saw_id = false;
 
 
  for (; !tsi_end_p (i); tsi_next (&i))
  for (; !tsi_end_p (i); tsi_next (&i))
    {
    {
      tree stmt = tsi_stmt (i);
      tree stmt = tsi_stmt (i);
      tree type = CATCH_TYPES (stmt);
      tree type = CATCH_TYPES (stmt);
      tree body = CATCH_BODY (stmt);
      tree body = CATCH_BODY (stmt);
 
 
      if (type == NULL)
      if (type == NULL)
        {
        {
          *last = body;
          *last = body;
          saw_id = true;
          saw_id = true;
          break;
          break;
        }
        }
      else
      else
        {
        {
          tree args, cond;
          tree args, cond;
 
 
          if (type == error_mark_node)
          if (type == error_mark_node)
            cond = error_mark_node;
            cond = error_mark_node;
          else
          else
            {
            {
              args = tree_cons (NULL, cur_try_context->caught_decl, NULL);
              args = tree_cons (NULL, cur_try_context->caught_decl, NULL);
              t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type)));
              t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type)));
              args = tree_cons (NULL, t, args);
              args = tree_cons (NULL, t, args);
              t = build_function_call (input_location,
              t = build_function_call (input_location,
                                       objc_exception_match_decl, args);
                                       objc_exception_match_decl, args);
              cond = c_common_truthvalue_conversion (input_location, t);
              cond = c_common_truthvalue_conversion (input_location, t);
            }
            }
          t = build3 (COND_EXPR, void_type_node, cond, body, NULL);
          t = build3 (COND_EXPR, void_type_node, cond, body, NULL);
          SET_EXPR_LOCATION (t, EXPR_LOCATION (stmt));
          SET_EXPR_LOCATION (t, EXPR_LOCATION (stmt));
 
 
          *last = t;
          *last = t;
          last = &COND_EXPR_ELSE (t);
          last = &COND_EXPR_ELSE (t);
        }
        }
    }
    }
 
 
  if (!saw_id)
  if (!saw_id)
    {
    {
      t = build2 (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl,
      t = build2 (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl,
                  cur_try_context->caught_decl);
                  cur_try_context->caught_decl);
      SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus);
      SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus);
      append_to_statement_list (t, last);
      append_to_statement_list (t, last);
 
 
      t = next_sjlj_build_try_exit ();
      t = next_sjlj_build_try_exit ();
      SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus);
      SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus);
      append_to_statement_list (t, last);
      append_to_statement_list (t, last);
    }
    }
 
 
  return catch_seq;
  return catch_seq;
}
}
 
 
/* Build a complete @try-@catch-@finally block for legacy Darwin setjmp
/* Build a complete @try-@catch-@finally block for legacy Darwin setjmp
   exception handling.  We aim to build:
   exception handling.  We aim to build:
 
 
        {
        {
          struct _objc_exception_data _stack;
          struct _objc_exception_data _stack;
          id _rethrow = 0;
          id _rethrow = 0;
          try
          try
            {
            {
              objc_exception_try_enter (&_stack);
              objc_exception_try_enter (&_stack);
              if (_setjmp(&_stack.buf))
              if (_setjmp(&_stack.buf))
                {
                {
                  id _caught = objc_exception_extract(&_stack);
                  id _caught = objc_exception_extract(&_stack);
                  objc_exception_try_enter (&_stack);
                  objc_exception_try_enter (&_stack);
                  if (_setjmp(&_stack.buf))
                  if (_setjmp(&_stack.buf))
                    _rethrow = objc_exception_extract(&_stack);
                    _rethrow = objc_exception_extract(&_stack);
                  else
                  else
                    CATCH-LIST
                    CATCH-LIST
                }
                }
              else
              else
                TRY-BLOCK
                TRY-BLOCK
            }
            }
          finally
          finally
            {
            {
              if (!_rethrow)
              if (!_rethrow)
                objc_exception_try_exit(&_stack);
                objc_exception_try_exit(&_stack);
              FINALLY-BLOCK
              FINALLY-BLOCK
              if (_rethrow)
              if (_rethrow)
                objc_exception_throw(_rethrow);
                objc_exception_throw(_rethrow);
            }
            }
        }
        }
 
 
   If CATCH-LIST is empty, we can omit all of the block containing
   If CATCH-LIST is empty, we can omit all of the block containing
   "_caught" except for the setting of _rethrow.  Note the use of
   "_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,
   a real TRY_FINALLY_EXPR here, which is not involved in EH per-se,
   but handles goto and other exits from the block.  */
   but handles goto and other exits from the block.  */
 
 
static tree
static tree
next_sjlj_build_try_catch_finally (void)
next_sjlj_build_try_catch_finally (void)
{
{
  tree rethrow_decl, stack_decl, t;
  tree rethrow_decl, stack_decl, t;
  tree catch_seq, try_fin, bind;
  tree catch_seq, try_fin, bind;
 
 
  /* Create the declarations involved.  */
  /* Create the declarations involved.  */
  t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
  t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
  stack_decl = objc_create_temporary_var (t);
  stack_decl = objc_create_temporary_var (t);
  cur_try_context->stack_decl = stack_decl;
  cur_try_context->stack_decl = stack_decl;
 
 
  rethrow_decl = objc_create_temporary_var (objc_object_type);
  rethrow_decl = objc_create_temporary_var (objc_object_type);
  cur_try_context->rethrow_decl = rethrow_decl;
  cur_try_context->rethrow_decl = rethrow_decl;
  TREE_CHAIN (rethrow_decl) = stack_decl;
  TREE_CHAIN (rethrow_decl) = stack_decl;
 
 
  /* Build the outermost variable binding level.  */
  /* Build the outermost variable binding level.  */
  bind = build3 (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL);
  bind = build3 (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL);
  SET_EXPR_LOCATION (bind, cur_try_context->try_locus);
  SET_EXPR_LOCATION (bind, cur_try_context->try_locus);
  TREE_SIDE_EFFECTS (bind) = 1;
  TREE_SIDE_EFFECTS (bind) = 1;
 
 
  /* Initialize rethrow_decl.  */
  /* Initialize rethrow_decl.  */
  t = build2 (MODIFY_EXPR, void_type_node, rethrow_decl,
  t = build2 (MODIFY_EXPR, void_type_node, rethrow_decl,
              convert (objc_object_type, null_pointer_node));
              convert (objc_object_type, null_pointer_node));
  SET_EXPR_LOCATION (t, cur_try_context->try_locus);
  SET_EXPR_LOCATION (t, cur_try_context->try_locus);
  append_to_statement_list (t, &BIND_EXPR_BODY (bind));
  append_to_statement_list (t, &BIND_EXPR_BODY (bind));
 
 
  /* Build the outermost TRY_FINALLY_EXPR.  */
  /* Build the outermost TRY_FINALLY_EXPR.  */
  try_fin = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
  try_fin = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
  SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus);
  SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus);
  TREE_SIDE_EFFECTS (try_fin) = 1;
  TREE_SIDE_EFFECTS (try_fin) = 1;
  append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind));
  append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind));
 
 
  /* Create the complete catch sequence.  */
  /* Create the complete catch sequence.  */
  if (cur_try_context->catch_list)
  if (cur_try_context->catch_list)
    {
    {
      tree caught_decl = objc_build_exc_ptr ();
      tree caught_decl = objc_build_exc_ptr ();
      catch_seq = build_stmt (input_location, BIND_EXPR, caught_decl, NULL, NULL);
      catch_seq = build_stmt (input_location, BIND_EXPR, caught_decl, NULL, NULL);
      TREE_SIDE_EFFECTS (catch_seq) = 1;
      TREE_SIDE_EFFECTS (catch_seq) = 1;
 
 
      t = next_sjlj_build_exc_extract (caught_decl);
      t = next_sjlj_build_exc_extract (caught_decl);
      append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
      append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
 
 
      t = next_sjlj_build_enter_and_setjmp ();
      t = next_sjlj_build_enter_and_setjmp ();
      COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (rethrow_decl);
      COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (rethrow_decl);
      COND_EXPR_ELSE (t) = next_sjlj_build_catch_list ();
      COND_EXPR_ELSE (t) = next_sjlj_build_catch_list ();
      append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
      append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
    }
    }
  else
  else
    catch_seq = next_sjlj_build_exc_extract (rethrow_decl);
    catch_seq = next_sjlj_build_exc_extract (rethrow_decl);
  SET_EXPR_LOCATION (catch_seq, cur_try_context->end_try_locus);
  SET_EXPR_LOCATION (catch_seq, cur_try_context->end_try_locus);
 
 
  /* Build the main register-and-try if statement.  */
  /* Build the main register-and-try if statement.  */
  t = next_sjlj_build_enter_and_setjmp ();
  t = next_sjlj_build_enter_and_setjmp ();
  SET_EXPR_LOCATION (t, cur_try_context->try_locus);
  SET_EXPR_LOCATION (t, cur_try_context->try_locus);
  COND_EXPR_THEN (t) = catch_seq;
  COND_EXPR_THEN (t) = catch_seq;
  COND_EXPR_ELSE (t) = cur_try_context->try_body;
  COND_EXPR_ELSE (t) = cur_try_context->try_body;
  TREE_OPERAND (try_fin, 0) = t;
  TREE_OPERAND (try_fin, 0) = t;
 
 
  /* Build the complete FINALLY statement list.  */
  /* Build the complete FINALLY statement list.  */
  t = next_sjlj_build_try_exit ();
  t = next_sjlj_build_try_exit ();
  t = build_stmt (input_location, COND_EXPR,
  t = build_stmt (input_location, COND_EXPR,
                  c_common_truthvalue_conversion
                  c_common_truthvalue_conversion
                    (input_location, rethrow_decl),
                    (input_location, rethrow_decl),
                  NULL, t);
                  NULL, t);
  SET_EXPR_LOCATION (t, cur_try_context->finally_locus);
  SET_EXPR_LOCATION (t, cur_try_context->finally_locus);
  append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
  append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
 
 
  append_to_statement_list (cur_try_context->finally_body,
  append_to_statement_list (cur_try_context->finally_body,
                            &TREE_OPERAND (try_fin, 1));
                            &TREE_OPERAND (try_fin, 1));
 
 
  t = tree_cons (NULL, rethrow_decl, NULL);
  t = tree_cons (NULL, rethrow_decl, NULL);
  t = build_function_call (input_location,
  t = build_function_call (input_location,
                           objc_exception_throw_decl, t);
                           objc_exception_throw_decl, t);
  t = build_stmt (input_location, COND_EXPR,
  t = build_stmt (input_location, COND_EXPR,
                  c_common_truthvalue_conversion (input_location,
                  c_common_truthvalue_conversion (input_location,
                                                  rethrow_decl),
                                                  rethrow_decl),
                  t, NULL);
                  t, NULL);
  SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus);
  SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus);
  append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
  append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
 
 
  return bind;
  return bind;
}
}
 
 
/* Called just after parsing the @try and its associated BODY.  We now
/* Called just after parsing the @try and its associated BODY.  We now
   must prepare for the tricky bits -- handling the catches and finally.  */
   must prepare for the tricky bits -- handling the catches and finally.  */
 
 
void
void
objc_begin_try_stmt (location_t try_locus, tree body)
objc_begin_try_stmt (location_t try_locus, tree body)
{
{
  struct objc_try_context *c = XCNEW (struct objc_try_context);
  struct objc_try_context *c = XCNEW (struct objc_try_context);
  c->outer = cur_try_context;
  c->outer = cur_try_context;
  c->try_body = body;
  c->try_body = body;
  c->try_locus = try_locus;
  c->try_locus = try_locus;
  c->end_try_locus = input_location;
  c->end_try_locus = input_location;
  cur_try_context = c;
  cur_try_context = c;
 
 
  if (flag_objc_sjlj_exceptions)
  if (flag_objc_sjlj_exceptions)
    {
    {
      /* On Darwin, ObjC exceptions require a sufficiently recent
      /* On Darwin, ObjC exceptions require a sufficiently recent
         version of the runtime, so the user must ask for them explicitly.  */
         version of the runtime, so the user must ask for them explicitly.  */
      if (!flag_objc_exceptions)
      if (!flag_objc_exceptions)
        warning (0, "use %<-fobjc-exceptions%> to enable Objective-C "
        warning (0, "use %<-fobjc-exceptions%> to enable Objective-C "
                 "exception syntax");
                 "exception syntax");
    }
    }
 
 
  if (flag_objc_sjlj_exceptions)
  if (flag_objc_sjlj_exceptions)
    objc_mark_locals_volatile (NULL);
    objc_mark_locals_volatile (NULL);
}
}
 
 
/* Called just after parsing "@catch (parm)".  Open a binding level,
/* Called just after parsing "@catch (parm)".  Open a binding level,
   enter DECL into the binding level, and initialize it.  Leave the
   enter DECL into the binding level, and initialize it.  Leave the
   binding level open while the body of the compound statement is parsed.  */
   binding level open while the body of the compound statement is parsed.  */
 
 
void
void
objc_begin_catch_clause (tree decl)
objc_begin_catch_clause (tree decl)
{
{
  tree compound, type, t;
  tree compound, type, t;
 
 
  /* Begin a new scope that the entire catch clause will live in.  */
  /* Begin a new scope that the entire catch clause will live in.  */
  compound = c_begin_compound_stmt (true);
  compound = c_begin_compound_stmt (true);
 
 
  /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL.  */
  /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL.  */
  decl = build_decl (input_location,
  decl = build_decl (input_location,
                     VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
                     VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
  lang_hooks.decls.pushdecl (decl);
  lang_hooks.decls.pushdecl (decl);
 
 
  /* Since a decl is required here by syntax, don't warn if its unused.  */
  /* Since a decl is required here by syntax, don't warn if its unused.  */
  /* ??? As opposed to __attribute__((unused))?  Anyway, this appears to
  /* ??? As opposed to __attribute__((unused))?  Anyway, this appears to
     be what the previous objc implementation did.  */
     be what the previous objc implementation did.  */
  TREE_USED (decl) = 1;
  TREE_USED (decl) = 1;
 
 
  /* Verify that the type of the catch is valid.  It must be a pointer
  /* 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).  */
     to an Objective-C class, or "id" (which is catch-all).  */
  type = TREE_TYPE (decl);
  type = TREE_TYPE (decl);
 
 
  if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
  if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
    type = NULL;
    type = NULL;
  else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type)))
  else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type)))
    {
    {
      error ("@catch parameter is not a known Objective-C class type");
      error ("@catch parameter is not a known Objective-C class type");
      type = error_mark_node;
      type = error_mark_node;
    }
    }
  else if (cur_try_context->catch_list)
  else if (cur_try_context->catch_list)
    {
    {
      /* Examine previous @catch clauses and see if we've already
      /* Examine previous @catch clauses and see if we've already
         caught the type in question.  */
         caught the type in question.  */
      tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
      tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
      for (; !tsi_end_p (i); tsi_next (&i))
      for (; !tsi_end_p (i); tsi_next (&i))
        {
        {
          tree stmt = tsi_stmt (i);
          tree stmt = tsi_stmt (i);
          t = CATCH_TYPES (stmt);
          t = CATCH_TYPES (stmt);
          if (t == error_mark_node)
          if (t == error_mark_node)
            continue;
            continue;
          if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
          if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
            {
            {
              warning (0, "exception of type %<%T%> will be caught",
              warning (0, "exception of type %<%T%> will be caught",
                       TREE_TYPE (type));
                       TREE_TYPE (type));
              warning_at  (EXPR_LOCATION (stmt), 0, "   by earlier handler for %<%T%>",
              warning_at  (EXPR_LOCATION (stmt), 0, "   by earlier handler for %<%T%>",
                           TREE_TYPE (t ? t : objc_object_type));
                           TREE_TYPE (t ? t : objc_object_type));
              break;
              break;
            }
            }
        }
        }
    }
    }
 
 
  /* Record the data for the catch in the try context so that we can
  /* Record the data for the catch in the try context so that we can
     finalize it later.  */
     finalize it later.  */
  t = build_stmt (input_location, CATCH_EXPR, type, compound);
  t = build_stmt (input_location, CATCH_EXPR, type, compound);
  cur_try_context->current_catch = t;
  cur_try_context->current_catch = t;
 
 
  /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime.  */
  /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime.  */
  t = objc_build_exc_ptr ();
  t = objc_build_exc_ptr ();
  t = convert (TREE_TYPE (decl), t);
  t = convert (TREE_TYPE (decl), t);
  t = build2 (MODIFY_EXPR, void_type_node, decl, t);
  t = build2 (MODIFY_EXPR, void_type_node, decl, t);
  add_stmt (t);
  add_stmt (t);
}
}
 
 
/* Called just after parsing the closing brace of a @catch clause.  Close
/* Called just after parsing the closing brace of a @catch clause.  Close
   the open binding level, and record a CATCH_EXPR for it.  */
   the open binding level, and record a CATCH_EXPR for it.  */
 
 
void
void
objc_finish_catch_clause (void)
objc_finish_catch_clause (void)
{
{
  tree c = cur_try_context->current_catch;
  tree c = cur_try_context->current_catch;
  cur_try_context->current_catch = NULL;
  cur_try_context->current_catch = NULL;
  cur_try_context->end_catch_locus = input_location;
  cur_try_context->end_catch_locus = input_location;
 
 
  CATCH_BODY (c) = c_end_compound_stmt (input_location, CATCH_BODY (c), 1);
  CATCH_BODY (c) = c_end_compound_stmt (input_location, CATCH_BODY (c), 1);
  append_to_statement_list (c, &cur_try_context->catch_list);
  append_to_statement_list (c, &cur_try_context->catch_list);
}
}
 
 
/* Called after parsing a @finally clause and its associated BODY.
/* Called after parsing a @finally clause and its associated BODY.
   Record the body for later placement.  */
   Record the body for later placement.  */
 
 
void
void
objc_build_finally_clause (location_t finally_locus, tree body)
objc_build_finally_clause (location_t finally_locus, tree body)
{
{
  cur_try_context->finally_body = body;
  cur_try_context->finally_body = body;
  cur_try_context->finally_locus = finally_locus;
  cur_try_context->finally_locus = finally_locus;
  cur_try_context->end_finally_locus = input_location;
  cur_try_context->end_finally_locus = input_location;
}
}
 
 
/* Called to finalize a @try construct.  */
/* Called to finalize a @try construct.  */
 
 
tree
tree
objc_finish_try_stmt (void)
objc_finish_try_stmt (void)
{
{
  struct objc_try_context *c = cur_try_context;
  struct objc_try_context *c = cur_try_context;
  tree stmt;
  tree stmt;
 
 
  if (c->catch_list == NULL && c->finally_body == NULL)
  if (c->catch_list == NULL && c->finally_body == NULL)
    error ("%<@try%> without %<@catch%> or %<@finally%>");
    error ("%<@try%> without %<@catch%> or %<@finally%>");
 
 
  /* If we're doing Darwin setjmp exceptions, build the big nasty.  */
  /* If we're doing Darwin setjmp exceptions, build the big nasty.  */
  if (flag_objc_sjlj_exceptions)
  if (flag_objc_sjlj_exceptions)
    {
    {
      bool save = in_late_binary_op;
      bool save = in_late_binary_op;
      in_late_binary_op = true;
      in_late_binary_op = true;
      if (!cur_try_context->finally_body)
      if (!cur_try_context->finally_body)
        {
        {
          cur_try_context->finally_locus = input_location;
          cur_try_context->finally_locus = input_location;
          cur_try_context->end_finally_locus = input_location;
          cur_try_context->end_finally_locus = input_location;
        }
        }
      stmt = next_sjlj_build_try_catch_finally ();
      stmt = next_sjlj_build_try_catch_finally ();
      in_late_binary_op = save;
      in_late_binary_op = save;
    }
    }
  else
  else
    {
    {
      /* Otherwise, nest the CATCH inside a FINALLY.  */
      /* Otherwise, nest the CATCH inside a FINALLY.  */
      stmt = c->try_body;
      stmt = c->try_body;
      if (c->catch_list)
      if (c->catch_list)
        {
        {
          stmt = build_stmt (input_location, TRY_CATCH_EXPR, stmt, c->catch_list);
          stmt = build_stmt (input_location, TRY_CATCH_EXPR, stmt, c->catch_list);
          SET_EXPR_LOCATION (stmt, cur_try_context->try_locus);
          SET_EXPR_LOCATION (stmt, cur_try_context->try_locus);
        }
        }
      if (c->finally_body)
      if (c->finally_body)
        {
        {
          stmt = build_stmt (input_location, TRY_FINALLY_EXPR, stmt, c->finally_body);
          stmt = build_stmt (input_location, TRY_FINALLY_EXPR, stmt, c->finally_body);
          SET_EXPR_LOCATION (stmt, cur_try_context->try_locus);
          SET_EXPR_LOCATION (stmt, cur_try_context->try_locus);
        }
        }
    }
    }
  add_stmt (stmt);
  add_stmt (stmt);
 
 
  cur_try_context = c->outer;
  cur_try_context = c->outer;
  free (c);
  free (c);
  return stmt;
  return stmt;
}
}
 
 
tree
tree
objc_build_throw_stmt (location_t loc, tree throw_expr)
objc_build_throw_stmt (location_t loc, tree throw_expr)
{
{
  tree args;
  tree args;
 
 
  if (flag_objc_sjlj_exceptions)
  if (flag_objc_sjlj_exceptions)
    {
    {
      /* On Darwin, ObjC exceptions require a sufficiently recent
      /* On Darwin, ObjC exceptions require a sufficiently recent
         version of the runtime, so the user must ask for them explicitly.  */
         version of the runtime, so the user must ask for them explicitly.  */
      if (!flag_objc_exceptions)
      if (!flag_objc_exceptions)
        warning (0, "use %<-fobjc-exceptions%> to enable Objective-C "
        warning (0, "use %<-fobjc-exceptions%> to enable Objective-C "
                 "exception syntax");
                 "exception syntax");
    }
    }
 
 
  if (throw_expr == NULL)
  if (throw_expr == NULL)
    {
    {
      /* If we're not inside a @catch block, there is no "current
      /* If we're not inside a @catch block, there is no "current
         exception" to be rethrown.  */
         exception" to be rethrown.  */
      if (cur_try_context == NULL
      if (cur_try_context == NULL
          || cur_try_context->current_catch == NULL)
          || cur_try_context->current_catch == NULL)
        {
        {
          error_at (loc, "%<@throw%> (rethrow) used outside of a @catch block");
          error_at (loc, "%<@throw%> (rethrow) used outside of a @catch block");
          return NULL_TREE;
          return NULL_TREE;
        }
        }
 
 
      /* Otherwise the object is still sitting in the EXC_PTR_EXPR
      /* Otherwise the object is still sitting in the EXC_PTR_EXPR
         value that we get from the runtime.  */
         value that we get from the runtime.  */
      throw_expr = objc_build_exc_ptr ();
      throw_expr = objc_build_exc_ptr ();
    }
    }
 
 
  /* A throw is just a call to the runtime throw function with the
  /* A throw is just a call to the runtime throw function with the
     object as a parameter.  */
     object as a parameter.  */
  args = tree_cons (NULL, throw_expr, NULL);
  args = tree_cons (NULL, throw_expr, NULL);
  return add_stmt (build_function_call (loc,
  return add_stmt (build_function_call (loc,
                                        objc_exception_throw_decl, args));
                                        objc_exception_throw_decl, args));
}
}
 
 
tree
tree
objc_build_synchronized (location_t start_locus, tree mutex, tree body)
objc_build_synchronized (location_t start_locus, tree mutex, tree body)
{
{
  tree args, call;
  tree args, call;
 
 
  /* First lock the mutex.  */
  /* First lock the mutex.  */
  mutex = save_expr (mutex);
  mutex = save_expr (mutex);
  args = tree_cons (NULL, mutex, NULL);
  args = tree_cons (NULL, mutex, NULL);
  call = build_function_call (input_location,
  call = build_function_call (input_location,
                              objc_sync_enter_decl, args);
                              objc_sync_enter_decl, args);
  SET_EXPR_LOCATION (call, start_locus);
  SET_EXPR_LOCATION (call, start_locus);
  add_stmt (call);
  add_stmt (call);
 
 
  /* Build the mutex unlock.  */
  /* Build the mutex unlock.  */
  args = tree_cons (NULL, mutex, NULL);
  args = tree_cons (NULL, mutex, NULL);
  call = build_function_call (input_location,
  call = build_function_call (input_location,
                              objc_sync_exit_decl, args);
                              objc_sync_exit_decl, args);
  SET_EXPR_LOCATION (call, input_location);
  SET_EXPR_LOCATION (call, input_location);
 
 
  /* Put the that and the body in a TRY_FINALLY.  */
  /* Put the that and the body in a TRY_FINALLY.  */
  objc_begin_try_stmt (start_locus, body);
  objc_begin_try_stmt (start_locus, body);
  objc_build_finally_clause (input_location, call);
  objc_build_finally_clause (input_location, call);
  return objc_finish_try_stmt ();
  return objc_finish_try_stmt ();
}
}
 
 


/* Predefine the following data type:
/* Predefine the following data type:
 
 
   struct _objc_exception_data
   struct _objc_exception_data
   {
   {
     int buf[OBJC_JBLEN];
     int buf[OBJC_JBLEN];
     void *pointers[4];
     void *pointers[4];
   }; */
   }; */
 
 
/* The following yuckiness should prevent users from having to #include
/* The following yuckiness should prevent users from having to #include
   <setjmp.h> in their code... */
   <setjmp.h> in their code... */
 
 
/* Define to a harmless positive value so the below code doesn't die.  */
/* Define to a harmless positive value so the below code doesn't die.  */
#ifndef OBJC_JBLEN
#ifndef OBJC_JBLEN
#define OBJC_JBLEN 18
#define OBJC_JBLEN 18
#endif
#endif
 
 
static void
static void
build_next_objc_exception_stuff (void)
build_next_objc_exception_stuff (void)
{
{
  tree field_decl, field_decl_chain, index, temp_type;
  tree field_decl, field_decl_chain, index, temp_type;
 
 
  objc_exception_data_template
  objc_exception_data_template
    = objc_start_struct (get_identifier (UTAG_EXCDATA));
    = objc_start_struct (get_identifier (UTAG_EXCDATA));
 
 
  /* int buf[OBJC_JBLEN]; */
  /* int buf[OBJC_JBLEN]; */
 
 
  index = build_index_type (build_int_cst (NULL_TREE, OBJC_JBLEN - 1));
  index = build_index_type (build_int_cst (NULL_TREE, OBJC_JBLEN - 1));
  field_decl = create_field_decl (build_array_type (integer_type_node, index),
  field_decl = create_field_decl (build_array_type (integer_type_node, index),
                                  "buf");
                                  "buf");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* void *pointers[4]; */
  /* void *pointers[4]; */
 
 
  index = build_index_type (build_int_cst (NULL_TREE, 4 - 1));
  index = build_index_type (build_int_cst (NULL_TREE, 4 - 1));
  field_decl = create_field_decl (build_array_type (ptr_type_node, index),
  field_decl = create_field_decl (build_array_type (ptr_type_node, index),
                                  "pointers");
                                  "pointers");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_exception_data_template, field_decl_chain);
  objc_finish_struct (objc_exception_data_template, field_decl_chain);
 
 
  /* int _setjmp(...); */
  /* int _setjmp(...); */
  /* If the user includes <setjmp.h>, this shall be superseded by
  /* If the user includes <setjmp.h>, this shall be superseded by
     'int _setjmp(jmp_buf);' */
     'int _setjmp(jmp_buf);' */
  temp_type = build_function_type (integer_type_node, NULL_TREE);
  temp_type = build_function_type (integer_type_node, NULL_TREE);
  objc_setjmp_decl
  objc_setjmp_decl
    = add_builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
    = add_builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
 
 
  /* id objc_exception_extract(struct _objc_exception_data *); */
  /* id objc_exception_extract(struct _objc_exception_data *); */
  temp_type
  temp_type
    = build_function_type (objc_object_type,
    = build_function_type (objc_object_type,
                           tree_cons (NULL_TREE,
                           tree_cons (NULL_TREE,
                                      build_pointer_type (objc_exception_data_template),
                                      build_pointer_type (objc_exception_data_template),
                                      OBJC_VOID_AT_END));
                                      OBJC_VOID_AT_END));
  objc_exception_extract_decl
  objc_exception_extract_decl
    = add_builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL,
    = add_builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL,
                            NULL_TREE);
                            NULL_TREE);
  /* void objc_exception_try_enter(struct _objc_exception_data *); */
  /* void objc_exception_try_enter(struct _objc_exception_data *); */
  /* void objc_exception_try_exit(struct _objc_exception_data *); */
  /* void objc_exception_try_exit(struct _objc_exception_data *); */
  temp_type
  temp_type
    = build_function_type (void_type_node,
    = build_function_type (void_type_node,
                           tree_cons (NULL_TREE,
                           tree_cons (NULL_TREE,
                                      build_pointer_type (objc_exception_data_template),
                                      build_pointer_type (objc_exception_data_template),
                                      OBJC_VOID_AT_END));
                                      OBJC_VOID_AT_END));
  objc_exception_try_enter_decl
  objc_exception_try_enter_decl
    = add_builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL,
    = add_builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL,
                            NULL_TREE);
                            NULL_TREE);
  objc_exception_try_exit_decl
  objc_exception_try_exit_decl
    = add_builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL,
    = add_builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL,
                            NULL_TREE);
                            NULL_TREE);
 
 
  /* int objc_exception_match(id, id); */
  /* int objc_exception_match(id, id); */
  temp_type
  temp_type
    = build_function_type (integer_type_node,
    = build_function_type (integer_type_node,
                           tree_cons (NULL_TREE, objc_object_type,
                           tree_cons (NULL_TREE, objc_object_type,
                                      tree_cons (NULL_TREE, objc_object_type,
                                      tree_cons (NULL_TREE, objc_object_type,
                                                 OBJC_VOID_AT_END)));
                                                 OBJC_VOID_AT_END)));
  objc_exception_match_decl
  objc_exception_match_decl
    = add_builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL,
    = add_builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL,
                            NULL_TREE);
                            NULL_TREE);
 
 
  /* id objc_assign_ivar (id, id, unsigned int); */
  /* id objc_assign_ivar (id, id, unsigned int); */
  /* id objc_assign_ivar_Fast (id, id, unsigned int)
  /* id objc_assign_ivar_Fast (id, id, unsigned int)
       __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */
       __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */
  temp_type
  temp_type
    = build_function_type (objc_object_type,
    = build_function_type (objc_object_type,
                           tree_cons
                           tree_cons
                           (NULL_TREE, objc_object_type,
                           (NULL_TREE, objc_object_type,
                            tree_cons (NULL_TREE, objc_object_type,
                            tree_cons (NULL_TREE, objc_object_type,
                                       tree_cons (NULL_TREE,
                                       tree_cons (NULL_TREE,
                                                  unsigned_type_node,
                                                  unsigned_type_node,
                                                  OBJC_VOID_AT_END))));
                                                  OBJC_VOID_AT_END))));
  objc_assign_ivar_decl
  objc_assign_ivar_decl
    = add_builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN,
    = add_builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN,
                            NULL, NULL_TREE);
                            NULL, NULL_TREE);
#ifdef OFFS_ASSIGNIVAR_FAST
#ifdef OFFS_ASSIGNIVAR_FAST
  objc_assign_ivar_fast_decl
  objc_assign_ivar_fast_decl
    = add_builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0,
    = add_builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0,
                            NOT_BUILT_IN, NULL, NULL_TREE);
                            NOT_BUILT_IN, NULL, NULL_TREE);
  DECL_ATTRIBUTES (objc_assign_ivar_fast_decl)
  DECL_ATTRIBUTES (objc_assign_ivar_fast_decl)
    = tree_cons (get_identifier ("hard_coded_address"),
    = tree_cons (get_identifier ("hard_coded_address"),
                 build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST),
                 build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST),
                 NULL_TREE);
                 NULL_TREE);
#else
#else
  /* Default to slower ivar method.  */
  /* Default to slower ivar method.  */
  objc_assign_ivar_fast_decl = objc_assign_ivar_decl;
  objc_assign_ivar_fast_decl = objc_assign_ivar_decl;
#endif
#endif
 
 
  /* id objc_assign_global (id, id *); */
  /* id objc_assign_global (id, id *); */
  /* id objc_assign_strongCast (id, id *); */
  /* id objc_assign_strongCast (id, id *); */
  temp_type = build_function_type (objc_object_type,
  temp_type = build_function_type (objc_object_type,
                tree_cons (NULL_TREE, objc_object_type,
                tree_cons (NULL_TREE, objc_object_type,
                    tree_cons (NULL_TREE, build_pointer_type (objc_object_type),
                    tree_cons (NULL_TREE, build_pointer_type (objc_object_type),
                        OBJC_VOID_AT_END)));
                        OBJC_VOID_AT_END)));
  objc_assign_global_decl
  objc_assign_global_decl
        = add_builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL,
        = add_builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL,
                                NULL_TREE);
                                NULL_TREE);
  objc_assign_strong_cast_decl
  objc_assign_strong_cast_decl
        = add_builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL,
        = add_builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL,
                                NULL_TREE);
                                NULL_TREE);
}
}
 
 
static void
static void
build_objc_exception_stuff (void)
build_objc_exception_stuff (void)
{
{
  tree noreturn_list, nothrow_list, temp_type;
  tree noreturn_list, nothrow_list, temp_type;
 
 
  noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL);
  noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL);
  nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL);
  nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL);
 
 
  /* void objc_exception_throw(id) __attribute__((noreturn)); */
  /* void objc_exception_throw(id) __attribute__((noreturn)); */
  /* void objc_sync_enter(id); */
  /* void objc_sync_enter(id); */
  /* void objc_sync_exit(id); */
  /* void objc_sync_exit(id); */
  temp_type = build_function_type (void_type_node,
  temp_type = build_function_type (void_type_node,
                                   tree_cons (NULL_TREE, objc_object_type,
                                   tree_cons (NULL_TREE, objc_object_type,
                                              OBJC_VOID_AT_END));
                                              OBJC_VOID_AT_END));
  objc_exception_throw_decl
  objc_exception_throw_decl
    = add_builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL,
    = add_builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL,
                            noreturn_list);
                            noreturn_list);
  objc_sync_enter_decl
  objc_sync_enter_decl
    = add_builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN,
    = add_builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN,
                            NULL, nothrow_list);
                            NULL, nothrow_list);
  objc_sync_exit_decl
  objc_sync_exit_decl
    = add_builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN,
    = add_builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN,
                            NULL, nothrow_list);
                            NULL, nothrow_list);
}
}
 
 
/* Construct a C struct corresponding to ObjC class CLASS, with the same
/* Construct a C struct corresponding to ObjC class CLASS, with the same
   name as the class:
   name as the class:
 
 
   struct <classname> {
   struct <classname> {
     struct _objc_class *isa;
     struct _objc_class *isa;
     ...
     ...
   };  */
   };  */
 
 
static void
static void
build_private_template (tree klass)
build_private_template (tree klass)
{
{
  if (!CLASS_STATIC_TEMPLATE (klass))
  if (!CLASS_STATIC_TEMPLATE (klass))
    {
    {
      tree record = objc_build_struct (klass,
      tree record = objc_build_struct (klass,
                                       get_class_ivars (klass, false),
                                       get_class_ivars (klass, false),
                                       CLASS_SUPER_NAME (klass));
                                       CLASS_SUPER_NAME (klass));
 
 
      /* Set the TREE_USED bit for this struct, so that stab generator
      /* Set the TREE_USED bit for this struct, so that stab generator
         can emit stabs for this struct type.  */
         can emit stabs for this struct type.  */
      if (flag_debug_only_used_symbols && TYPE_STUB_DECL (record))
      if (flag_debug_only_used_symbols && TYPE_STUB_DECL (record))
        TREE_USED (TYPE_STUB_DECL (record)) = 1;
        TREE_USED (TYPE_STUB_DECL (record)) = 1;
    }
    }
}
}


/* Begin code generation for protocols...  */
/* Begin code generation for protocols...  */
 
 
/* struct _objc_protocol {
/* struct _objc_protocol {
     struct _objc_class *isa;
     struct _objc_class *isa;
     char *protocol_name;
     char *protocol_name;
     struct _objc_protocol **protocol_list;
     struct _objc_protocol **protocol_list;
     struct _objc__method_prototype_list *instance_methods;
     struct _objc__method_prototype_list *instance_methods;
     struct _objc__method_prototype_list *class_methods;
     struct _objc__method_prototype_list *class_methods;
   };  */
   };  */
 
 
static void
static void
build_protocol_template (void)
build_protocol_template (void)
{
{
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL));
  objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL));
 
 
  /* struct _objc_class *isa; */
  /* struct _objc_class *isa; */
  field_decl = create_field_decl (build_pointer_type
  field_decl = create_field_decl (build_pointer_type
                                  (xref_tag (RECORD_TYPE,
                                  (xref_tag (RECORD_TYPE,
                                             get_identifier (UTAG_CLASS))),
                                             get_identifier (UTAG_CLASS))),
                                  "isa");
                                  "isa");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* char *protocol_name; */
  /* char *protocol_name; */
  field_decl = create_field_decl (string_type_node, "protocol_name");
  field_decl = create_field_decl (string_type_node, "protocol_name");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc_protocol **protocol_list; */
  /* struct _objc_protocol **protocol_list; */
  field_decl = create_field_decl (build_pointer_type
  field_decl = create_field_decl (build_pointer_type
                                  (build_pointer_type
                                  (build_pointer_type
                                   (objc_protocol_template)),
                                   (objc_protocol_template)),
                                  "protocol_list");
                                  "protocol_list");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc__method_prototype_list *instance_methods; */
  /* struct _objc__method_prototype_list *instance_methods; */
  field_decl = create_field_decl (objc_method_proto_list_ptr,
  field_decl = create_field_decl (objc_method_proto_list_ptr,
                                  "instance_methods");
                                  "instance_methods");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc__method_prototype_list *class_methods; */
  /* struct _objc__method_prototype_list *class_methods; */
  field_decl = create_field_decl (objc_method_proto_list_ptr,
  field_decl = create_field_decl (objc_method_proto_list_ptr,
                                  "class_methods");
                                  "class_methods");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_protocol_template, field_decl_chain);
  objc_finish_struct (objc_protocol_template, field_decl_chain);
}
}
 
 
static tree
static tree
build_descriptor_table_initializer (tree type, tree entries)
build_descriptor_table_initializer (tree type, tree entries)
{
{
  tree initlist = NULL_TREE;
  tree initlist = NULL_TREE;
 
 
  do
  do
    {
    {
      tree eltlist = NULL_TREE;
      tree eltlist = NULL_TREE;
 
 
      eltlist
      eltlist
        = tree_cons (NULL_TREE,
        = tree_cons (NULL_TREE,
                     build_selector (METHOD_SEL_NAME (entries)), NULL_TREE);
                     build_selector (METHOD_SEL_NAME (entries)), NULL_TREE);
      eltlist
      eltlist
        = tree_cons (NULL_TREE,
        = tree_cons (NULL_TREE,
                     add_objc_string (METHOD_ENCODING (entries),
                     add_objc_string (METHOD_ENCODING (entries),
                                      meth_var_types),
                                      meth_var_types),
                     eltlist);
                     eltlist);
 
 
      initlist
      initlist
        = tree_cons (NULL_TREE,
        = tree_cons (NULL_TREE,
                     objc_build_constructor (type, nreverse (eltlist)),
                     objc_build_constructor (type, nreverse (eltlist)),
                     initlist);
                     initlist);
 
 
      entries = TREE_CHAIN (entries);
      entries = TREE_CHAIN (entries);
    }
    }
  while (entries);
  while (entries);
 
 
  return objc_build_constructor (build_array_type (type, 0),
  return objc_build_constructor (build_array_type (type, 0),
                                 nreverse (initlist));
                                 nreverse (initlist));
}
}
 
 
/* struct objc_method_prototype_list {
/* struct objc_method_prototype_list {
     int count;
     int count;
     struct objc_method_prototype {
     struct objc_method_prototype {
        SEL name;
        SEL name;
        char *types;
        char *types;
     } list[1];
     } list[1];
   };  */
   };  */
 
 
static tree
static tree
build_method_prototype_list_template (tree list_type, int size)
build_method_prototype_list_template (tree list_type, int size)
{
{
  tree objc_ivar_list_record;
  tree objc_ivar_list_record;
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  /* Generate an unnamed struct definition.  */
  /* Generate an unnamed struct definition.  */
 
 
  objc_ivar_list_record = objc_start_struct (NULL_TREE);
  objc_ivar_list_record = objc_start_struct (NULL_TREE);
 
 
  /* int method_count; */
  /* int method_count; */
  field_decl = create_field_decl (integer_type_node, "method_count");
  field_decl = create_field_decl (integer_type_node, "method_count");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* struct objc_method method_list[]; */
  /* struct objc_method method_list[]; */
  field_decl = create_field_decl (build_array_type
  field_decl = create_field_decl (build_array_type
                                  (list_type,
                                  (list_type,
                                   build_index_type
                                   build_index_type
                                   (build_int_cst (NULL_TREE, size - 1))),
                                   (build_int_cst (NULL_TREE, size - 1))),
                                  "method_list");
                                  "method_list");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_ivar_list_record, field_decl_chain);
  objc_finish_struct (objc_ivar_list_record, field_decl_chain);
 
 
  return objc_ivar_list_record;
  return objc_ivar_list_record;
}
}
 
 
static tree
static tree
build_method_prototype_template (void)
build_method_prototype_template (void)
{
{
  tree proto_record;
  tree proto_record;
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  proto_record = objc_start_struct (get_identifier (UTAG_METHOD_PROTOTYPE));
  proto_record = objc_start_struct (get_identifier (UTAG_METHOD_PROTOTYPE));
 
 
  /* SEL _cmd; */
  /* SEL _cmd; */
  field_decl = create_field_decl (objc_selector_type, "_cmd");
  field_decl = create_field_decl (objc_selector_type, "_cmd");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* char *method_types; */
  /* char *method_types; */
  field_decl = create_field_decl (string_type_node, "method_types");
  field_decl = create_field_decl (string_type_node, "method_types");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (proto_record, field_decl_chain);
  objc_finish_struct (proto_record, field_decl_chain);
 
 
  return proto_record;
  return proto_record;
}
}
 
 
static tree
static tree
objc_method_parm_type (tree type)
objc_method_parm_type (tree type)
{
{
  type = TREE_VALUE (TREE_TYPE (type));
  type = TREE_VALUE (TREE_TYPE (type));
  if (TREE_CODE (type) == TYPE_DECL)
  if (TREE_CODE (type) == TYPE_DECL)
    type = TREE_TYPE (type);
    type = TREE_TYPE (type);
  return type;
  return type;
}
}
 
 
static int
static int
objc_encoded_type_size (tree type)
objc_encoded_type_size (tree type)
{
{
  int sz = int_size_in_bytes (type);
  int sz = int_size_in_bytes (type);
 
 
  /* Make all integer and enum types at least as large
  /* Make all integer and enum types at least as large
     as an int.  */
     as an int.  */
  if (sz > 0 && INTEGRAL_TYPE_P (type))
  if (sz > 0 && INTEGRAL_TYPE_P (type))
    sz = MAX (sz, int_size_in_bytes (integer_type_node));
    sz = MAX (sz, int_size_in_bytes (integer_type_node));
  /* Treat arrays as pointers, since that's how they're
  /* Treat arrays as pointers, since that's how they're
     passed in.  */
     passed in.  */
  else if (TREE_CODE (type) == ARRAY_TYPE)
  else if (TREE_CODE (type) == ARRAY_TYPE)
    sz = int_size_in_bytes (ptr_type_node);
    sz = int_size_in_bytes (ptr_type_node);
  return sz;
  return sz;
}
}
 
 
static tree
static tree
encode_method_prototype (tree method_decl)
encode_method_prototype (tree method_decl)
{
{
  tree parms;
  tree parms;
  int parm_offset, i;
  int parm_offset, i;
  char buf[40];
  char buf[40];
  tree result;
  tree result;
 
 
  /* ONEWAY and BYCOPY, for remote object are the only method qualifiers.  */
  /* ONEWAY and BYCOPY, for remote object are the only method qualifiers.  */
  encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl)));
  encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl)));
 
 
  /* Encode return type.  */
  /* Encode return type.  */
  encode_type (objc_method_parm_type (method_decl),
  encode_type (objc_method_parm_type (method_decl),
               obstack_object_size (&util_obstack),
               obstack_object_size (&util_obstack),
               OBJC_ENCODE_INLINE_DEFS);
               OBJC_ENCODE_INLINE_DEFS);
 
 
  /* Stack size.  */
  /* Stack size.  */
  /* The first two arguments (self and _cmd) are pointers; account for
  /* The first two arguments (self and _cmd) are pointers; account for
     their size.  */
     their size.  */
  i = int_size_in_bytes (ptr_type_node);
  i = int_size_in_bytes (ptr_type_node);
  parm_offset = 2 * i;
  parm_offset = 2 * i;
  for (parms = METHOD_SEL_ARGS (method_decl); parms;
  for (parms = METHOD_SEL_ARGS (method_decl); parms;
       parms = TREE_CHAIN (parms))
       parms = TREE_CHAIN (parms))
    {
    {
      tree type = objc_method_parm_type (parms);
      tree type = objc_method_parm_type (parms);
      int sz = objc_encoded_type_size (type);
      int sz = objc_encoded_type_size (type);
 
 
      /* If a type size is not known, bail out.  */
      /* If a type size is not known, bail out.  */
      if (sz < 0)
      if (sz < 0)
        {
        {
          error ("type %q+D does not have a known size",
          error ("type %q+D does not have a known size",
                 type);
                 type);
          /* Pretend that the encoding succeeded; the compilation will
          /* Pretend that the encoding succeeded; the compilation will
             fail nevertheless.  */
             fail nevertheless.  */
          goto finish_encoding;
          goto finish_encoding;
        }
        }
      parm_offset += sz;
      parm_offset += sz;
    }
    }
 
 
  sprintf (buf, "%d@0:%d", parm_offset, i);
  sprintf (buf, "%d@0:%d", parm_offset, i);
  obstack_grow (&util_obstack, buf, strlen (buf));
  obstack_grow (&util_obstack, buf, strlen (buf));
 
 
  /* Argument types.  */
  /* Argument types.  */
  parm_offset = 2 * i;
  parm_offset = 2 * i;
  for (parms = METHOD_SEL_ARGS (method_decl); parms;
  for (parms = METHOD_SEL_ARGS (method_decl); parms;
       parms = TREE_CHAIN (parms))
       parms = TREE_CHAIN (parms))
    {
    {
      tree type = objc_method_parm_type (parms);
      tree type = objc_method_parm_type (parms);
 
 
      /* Process argument qualifiers for user supplied arguments.  */
      /* Process argument qualifiers for user supplied arguments.  */
      encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms)));
      encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms)));
 
 
      /* Type.  */
      /* Type.  */
      encode_type (type, obstack_object_size (&util_obstack),
      encode_type (type, obstack_object_size (&util_obstack),
                   OBJC_ENCODE_INLINE_DEFS);
                   OBJC_ENCODE_INLINE_DEFS);
 
 
      /* Compute offset.  */
      /* Compute offset.  */
      sprintf (buf, "%d", parm_offset);
      sprintf (buf, "%d", parm_offset);
      parm_offset += objc_encoded_type_size (type);
      parm_offset += objc_encoded_type_size (type);
 
 
      obstack_grow (&util_obstack, buf, strlen (buf));
      obstack_grow (&util_obstack, buf, strlen (buf));
    }
    }
 
 
  finish_encoding:
  finish_encoding:
  obstack_1grow (&util_obstack, '\0');
  obstack_1grow (&util_obstack, '\0');
  result = get_identifier (XOBFINISH (&util_obstack, char *));
  result = get_identifier (XOBFINISH (&util_obstack, char *));
  obstack_free (&util_obstack, util_firstobj);
  obstack_free (&util_obstack, util_firstobj);
  return result;
  return result;
}
}
 
 
static tree
static tree
generate_descriptor_table (tree type, const char *name, int size, tree list,
generate_descriptor_table (tree type, const char *name, int size, tree list,
                           tree proto)
                           tree proto)
{
{
  tree decl, initlist;
  tree decl, initlist;
 
 
  decl = start_var_decl (type, synth_id_with_class_suffix (name, proto));
  decl = start_var_decl (type, synth_id_with_class_suffix (name, proto));
 
 
  initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size));
  initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size));
  initlist = tree_cons (NULL_TREE, list, initlist);
  initlist = tree_cons (NULL_TREE, list, initlist);
 
 
  finish_var_decl (decl, objc_build_constructor (type, nreverse (initlist)));
  finish_var_decl (decl, objc_build_constructor (type, nreverse (initlist)));
 
 
  return decl;
  return decl;
}
}
 
 
static void
static void
generate_method_descriptors (tree protocol)
generate_method_descriptors (tree protocol)
{
{
  tree initlist, chain, method_list_template;
  tree initlist, chain, method_list_template;
  int size;
  int size;
 
 
  if (!objc_method_prototype_template)
  if (!objc_method_prototype_template)
    objc_method_prototype_template = build_method_prototype_template ();
    objc_method_prototype_template = build_method_prototype_template ();
 
 
  chain = PROTOCOL_CLS_METHODS (protocol);
  chain = PROTOCOL_CLS_METHODS (protocol);
  if (chain)
  if (chain)
    {
    {
      size = list_length (chain);
      size = list_length (chain);
 
 
      method_list_template
      method_list_template
        = build_method_prototype_list_template (objc_method_prototype_template,
        = build_method_prototype_list_template (objc_method_prototype_template,
                                                size);
                                                size);
 
 
      initlist
      initlist
        = build_descriptor_table_initializer (objc_method_prototype_template,
        = build_descriptor_table_initializer (objc_method_prototype_template,
                                              chain);
                                              chain);
 
 
      UOBJC_CLASS_METHODS_decl
      UOBJC_CLASS_METHODS_decl
        = generate_descriptor_table (method_list_template,
        = generate_descriptor_table (method_list_template,
                                     "_OBJC_PROTOCOL_CLASS_METHODS",
                                     "_OBJC_PROTOCOL_CLASS_METHODS",
                                     size, initlist, protocol);
                                     size, initlist, protocol);
    }
    }
  else
  else
    UOBJC_CLASS_METHODS_decl = 0;
    UOBJC_CLASS_METHODS_decl = 0;
 
 
  chain = PROTOCOL_NST_METHODS (protocol);
  chain = PROTOCOL_NST_METHODS (protocol);
  if (chain)
  if (chain)
    {
    {
      size = list_length (chain);
      size = list_length (chain);
 
 
      method_list_template
      method_list_template
        = build_method_prototype_list_template (objc_method_prototype_template,
        = build_method_prototype_list_template (objc_method_prototype_template,
                                                size);
                                                size);
      initlist
      initlist
        = build_descriptor_table_initializer (objc_method_prototype_template,
        = build_descriptor_table_initializer (objc_method_prototype_template,
                                              chain);
                                              chain);
 
 
      UOBJC_INSTANCE_METHODS_decl
      UOBJC_INSTANCE_METHODS_decl
        = generate_descriptor_table (method_list_template,
        = generate_descriptor_table (method_list_template,
                                     "_OBJC_PROTOCOL_INSTANCE_METHODS",
                                     "_OBJC_PROTOCOL_INSTANCE_METHODS",
                                     size, initlist, protocol);
                                     size, initlist, protocol);
    }
    }
  else
  else
    UOBJC_INSTANCE_METHODS_decl = 0;
    UOBJC_INSTANCE_METHODS_decl = 0;
}
}
 
 
static void
static void
generate_protocol_references (tree plist)
generate_protocol_references (tree plist)
{
{
  tree lproto;
  tree lproto;
 
 
  /* Forward declare protocols referenced.  */
  /* Forward declare protocols referenced.  */
  for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
  for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
    {
    {
      tree proto = TREE_VALUE (lproto);
      tree proto = TREE_VALUE (lproto);
 
 
      if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE
      if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE
          && PROTOCOL_NAME (proto))
          && PROTOCOL_NAME (proto))
        {
        {
          if (! PROTOCOL_FORWARD_DECL (proto))
          if (! PROTOCOL_FORWARD_DECL (proto))
            build_protocol_reference (proto);
            build_protocol_reference (proto);
 
 
          if (PROTOCOL_LIST (proto))
          if (PROTOCOL_LIST (proto))
            generate_protocol_references (PROTOCOL_LIST (proto));
            generate_protocol_references (PROTOCOL_LIST (proto));
        }
        }
    }
    }
}
}
 
 
/* Generate either '- .cxx_construct' or '- .cxx_destruct' for the
/* Generate either '- .cxx_construct' or '- .cxx_destruct' for the
   current class.  */
   current class.  */
#ifdef OBJCPLUS
#ifdef OBJCPLUS
static void
static void
objc_generate_cxx_ctor_or_dtor (bool dtor)
objc_generate_cxx_ctor_or_dtor (bool dtor)
{
{
  tree fn, body, compound_stmt, ivar;
  tree fn, body, compound_stmt, ivar;
 
 
  /* - (id) .cxx_construct { ... return self; } */
  /* - (id) .cxx_construct { ... return self; } */
  /* - (void) .cxx_construct { ... }            */
  /* - (void) .cxx_construct { ... }            */
 
 
  objc_set_method_type (MINUS_EXPR);
  objc_set_method_type (MINUS_EXPR);
  objc_start_method_definition
  objc_start_method_definition
   (objc_build_method_signature (build_tree_list (NULL_TREE,
   (objc_build_method_signature (build_tree_list (NULL_TREE,
                                                  dtor
                                                  dtor
                                                  ? void_type_node
                                                  ? void_type_node
                                                  : objc_object_type),
                                                  : objc_object_type),
                                 get_identifier (dtor
                                 get_identifier (dtor
                                                 ? TAG_CXX_DESTRUCT
                                                 ? TAG_CXX_DESTRUCT
                                                 : TAG_CXX_CONSTRUCT),
                                                 : TAG_CXX_CONSTRUCT),
                                 make_node (TREE_LIST),
                                 make_node (TREE_LIST),
                                 false));
                                 false));
  body = begin_function_body ();
  body = begin_function_body ();
  compound_stmt = begin_compound_stmt (0);
  compound_stmt = begin_compound_stmt (0);
 
 
  ivar = CLASS_IVARS (implementation_template);
  ivar = CLASS_IVARS (implementation_template);
  /* Destroy ivars in reverse order.  */
  /* Destroy ivars in reverse order.  */
  if (dtor)
  if (dtor)
    ivar = nreverse (copy_list (ivar));
    ivar = nreverse (copy_list (ivar));
 
 
  for (; ivar; ivar = TREE_CHAIN (ivar))
  for (; ivar; ivar = TREE_CHAIN (ivar))
    {
    {
      if (TREE_CODE (ivar) == FIELD_DECL)
      if (TREE_CODE (ivar) == FIELD_DECL)
        {
        {
          tree type = TREE_TYPE (ivar);
          tree type = TREE_TYPE (ivar);
 
 
          /* Call the ivar's default constructor or destructor.  Do not
          /* Call the ivar's default constructor or destructor.  Do not
             call the destructor unless a corresponding constructor call
             call the destructor unless a corresponding constructor call
             has also been made (or is not needed).  */
             has also been made (or is not needed).  */
          if (MAYBE_CLASS_TYPE_P (type)
          if (MAYBE_CLASS_TYPE_P (type)
              && (dtor
              && (dtor
                  ? (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
                  ? (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
                     && (!TYPE_NEEDS_CONSTRUCTING (type)
                     && (!TYPE_NEEDS_CONSTRUCTING (type)
                         || TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
                         || TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
                  : (TYPE_NEEDS_CONSTRUCTING (type)
                  : (TYPE_NEEDS_CONSTRUCTING (type)
                     && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))))
                     && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))))
            finish_expr_stmt
            finish_expr_stmt
             (build_special_member_call
             (build_special_member_call
              (build_ivar_reference (DECL_NAME (ivar)),
              (build_ivar_reference (DECL_NAME (ivar)),
               dtor ? complete_dtor_identifier : complete_ctor_identifier,
               dtor ? complete_dtor_identifier : complete_ctor_identifier,
               NULL, type, LOOKUP_NORMAL, tf_warning_or_error));
               NULL, type, LOOKUP_NORMAL, tf_warning_or_error));
        }
        }
    }
    }
 
 
  /* The constructor returns 'self'.  */
  /* The constructor returns 'self'.  */
  if (!dtor)
  if (!dtor)
    finish_return_stmt (self_decl);
    finish_return_stmt (self_decl);
 
 
  finish_compound_stmt (compound_stmt);
  finish_compound_stmt (compound_stmt);
  finish_function_body (body);
  finish_function_body (body);
  fn = current_function_decl;
  fn = current_function_decl;
  finish_function ();
  finish_function ();
  objc_finish_method_definition (fn);
  objc_finish_method_definition (fn);
}
}
 
 
/* The following routine will examine the current @interface for any
/* The following routine will examine the current @interface for any
   non-POD C++ ivars requiring non-trivial construction and/or
   non-POD C++ ivars requiring non-trivial construction and/or
   destruction, and then synthesize special '- .cxx_construct' and/or
   destruction, and then synthesize special '- .cxx_construct' and/or
   '- .cxx_destruct' methods which will run the appropriate
   '- .cxx_destruct' methods which will run the appropriate
   construction or destruction code.  Note that ivars inherited from
   construction or destruction code.  Note that ivars inherited from
   super-classes are _not_ considered.  */
   super-classes are _not_ considered.  */
static void
static void
objc_generate_cxx_cdtors (void)
objc_generate_cxx_cdtors (void)
{
{
  bool need_ctor = false, need_dtor = false;
  bool need_ctor = false, need_dtor = false;
  tree ivar;
  tree ivar;
 
 
  /* We do not want to do this for categories, since they do not have
  /* We do not want to do this for categories, since they do not have
     their own ivars.  */
     their own ivars.  */
 
 
  if (TREE_CODE (objc_implementation_context) != CLASS_IMPLEMENTATION_TYPE)
  if (TREE_CODE (objc_implementation_context) != CLASS_IMPLEMENTATION_TYPE)
    return;
    return;
 
 
  /* First, determine if we even need a constructor and/or destructor.  */
  /* First, determine if we even need a constructor and/or destructor.  */
 
 
  for (ivar = CLASS_IVARS (implementation_template); ivar;
  for (ivar = CLASS_IVARS (implementation_template); ivar;
       ivar = TREE_CHAIN (ivar))
       ivar = TREE_CHAIN (ivar))
    {
    {
      if (TREE_CODE (ivar) == FIELD_DECL)
      if (TREE_CODE (ivar) == FIELD_DECL)
        {
        {
          tree type = TREE_TYPE (ivar);
          tree type = TREE_TYPE (ivar);
 
 
          if (MAYBE_CLASS_TYPE_P (type))
          if (MAYBE_CLASS_TYPE_P (type))
            {
            {
              if (TYPE_NEEDS_CONSTRUCTING (type)
              if (TYPE_NEEDS_CONSTRUCTING (type)
                  && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
                  && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
                /* NB: If a default constructor is not available, we will not
                /* NB: If a default constructor is not available, we will not
                   be able to initialize this ivar; the add_instance_variable()
                   be able to initialize this ivar; the add_instance_variable()
                   routine will already have warned about this.  */
                   routine will already have warned about this.  */
                need_ctor = true;
                need_ctor = true;
 
 
              if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
              if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
                  && (!TYPE_NEEDS_CONSTRUCTING (type)
                  && (!TYPE_NEEDS_CONSTRUCTING (type)
                      || TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
                      || TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
                /* NB: If a default constructor is not available, we will not
                /* NB: If a default constructor is not available, we will not
                   call the destructor either, for symmetry.  */
                   call the destructor either, for symmetry.  */
                need_dtor = true;
                need_dtor = true;
            }
            }
        }
        }
    }
    }
 
 
  /* Generate '- .cxx_construct' if needed.  */
  /* Generate '- .cxx_construct' if needed.  */
 
 
  if (need_ctor)
  if (need_ctor)
    objc_generate_cxx_ctor_or_dtor (false);
    objc_generate_cxx_ctor_or_dtor (false);
 
 
  /* Generate '- .cxx_destruct' if needed.  */
  /* Generate '- .cxx_destruct' if needed.  */
 
 
  if (need_dtor)
  if (need_dtor)
    objc_generate_cxx_ctor_or_dtor (true);
    objc_generate_cxx_ctor_or_dtor (true);
 
 
  /* The 'imp_list' variable points at an imp_entry record for the current
  /* The 'imp_list' variable points at an imp_entry record for the current
     @implementation.  Record the existence of '- .cxx_construct' and/or
     @implementation.  Record the existence of '- .cxx_construct' and/or
     '- .cxx_destruct' methods therein; it will be included in the
     '- .cxx_destruct' methods therein; it will be included in the
     metadata for the class.  */
     metadata for the class.  */
  if (flag_next_runtime)
  if (flag_next_runtime)
    imp_list->has_cxx_cdtors = (need_ctor || need_dtor);
    imp_list->has_cxx_cdtors = (need_ctor || need_dtor);
}
}
#endif
#endif
 
 
/* For each protocol which was referenced either from a @protocol()
/* For each protocol which was referenced either from a @protocol()
   expression, or because a class/category implements it (then a
   expression, or because a class/category implements it (then a
   pointer to the protocol is stored in the struct describing the
   pointer to the protocol is stored in the struct describing the
   class/category), we create a statically allocated instance of the
   class/category), we create a statically allocated instance of the
   Protocol class.  The code is written in such a way as to generate
   Protocol class.  The code is written in such a way as to generate
   as few Protocol objects as possible; we generate a unique Protocol
   as few Protocol objects as possible; we generate a unique Protocol
   instance for each protocol, and we don't generate a Protocol
   instance for each protocol, and we don't generate a Protocol
   instance if the protocol is never referenced (either from a
   instance if the protocol is never referenced (either from a
   @protocol() or from a class/category implementation).  These
   @protocol() or from a class/category implementation).  These
   statically allocated objects can be referred to via the static
   statically allocated objects can be referred to via the static
   (that is, private to this module) symbols _OBJC_PROTOCOL_n.
   (that is, private to this module) symbols _OBJC_PROTOCOL_n.
 
 
   The statically allocated Protocol objects that we generate here
   The statically allocated Protocol objects that we generate here
   need to be fixed up at runtime in order to be used: the 'isa'
   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.
   class, as known at runtime.
 
 
   The NeXT runtime fixes up all protocols at program startup time,
   The NeXT runtime fixes up all protocols at program startup time,
   before main() is entered.  It uses a low-level trick to look up all
   before main() is entered.  It uses a low-level trick to look up all
   those symbols, then loops on them and fixes them up.
   those symbols, then loops on them and fixes them up.
 
 
   The GNU runtime as well fixes up all protocols before user code
   The GNU runtime as well fixes up all protocols before user code
   from the module is executed; it requires pointers to those symbols
   from the module is executed; it requires pointers to those symbols
   to be put in the objc_symtab (which is then passed as argument to
   to be put in the objc_symtab (which is then passed as argument to
   the function __objc_exec_class() which the compiler sets up to be
   the function __objc_exec_class() which the compiler sets up to be
   executed automatically when the module is loaded); setup of those
   executed automatically when the module is loaded); setup of those
   Protocol objects happen in two ways in the GNU runtime: all
   Protocol objects happen in two ways in the GNU runtime: all
   Protocol objects referred to by a class or category implementation
   Protocol objects referred to by a class or category implementation
   are fixed up when the class/category is loaded; all Protocol
   are fixed up when the class/category is loaded; all Protocol
   objects referred to by a @protocol() expression are added by the
   objects referred to by a @protocol() expression are added by the
   compiler to the list of statically allocated instances to fixup
   compiler to the list of statically allocated instances to fixup
   (the same list holding the statically allocated constant string
   (the same list holding the statically allocated constant string
   objects).  Because, as explained above, the compiler generates as
   objects).  Because, as explained above, the compiler generates as
   few Protocol objects as possible, some Protocol object might end up
   few Protocol objects as possible, some Protocol object might end up
   being referenced multiple times when compiled with the GNU runtime,
   being referenced multiple times when compiled with the GNU runtime,
   and end up being fixed up multiple times at runtime initialization.
   and end up being fixed up multiple times at runtime initialization.
   But that doesn't hurt, it's just a little inefficient.  */
   But that doesn't hurt, it's just a little inefficient.  */
 
 
static void
static void
generate_protocols (void)
generate_protocols (void)
{
{
  tree p, encoding;
  tree p, encoding;
  tree decl;
  tree decl;
  tree initlist, protocol_name_expr, refs_decl, refs_expr;
  tree initlist, protocol_name_expr, refs_decl, refs_expr;
 
 
  /* If a protocol was directly referenced, pull in indirect references.  */
  /* If a protocol was directly referenced, pull in indirect references.  */
  for (p = protocol_chain; p; p = TREE_CHAIN (p))
  for (p = protocol_chain; p; p = TREE_CHAIN (p))
    if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p))
    if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p))
      generate_protocol_references (PROTOCOL_LIST (p));
      generate_protocol_references (PROTOCOL_LIST (p));
 
 
  for (p = protocol_chain; p; p = TREE_CHAIN (p))
  for (p = protocol_chain; p; p = TREE_CHAIN (p))
    {
    {
      tree nst_methods = PROTOCOL_NST_METHODS (p);
      tree nst_methods = PROTOCOL_NST_METHODS (p);
      tree cls_methods = PROTOCOL_CLS_METHODS (p);
      tree cls_methods = PROTOCOL_CLS_METHODS (p);
 
 
      /* If protocol wasn't referenced, don't generate any code.  */
      /* If protocol wasn't referenced, don't generate any code.  */
      decl = PROTOCOL_FORWARD_DECL (p);
      decl = PROTOCOL_FORWARD_DECL (p);
 
 
      if (!decl)
      if (!decl)
        continue;
        continue;
 
 
      /* Make sure we link in the Protocol class.  */
      /* Make sure we link in the Protocol class.  */
      add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
      add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
 
 
      while (nst_methods)
      while (nst_methods)
        {
        {
          if (! METHOD_ENCODING (nst_methods))
          if (! METHOD_ENCODING (nst_methods))
            {
            {
              encoding = encode_method_prototype (nst_methods);
              encoding = encode_method_prototype (nst_methods);
              METHOD_ENCODING (nst_methods) = encoding;
              METHOD_ENCODING (nst_methods) = encoding;
            }
            }
          nst_methods = TREE_CHAIN (nst_methods);
          nst_methods = TREE_CHAIN (nst_methods);
        }
        }
 
 
      while (cls_methods)
      while (cls_methods)
        {
        {
          if (! METHOD_ENCODING (cls_methods))
          if (! METHOD_ENCODING (cls_methods))
            {
            {
              encoding = encode_method_prototype (cls_methods);
              encoding = encode_method_prototype (cls_methods);
              METHOD_ENCODING (cls_methods) = encoding;
              METHOD_ENCODING (cls_methods) = encoding;
            }
            }
 
 
          cls_methods = TREE_CHAIN (cls_methods);
          cls_methods = TREE_CHAIN (cls_methods);
        }
        }
      generate_method_descriptors (p);
      generate_method_descriptors (p);
 
 
      if (PROTOCOL_LIST (p))
      if (PROTOCOL_LIST (p))
        refs_decl = generate_protocol_list (p);
        refs_decl = generate_protocol_list (p);
      else
      else
        refs_decl = 0;
        refs_decl = 0;
 
 
      /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */
      /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */
      protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names);
      protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names);
 
 
      if (refs_decl)
      if (refs_decl)
        refs_expr = convert (build_pointer_type (build_pointer_type
        refs_expr = convert (build_pointer_type (build_pointer_type
                                                 (objc_protocol_template)),
                                                 (objc_protocol_template)),
                             build_unary_op (input_location,
                             build_unary_op (input_location,
                                             ADDR_EXPR, refs_decl, 0));
                                             ADDR_EXPR, refs_decl, 0));
      else
      else
        refs_expr = build_int_cst (NULL_TREE, 0);
        refs_expr = build_int_cst (NULL_TREE, 0);
 
 
      /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set
      /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set
         by generate_method_descriptors, which is called above.  */
         by generate_method_descriptors, which is called above.  */
      initlist = build_protocol_initializer (TREE_TYPE (decl),
      initlist = build_protocol_initializer (TREE_TYPE (decl),
                                             protocol_name_expr, refs_expr,
                                             protocol_name_expr, refs_expr,
                                             UOBJC_INSTANCE_METHODS_decl,
                                             UOBJC_INSTANCE_METHODS_decl,
                                             UOBJC_CLASS_METHODS_decl);
                                             UOBJC_CLASS_METHODS_decl);
      finish_var_decl (decl, initlist);
      finish_var_decl (decl, initlist);
    }
    }
}
}
 
 
static tree
static tree
build_protocol_initializer (tree type, tree protocol_name,
build_protocol_initializer (tree type, tree protocol_name,
                            tree protocol_list, tree instance_methods,
                            tree protocol_list, tree instance_methods,
                            tree class_methods)
                            tree class_methods)
{
{
  tree initlist = NULL_TREE, expr;
  tree initlist = NULL_TREE, expr;
  tree cast_type = build_pointer_type
  tree cast_type = build_pointer_type
                   (xref_tag (RECORD_TYPE,
                   (xref_tag (RECORD_TYPE,
                              get_identifier (UTAG_CLASS)));
                              get_identifier (UTAG_CLASS)));
 
 
  /* Filling the "isa" in with one allows the runtime system to
  /* Filling the "isa" in with one allows the runtime system to
     detect that the version change...should remove before final release.  */
     detect that the version change...should remove before final release.  */
 
 
  expr = build_int_cst (cast_type, PROTOCOL_VERSION);
  expr = build_int_cst (cast_type, PROTOCOL_VERSION);
  initlist = tree_cons (NULL_TREE, expr, initlist);
  initlist = tree_cons (NULL_TREE, expr, initlist);
  initlist = tree_cons (NULL_TREE, protocol_name, initlist);
  initlist = tree_cons (NULL_TREE, protocol_name, initlist);
  initlist = tree_cons (NULL_TREE, protocol_list, initlist);
  initlist = tree_cons (NULL_TREE, protocol_list, initlist);
 
 
  if (!instance_methods)
  if (!instance_methods)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (objc_method_proto_list_ptr,
      expr = convert (objc_method_proto_list_ptr,
                      build_unary_op (input_location,
                      build_unary_op (input_location,
                                      ADDR_EXPR, instance_methods, 0));
                                      ADDR_EXPR, instance_methods, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  if (!class_methods)
  if (!class_methods)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (objc_method_proto_list_ptr,
      expr = convert (objc_method_proto_list_ptr,
                      build_unary_op (input_location,
                      build_unary_op (input_location,
                                      ADDR_EXPR, class_methods, 0));
                                      ADDR_EXPR, class_methods, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  return objc_build_constructor (type, nreverse (initlist));
  return objc_build_constructor (type, nreverse (initlist));
}
}


/* struct _objc_category {
/* struct _objc_category {
     char *category_name;
     char *category_name;
     char *class_name;
     char *class_name;
     struct _objc_method_list *instance_methods;
     struct _objc_method_list *instance_methods;
     struct _objc_method_list *class_methods;
     struct _objc_method_list *class_methods;
     struct _objc_protocol_list *protocols;
     struct _objc_protocol_list *protocols;
   };   */
   };   */
 
 
static void
static void
build_category_template (void)
build_category_template (void)
{
{
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY));
  objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY));
 
 
  /* char *category_name; */
  /* char *category_name; */
  field_decl = create_field_decl (string_type_node, "category_name");
  field_decl = create_field_decl (string_type_node, "category_name");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* char *class_name; */
  /* char *class_name; */
  field_decl = create_field_decl (string_type_node, "class_name");
  field_decl = create_field_decl (string_type_node, "class_name");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc_method_list *instance_methods; */
  /* struct _objc_method_list *instance_methods; */
  field_decl = create_field_decl (objc_method_list_ptr,
  field_decl = create_field_decl (objc_method_list_ptr,
                                  "instance_methods");
                                  "instance_methods");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc_method_list *class_methods; */
  /* struct _objc_method_list *class_methods; */
  field_decl = create_field_decl (objc_method_list_ptr,
  field_decl = create_field_decl (objc_method_list_ptr,
                                  "class_methods");
                                  "class_methods");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc_protocol **protocol_list; */
  /* struct _objc_protocol **protocol_list; */
  field_decl = create_field_decl (build_pointer_type
  field_decl = create_field_decl (build_pointer_type
                                  (build_pointer_type
                                  (build_pointer_type
                                   (objc_protocol_template)),
                                   (objc_protocol_template)),
                                  "protocol_list");
                                  "protocol_list");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_category_template, field_decl_chain);
  objc_finish_struct (objc_category_template, field_decl_chain);
}
}
 
 
/* struct _objc_selector {
/* struct _objc_selector {
     SEL sel_id;
     SEL sel_id;
     char *sel_type;
     char *sel_type;
   }; */
   }; */
 
 
static void
static void
build_selector_template (void)
build_selector_template (void)
{
{
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_selector_template = objc_start_struct (get_identifier (UTAG_SELECTOR));
  objc_selector_template = objc_start_struct (get_identifier (UTAG_SELECTOR));
 
 
  /* SEL sel_id; */
  /* SEL sel_id; */
  field_decl = create_field_decl (objc_selector_type, "sel_id");
  field_decl = create_field_decl (objc_selector_type, "sel_id");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* char *sel_type; */
  /* char *sel_type; */
  field_decl = create_field_decl (string_type_node, "sel_type");
  field_decl = create_field_decl (string_type_node, "sel_type");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_selector_template, field_decl_chain);
  objc_finish_struct (objc_selector_template, field_decl_chain);
}
}
 
 
/* struct _objc_class {
/* struct _objc_class {
     struct _objc_class *isa;
     struct _objc_class *isa;
     struct _objc_class *super_class;
     struct _objc_class *super_class;
     char *name;
     char *name;
     long version;
     long version;
     long info;
     long info;
     long instance_size;
     long instance_size;
     struct _objc_ivar_list *ivars;
     struct _objc_ivar_list *ivars;
     struct _objc_method_list *methods;
     struct _objc_method_list *methods;
     #ifdef __NEXT_RUNTIME__
     #ifdef __NEXT_RUNTIME__
       struct objc_cache *cache;
       struct objc_cache *cache;
     #else
     #else
       struct sarray *dtable;
       struct sarray *dtable;
       struct _objc_class *subclass_list;
       struct _objc_class *subclass_list;
       struct _objc_class *sibling_class;
       struct _objc_class *sibling_class;
     #endif
     #endif
     struct _objc_protocol_list *protocols;
     struct _objc_protocol_list *protocols;
     #ifdef __NEXT_RUNTIME__
     #ifdef __NEXT_RUNTIME__
       void *sel_id;
       void *sel_id;
     #endif
     #endif
     void *gc_object_type;
     void *gc_object_type;
   };  */
   };  */
 
 
/* NB: The 'sel_id' and 'gc_object_type' fields are not being used by
/* 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
   the NeXT/Apple runtime; still, the compiler must generate them to
   maintain backward binary compatibility (and to allow for future
   maintain backward binary compatibility (and to allow for future
   expansion).  */
   expansion).  */
 
 
static void
static void
build_class_template (void)
build_class_template (void)
{
{
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS));
  objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS));
 
 
  /* struct _objc_class *isa; */
  /* struct _objc_class *isa; */
  field_decl = create_field_decl (build_pointer_type (objc_class_template),
  field_decl = create_field_decl (build_pointer_type (objc_class_template),
                                  "isa");
                                  "isa");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* struct _objc_class *super_class; */
  /* struct _objc_class *super_class; */
  field_decl = create_field_decl (build_pointer_type (objc_class_template),
  field_decl = create_field_decl (build_pointer_type (objc_class_template),
                                  "super_class");
                                  "super_class");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* char *name; */
  /* char *name; */
  field_decl = create_field_decl (string_type_node, "name");
  field_decl = create_field_decl (string_type_node, "name");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* long version; */
  /* long version; */
  field_decl = create_field_decl (long_integer_type_node, "version");
  field_decl = create_field_decl (long_integer_type_node, "version");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* long info; */
  /* long info; */
  field_decl = create_field_decl (long_integer_type_node, "info");
  field_decl = create_field_decl (long_integer_type_node, "info");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* long instance_size; */
  /* long instance_size; */
  field_decl = create_field_decl (long_integer_type_node, "instance_size");
  field_decl = create_field_decl (long_integer_type_node, "instance_size");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc_ivar_list *ivars; */
  /* struct _objc_ivar_list *ivars; */
  field_decl = create_field_decl (objc_ivar_list_ptr,
  field_decl = create_field_decl (objc_ivar_list_ptr,
                                  "ivars");
                                  "ivars");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct _objc_method_list *methods; */
  /* struct _objc_method_list *methods; */
  field_decl = create_field_decl (objc_method_list_ptr,
  field_decl = create_field_decl (objc_method_list_ptr,
                                  "methods");
                                  "methods");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      /* struct objc_cache *cache; */
      /* struct objc_cache *cache; */
      field_decl = create_field_decl (build_pointer_type
      field_decl = create_field_decl (build_pointer_type
                                      (xref_tag (RECORD_TYPE,
                                      (xref_tag (RECORD_TYPE,
                                                 get_identifier
                                                 get_identifier
                                                 ("objc_cache"))),
                                                 ("objc_cache"))),
                                      "cache");
                                      "cache");
      chainon (field_decl_chain, field_decl);
      chainon (field_decl_chain, field_decl);
    }
    }
  else
  else
    {
    {
      /* struct sarray *dtable; */
      /* struct sarray *dtable; */
      field_decl = create_field_decl (build_pointer_type
      field_decl = create_field_decl (build_pointer_type
                                      (xref_tag (RECORD_TYPE,
                                      (xref_tag (RECORD_TYPE,
                                                 get_identifier
                                                 get_identifier
                                                 ("sarray"))),
                                                 ("sarray"))),
                                      "dtable");
                                      "dtable");
      chainon (field_decl_chain, field_decl);
      chainon (field_decl_chain, field_decl);
 
 
      /* struct objc_class *subclass_list; */
      /* struct objc_class *subclass_list; */
      field_decl = create_field_decl (build_pointer_type
      field_decl = create_field_decl (build_pointer_type
                                      (objc_class_template),
                                      (objc_class_template),
                                      "subclass_list");
                                      "subclass_list");
      chainon (field_decl_chain, field_decl);
      chainon (field_decl_chain, field_decl);
 
 
      /* struct objc_class *sibling_class; */
      /* struct objc_class *sibling_class; */
      field_decl = create_field_decl (build_pointer_type
      field_decl = create_field_decl (build_pointer_type
                                      (objc_class_template),
                                      (objc_class_template),
                                      "sibling_class");
                                      "sibling_class");
      chainon (field_decl_chain, field_decl);
      chainon (field_decl_chain, field_decl);
    }
    }
 
 
  /* struct _objc_protocol **protocol_list; */
  /* struct _objc_protocol **protocol_list; */
  field_decl = create_field_decl (build_pointer_type
  field_decl = create_field_decl (build_pointer_type
                                  (build_pointer_type
                                  (build_pointer_type
                                   (xref_tag (RECORD_TYPE,
                                   (xref_tag (RECORD_TYPE,
                                             get_identifier
                                             get_identifier
                                             (UTAG_PROTOCOL)))),
                                             (UTAG_PROTOCOL)))),
                                  "protocol_list");
                                  "protocol_list");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      /* void *sel_id; */
      /* void *sel_id; */
      field_decl = create_field_decl (build_pointer_type (void_type_node),
      field_decl = create_field_decl (build_pointer_type (void_type_node),
                                      "sel_id");
                                      "sel_id");
      chainon (field_decl_chain, field_decl);
      chainon (field_decl_chain, field_decl);
    }
    }
 
 
  /* void *gc_object_type; */
  /* void *gc_object_type; */
  field_decl = create_field_decl (build_pointer_type (void_type_node),
  field_decl = create_field_decl (build_pointer_type (void_type_node),
                                  "gc_object_type");
                                  "gc_object_type");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_class_template, field_decl_chain);
  objc_finish_struct (objc_class_template, field_decl_chain);
}
}
 
 
/* Generate appropriate forward declarations for an implementation.  */
/* Generate appropriate forward declarations for an implementation.  */
 
 
static void
static void
synth_forward_declarations (void)
synth_forward_declarations (void)
{
{
  tree an_id;
  tree an_id;
 
 
  /* static struct objc_class _OBJC_CLASS_<my_name>; */
  /* static struct objc_class _OBJC_CLASS_<my_name>; */
  UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS",
  UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS",
                                          objc_class_template);
                                          objc_class_template);
 
 
  /* static struct objc_class _OBJC_METACLASS_<my_name>; */
  /* static struct objc_class _OBJC_METACLASS_<my_name>; */
  UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS",
  UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS",
                                                  objc_class_template);
                                                  objc_class_template);
 
 
  /* Pre-build the following entities - for speed/convenience.  */
  /* Pre-build the following entities - for speed/convenience.  */
 
 
  an_id = get_identifier ("super_class");
  an_id = get_identifier ("super_class");
  ucls_super_ref = objc_build_component_ref (UOBJC_CLASS_decl, an_id);
  ucls_super_ref = objc_build_component_ref (UOBJC_CLASS_decl, an_id);
  uucls_super_ref = objc_build_component_ref (UOBJC_METACLASS_decl, an_id);
  uucls_super_ref = objc_build_component_ref (UOBJC_METACLASS_decl, an_id);
}
}
 
 
static void
static void
error_with_ivar (const char *message, tree decl)
error_with_ivar (const char *message, tree decl)
{
{
  error_at (DECL_SOURCE_LOCATION (decl), "%s %qs",
  error_at (DECL_SOURCE_LOCATION (decl), "%s %qs",
            message, identifier_to_locale (gen_declaration (decl)));
            message, identifier_to_locale (gen_declaration (decl)));
 
 
}
}
 
 
static void
static void
check_ivars (tree inter, tree imp)
check_ivars (tree inter, tree imp)
{
{
  tree intdecls = CLASS_RAW_IVARS (inter);
  tree intdecls = CLASS_RAW_IVARS (inter);
  tree impdecls = CLASS_RAW_IVARS (imp);
  tree impdecls = CLASS_RAW_IVARS (imp);
 
 
  while (1)
  while (1)
    {
    {
      tree t1, t2;
      tree t1, t2;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      if (intdecls && TREE_CODE (intdecls) == TYPE_DECL)
      if (intdecls && TREE_CODE (intdecls) == TYPE_DECL)
        intdecls = TREE_CHAIN (intdecls);
        intdecls = TREE_CHAIN (intdecls);
#endif
#endif
      if (intdecls == 0 && impdecls == 0)
      if (intdecls == 0 && impdecls == 0)
        break;
        break;
      if (intdecls == 0 || impdecls == 0)
      if (intdecls == 0 || impdecls == 0)
        {
        {
          error ("inconsistent instance variable specification");
          error ("inconsistent instance variable specification");
          break;
          break;
        }
        }
 
 
      t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
      t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
 
 
      if (!comptypes (t1, t2)
      if (!comptypes (t1, t2)
          || !tree_int_cst_equal (DECL_INITIAL (intdecls),
          || !tree_int_cst_equal (DECL_INITIAL (intdecls),
                                  DECL_INITIAL (impdecls)))
                                  DECL_INITIAL (impdecls)))
        {
        {
          if (DECL_NAME (intdecls) == DECL_NAME (impdecls))
          if (DECL_NAME (intdecls) == DECL_NAME (impdecls))
            {
            {
              error_with_ivar ("conflicting instance variable type",
              error_with_ivar ("conflicting instance variable type",
                               impdecls);
                               impdecls);
              error_with_ivar ("previous declaration of",
              error_with_ivar ("previous declaration of",
                               intdecls);
                               intdecls);
            }
            }
          else                  /* both the type and the name don't match */
          else                  /* both the type and the name don't match */
            {
            {
              error ("inconsistent instance variable specification");
              error ("inconsistent instance variable specification");
              break;
              break;
            }
            }
        }
        }
 
 
      else if (DECL_NAME (intdecls) != DECL_NAME (impdecls))
      else if (DECL_NAME (intdecls) != DECL_NAME (impdecls))
        {
        {
          error_with_ivar ("conflicting instance variable name",
          error_with_ivar ("conflicting instance variable name",
                           impdecls);
                           impdecls);
          error_with_ivar ("previous declaration of",
          error_with_ivar ("previous declaration of",
                           intdecls);
                           intdecls);
        }
        }
 
 
      intdecls = TREE_CHAIN (intdecls);
      intdecls = TREE_CHAIN (intdecls);
      impdecls = TREE_CHAIN (impdecls);
      impdecls = TREE_CHAIN (impdecls);
    }
    }
}
}
 
 
/* Set 'objc_super_template' to the data type node for 'struct _objc_super'.
/* Set 'objc_super_template' to the data type node for 'struct _objc_super'.
   This needs to be done just once per compilation.  */
   This needs to be done just once per compilation.  */
 
 
/* struct _objc_super {
/* struct _objc_super {
     struct _objc_object *self;
     struct _objc_object *self;
     struct _objc_class *super_class;
     struct _objc_class *super_class;
   };  */
   };  */
 
 
static void
static void
build_super_template (void)
build_super_template (void)
{
{
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER));
  objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER));
 
 
  /* struct _objc_object *self; */
  /* struct _objc_object *self; */
  field_decl = create_field_decl (objc_object_type, "self");
  field_decl = create_field_decl (objc_object_type, "self");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* struct _objc_class *super_class; */
  /* struct _objc_class *super_class; */
  field_decl = create_field_decl (build_pointer_type (objc_class_template),
  field_decl = create_field_decl (build_pointer_type (objc_class_template),
                                  "super_class");
                                  "super_class");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_super_template, field_decl_chain);
  objc_finish_struct (objc_super_template, field_decl_chain);
}
}
 
 
/* struct _objc_ivar {
/* struct _objc_ivar {
     char *ivar_name;
     char *ivar_name;
     char *ivar_type;
     char *ivar_type;
     int ivar_offset;
     int ivar_offset;
   };  */
   };  */
 
 
static tree
static tree
build_ivar_template (void)
build_ivar_template (void)
{
{
  tree objc_ivar_id, objc_ivar_record;
  tree objc_ivar_id, objc_ivar_record;
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_ivar_id = get_identifier (UTAG_IVAR);
  objc_ivar_id = get_identifier (UTAG_IVAR);
  objc_ivar_record = objc_start_struct (objc_ivar_id);
  objc_ivar_record = objc_start_struct (objc_ivar_id);
 
 
  /* char *ivar_name; */
  /* char *ivar_name; */
  field_decl = create_field_decl (string_type_node, "ivar_name");
  field_decl = create_field_decl (string_type_node, "ivar_name");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* char *ivar_type; */
  /* char *ivar_type; */
  field_decl = create_field_decl (string_type_node, "ivar_type");
  field_decl = create_field_decl (string_type_node, "ivar_type");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* int ivar_offset; */
  /* int ivar_offset; */
  field_decl = create_field_decl (integer_type_node, "ivar_offset");
  field_decl = create_field_decl (integer_type_node, "ivar_offset");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_ivar_record, field_decl_chain);
  objc_finish_struct (objc_ivar_record, field_decl_chain);
 
 
  return objc_ivar_record;
  return objc_ivar_record;
}
}
 
 
/* struct {
/* struct {
     int ivar_count;
     int ivar_count;
     struct objc_ivar ivar_list[ivar_count];
     struct objc_ivar ivar_list[ivar_count];
   };  */
   };  */
 
 
static tree
static tree
build_ivar_list_template (tree list_type, int size)
build_ivar_list_template (tree list_type, int size)
{
{
  tree objc_ivar_list_record;
  tree objc_ivar_list_record;
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_ivar_list_record = objc_start_struct (NULL_TREE);
  objc_ivar_list_record = objc_start_struct (NULL_TREE);
 
 
  /* int ivar_count; */
  /* int ivar_count; */
  field_decl = create_field_decl (integer_type_node, "ivar_count");
  field_decl = create_field_decl (integer_type_node, "ivar_count");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* struct objc_ivar ivar_list[]; */
  /* struct objc_ivar ivar_list[]; */
  field_decl = create_field_decl (build_array_type
  field_decl = create_field_decl (build_array_type
                                  (list_type,
                                  (list_type,
                                   build_index_type
                                   build_index_type
                                   (build_int_cst (NULL_TREE, size - 1))),
                                   (build_int_cst (NULL_TREE, size - 1))),
                                  "ivar_list");
                                  "ivar_list");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_ivar_list_record, field_decl_chain);
  objc_finish_struct (objc_ivar_list_record, field_decl_chain);
 
 
  return objc_ivar_list_record;
  return objc_ivar_list_record;
}
}
 
 
/* struct {
/* struct {
     struct _objc__method_prototype_list *method_next;
     struct _objc__method_prototype_list *method_next;
     int method_count;
     int method_count;
     struct objc_method method_list[method_count];
     struct objc_method method_list[method_count];
   };  */
   };  */
 
 
static tree
static tree
build_method_list_template (tree list_type, int size)
build_method_list_template (tree list_type, int size)
{
{
  tree objc_ivar_list_record;
  tree objc_ivar_list_record;
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  objc_ivar_list_record = objc_start_struct (NULL_TREE);
  objc_ivar_list_record = objc_start_struct (NULL_TREE);
 
 
  /* struct _objc__method_prototype_list *method_next; */
  /* struct _objc__method_prototype_list *method_next; */
  field_decl = create_field_decl (objc_method_proto_list_ptr,
  field_decl = create_field_decl (objc_method_proto_list_ptr,
                                  "method_next");
                                  "method_next");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* int method_count; */
  /* int method_count; */
  field_decl = create_field_decl (integer_type_node, "method_count");
  field_decl = create_field_decl (integer_type_node, "method_count");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* struct objc_method method_list[]; */
  /* struct objc_method method_list[]; */
  field_decl = create_field_decl (build_array_type
  field_decl = create_field_decl (build_array_type
                                  (list_type,
                                  (list_type,
                                   build_index_type
                                   build_index_type
                                   (build_int_cst (NULL_TREE, size - 1))),
                                   (build_int_cst (NULL_TREE, size - 1))),
                                  "method_list");
                                  "method_list");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (objc_ivar_list_record, field_decl_chain);
  objc_finish_struct (objc_ivar_list_record, field_decl_chain);
 
 
  return objc_ivar_list_record;
  return objc_ivar_list_record;
}
}
 
 
static tree
static tree
build_ivar_list_initializer (tree type, tree field_decl)
build_ivar_list_initializer (tree type, tree field_decl)
{
{
  tree initlist = NULL_TREE;
  tree initlist = NULL_TREE;
 
 
  do
  do
    {
    {
      tree ivar = NULL_TREE;
      tree ivar = NULL_TREE;
 
 
      /* Set name.  */
      /* Set name.  */
      if (DECL_NAME (field_decl))
      if (DECL_NAME (field_decl))
        ivar = tree_cons (NULL_TREE,
        ivar = tree_cons (NULL_TREE,
                          add_objc_string (DECL_NAME (field_decl),
                          add_objc_string (DECL_NAME (field_decl),
                                           meth_var_names),
                                           meth_var_names),
                          ivar);
                          ivar);
      else
      else
        /* Unnamed bit-field ivar (yuck).  */
        /* Unnamed bit-field ivar (yuck).  */
        ivar = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), ivar);
        ivar = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), ivar);
 
 
      /* Set type.  */
      /* Set type.  */
      encode_field_decl (field_decl,
      encode_field_decl (field_decl,
                         obstack_object_size (&util_obstack),
                         obstack_object_size (&util_obstack),
                         OBJC_ENCODE_DONT_INLINE_DEFS);
                         OBJC_ENCODE_DONT_INLINE_DEFS);
 
 
      /* Null terminate string.  */
      /* Null terminate string.  */
      obstack_1grow (&util_obstack, 0);
      obstack_1grow (&util_obstack, 0);
      ivar
      ivar
        = tree_cons
        = tree_cons
          (NULL_TREE,
          (NULL_TREE,
           add_objc_string (get_identifier (XOBFINISH (&util_obstack, char *)),
           add_objc_string (get_identifier (XOBFINISH (&util_obstack, char *)),
                            meth_var_types),
                            meth_var_types),
           ivar);
           ivar);
      obstack_free (&util_obstack, util_firstobj);
      obstack_free (&util_obstack, util_firstobj);
 
 
      /* Set offset.  */
      /* Set offset.  */
      ivar = tree_cons (NULL_TREE, byte_position (field_decl), ivar);
      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)),
                            objc_build_constructor (type, nreverse (ivar)),
                            initlist);
                            initlist);
      do
      do
        field_decl = TREE_CHAIN (field_decl);
        field_decl = TREE_CHAIN (field_decl);
      while (field_decl && TREE_CODE (field_decl) != FIELD_DECL);
      while (field_decl && TREE_CODE (field_decl) != FIELD_DECL);
    }
    }
  while (field_decl);
  while (field_decl);
 
 
  return objc_build_constructor (build_array_type (type, 0),
  return objc_build_constructor (build_array_type (type, 0),
                                 nreverse (initlist));
                                 nreverse (initlist));
}
}
 
 
static tree
static tree
generate_ivars_list (tree type, const char *name, int size, tree list)
generate_ivars_list (tree type, const char *name, int size, tree list)
{
{
  tree decl, initlist;
  tree decl, initlist;
 
 
  decl = start_var_decl (type, synth_id_with_class_suffix
  decl = start_var_decl (type, synth_id_with_class_suffix
                               (name, objc_implementation_context));
                               (name, objc_implementation_context));
 
 
  initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size));
  initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size));
  initlist = tree_cons (NULL_TREE, list, initlist);
  initlist = tree_cons (NULL_TREE, list, initlist);
 
 
  finish_var_decl (decl,
  finish_var_decl (decl,
                   objc_build_constructor (TREE_TYPE (decl),
                   objc_build_constructor (TREE_TYPE (decl),
                                           nreverse (initlist)));
                                           nreverse (initlist)));
 
 
  return decl;
  return decl;
}
}
 
 
/* Count only the fields occurring in T.  */
/* Count only the fields occurring in T.  */
 
 
static int
static int
ivar_list_length (tree t)
ivar_list_length (tree t)
{
{
  int count = 0;
  int count = 0;
 
 
  for (; t; t = TREE_CHAIN (t))
  for (; t; t = TREE_CHAIN (t))
    if (TREE_CODE (t) == FIELD_DECL)
    if (TREE_CODE (t) == FIELD_DECL)
      ++count;
      ++count;
 
 
  return count;
  return count;
}
}
 
 
static void
static void
generate_ivar_lists (void)
generate_ivar_lists (void)
{
{
  tree initlist, ivar_list_template, chain;
  tree initlist, ivar_list_template, chain;
  int size;
  int size;
 
 
  generating_instance_variables = 1;
  generating_instance_variables = 1;
 
 
  if (!objc_ivar_template)
  if (!objc_ivar_template)
    objc_ivar_template = build_ivar_template ();
    objc_ivar_template = build_ivar_template ();
 
 
  /* Only generate class variables for the root of the inheritance
  /* Only generate class variables for the root of the inheritance
     hierarchy since these will be the same for every class.  */
     hierarchy since these will be the same for every class.  */
 
 
  if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE
  if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE
      && (chain = TYPE_FIELDS (objc_class_template)))
      && (chain = TYPE_FIELDS (objc_class_template)))
    {
    {
      size = ivar_list_length (chain);
      size = ivar_list_length (chain);
 
 
      ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
      ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
      initlist = build_ivar_list_initializer (objc_ivar_template, chain);
      initlist = build_ivar_list_initializer (objc_ivar_template, chain);
 
 
      UOBJC_CLASS_VARIABLES_decl
      UOBJC_CLASS_VARIABLES_decl
        = generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES",
        = generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES",
                               size, initlist);
                               size, initlist);
    }
    }
  else
  else
    UOBJC_CLASS_VARIABLES_decl = 0;
    UOBJC_CLASS_VARIABLES_decl = 0;
 
 
  chain = CLASS_IVARS (implementation_template);
  chain = CLASS_IVARS (implementation_template);
  if (chain)
  if (chain)
    {
    {
      size = ivar_list_length (chain);
      size = ivar_list_length (chain);
      ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
      ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
      initlist = build_ivar_list_initializer (objc_ivar_template, chain);
      initlist = build_ivar_list_initializer (objc_ivar_template, chain);
 
 
      UOBJC_INSTANCE_VARIABLES_decl
      UOBJC_INSTANCE_VARIABLES_decl
        = generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES",
        = generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES",
                               size, initlist);
                               size, initlist);
    }
    }
  else
  else
    UOBJC_INSTANCE_VARIABLES_decl = 0;
    UOBJC_INSTANCE_VARIABLES_decl = 0;
 
 
  generating_instance_variables = 0;
  generating_instance_variables = 0;
}
}
 
 
static tree
static tree
build_dispatch_table_initializer (tree type, tree entries)
build_dispatch_table_initializer (tree type, tree entries)
{
{
  tree initlist = NULL_TREE;
  tree initlist = NULL_TREE;
 
 
  do
  do
    {
    {
      tree elemlist = NULL_TREE;
      tree elemlist = NULL_TREE;
 
 
      elemlist = tree_cons (NULL_TREE,
      elemlist = tree_cons (NULL_TREE,
                            build_selector (METHOD_SEL_NAME (entries)),
                            build_selector (METHOD_SEL_NAME (entries)),
                            NULL_TREE);
                            NULL_TREE);
 
 
      /* Generate the method encoding if we don't have one already.  */
      /* Generate the method encoding if we don't have one already.  */
      if (! METHOD_ENCODING (entries))
      if (! METHOD_ENCODING (entries))
        METHOD_ENCODING (entries) =
        METHOD_ENCODING (entries) =
          encode_method_prototype (entries);
          encode_method_prototype (entries);
 
 
      elemlist = tree_cons (NULL_TREE,
      elemlist = tree_cons (NULL_TREE,
                            add_objc_string (METHOD_ENCODING (entries),
                            add_objc_string (METHOD_ENCODING (entries),
                                             meth_var_types),
                                             meth_var_types),
                            elemlist);
                            elemlist);
 
 
      elemlist
      elemlist
        = tree_cons (NULL_TREE,
        = tree_cons (NULL_TREE,
                     convert (ptr_type_node,
                     convert (ptr_type_node,
                              build_unary_op (input_location, ADDR_EXPR,
                              build_unary_op (input_location, ADDR_EXPR,
                                              METHOD_DEFINITION (entries), 1)),
                                              METHOD_DEFINITION (entries), 1)),
                     elemlist);
                     elemlist);
 
 
      initlist = tree_cons (NULL_TREE,
      initlist = tree_cons (NULL_TREE,
                            objc_build_constructor (type, nreverse (elemlist)),
                            objc_build_constructor (type, nreverse (elemlist)),
                            initlist);
                            initlist);
 
 
      entries = TREE_CHAIN (entries);
      entries = TREE_CHAIN (entries);
    }
    }
  while (entries);
  while (entries);
 
 
  return objc_build_constructor (build_array_type (type, 0),
  return objc_build_constructor (build_array_type (type, 0),
                                 nreverse (initlist));
                                 nreverse (initlist));
}
}
 
 
/* To accomplish method prototyping without generating all kinds of
/* To accomplish method prototyping without generating all kinds of
   inane warnings, the definition of the dispatch table entries were
   inane warnings, the definition of the dispatch table entries were
   changed from:
   changed from:
 
 
        struct objc_method { SEL _cmd; ...; id (*_imp)(); };
        struct objc_method { SEL _cmd; ...; id (*_imp)(); };
   to:
   to:
        struct objc_method { SEL _cmd; ...; void *_imp; };  */
        struct objc_method { SEL _cmd; ...; void *_imp; };  */
 
 
static tree
static tree
build_method_template (void)
build_method_template (void)
{
{
  tree _SLT_record;
  tree _SLT_record;
  tree field_decl, field_decl_chain;
  tree field_decl, field_decl_chain;
 
 
  _SLT_record = objc_start_struct (get_identifier (UTAG_METHOD));
  _SLT_record = objc_start_struct (get_identifier (UTAG_METHOD));
 
 
  /* SEL _cmd; */
  /* SEL _cmd; */
  field_decl = create_field_decl (objc_selector_type, "_cmd");
  field_decl = create_field_decl (objc_selector_type, "_cmd");
  field_decl_chain = field_decl;
  field_decl_chain = field_decl;
 
 
  /* char *method_types; */
  /* char *method_types; */
  field_decl = create_field_decl (string_type_node, "method_types");
  field_decl = create_field_decl (string_type_node, "method_types");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  /* void *_imp; */
  /* void *_imp; */
  field_decl = create_field_decl (build_pointer_type (void_type_node),
  field_decl = create_field_decl (build_pointer_type (void_type_node),
                                  "_imp");
                                  "_imp");
  chainon (field_decl_chain, field_decl);
  chainon (field_decl_chain, field_decl);
 
 
  objc_finish_struct (_SLT_record, field_decl_chain);
  objc_finish_struct (_SLT_record, field_decl_chain);
 
 
  return _SLT_record;
  return _SLT_record;
}
}
 
 
 
 
static tree
static tree
generate_dispatch_table (tree type, const char *name, int size, tree list)
generate_dispatch_table (tree type, const char *name, int size, tree list)
{
{
  tree decl, initlist;
  tree decl, initlist;
 
 
  decl = start_var_decl (type, synth_id_with_class_suffix
  decl = start_var_decl (type, synth_id_with_class_suffix
                               (name, objc_implementation_context));
                               (name, objc_implementation_context));
 
 
  initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
  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, build_int_cst (NULL_TREE, size), initlist);
  initlist = tree_cons (NULL_TREE, list, initlist);
  initlist = tree_cons (NULL_TREE, list, initlist);
 
 
  finish_var_decl (decl,
  finish_var_decl (decl,
                   objc_build_constructor (TREE_TYPE (decl),
                   objc_build_constructor (TREE_TYPE (decl),
                                           nreverse (initlist)));
                                           nreverse (initlist)));
 
 
  return decl;
  return decl;
}
}
 
 
static void
static void
mark_referenced_methods (void)
mark_referenced_methods (void)
{
{
  struct imp_entry *impent;
  struct imp_entry *impent;
  tree chain;
  tree chain;
 
 
  for (impent = imp_list; impent; impent = impent->next)
  for (impent = imp_list; impent; impent = impent->next)
    {
    {
      chain = CLASS_CLS_METHODS (impent->imp_context);
      chain = CLASS_CLS_METHODS (impent->imp_context);
      while (chain)
      while (chain)
        {
        {
          cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
          cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
          chain = TREE_CHAIN (chain);
          chain = TREE_CHAIN (chain);
        }
        }
 
 
      chain = CLASS_NST_METHODS (impent->imp_context);
      chain = CLASS_NST_METHODS (impent->imp_context);
      while (chain)
      while (chain)
        {
        {
          cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
          cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
          chain = TREE_CHAIN (chain);
          chain = TREE_CHAIN (chain);
        }
        }
    }
    }
}
}
 
 
static void
static void
generate_dispatch_tables (void)
generate_dispatch_tables (void)
{
{
  tree initlist, chain, method_list_template;
  tree initlist, chain, method_list_template;
  int size;
  int size;
 
 
  if (!objc_method_template)
  if (!objc_method_template)
    objc_method_template = build_method_template ();
    objc_method_template = build_method_template ();
 
 
  chain = CLASS_CLS_METHODS (objc_implementation_context);
  chain = CLASS_CLS_METHODS (objc_implementation_context);
  if (chain)
  if (chain)
    {
    {
      size = list_length (chain);
      size = list_length (chain);
 
 
      method_list_template
      method_list_template
        = build_method_list_template (objc_method_template, size);
        = build_method_list_template (objc_method_template, size);
      initlist
      initlist
        = build_dispatch_table_initializer (objc_method_template, chain);
        = build_dispatch_table_initializer (objc_method_template, chain);
 
 
      UOBJC_CLASS_METHODS_decl
      UOBJC_CLASS_METHODS_decl
        = generate_dispatch_table (method_list_template,
        = generate_dispatch_table (method_list_template,
                                   ((TREE_CODE (objc_implementation_context)
                                   ((TREE_CODE (objc_implementation_context)
                                     == CLASS_IMPLEMENTATION_TYPE)
                                     == CLASS_IMPLEMENTATION_TYPE)
                                    ? "_OBJC_CLASS_METHODS"
                                    ? "_OBJC_CLASS_METHODS"
                                    : "_OBJC_CATEGORY_CLASS_METHODS"),
                                    : "_OBJC_CATEGORY_CLASS_METHODS"),
                                   size, initlist);
                                   size, initlist);
    }
    }
  else
  else
    UOBJC_CLASS_METHODS_decl = 0;
    UOBJC_CLASS_METHODS_decl = 0;
 
 
  chain = CLASS_NST_METHODS (objc_implementation_context);
  chain = CLASS_NST_METHODS (objc_implementation_context);
  if (chain)
  if (chain)
    {
    {
      size = list_length (chain);
      size = list_length (chain);
 
 
      method_list_template
      method_list_template
        = build_method_list_template (objc_method_template, size);
        = build_method_list_template (objc_method_template, size);
      initlist
      initlist
        = build_dispatch_table_initializer (objc_method_template, chain);
        = build_dispatch_table_initializer (objc_method_template, chain);
 
 
      if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
      if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
        UOBJC_INSTANCE_METHODS_decl
        UOBJC_INSTANCE_METHODS_decl
          = generate_dispatch_table (method_list_template,
          = generate_dispatch_table (method_list_template,
                                     "_OBJC_INSTANCE_METHODS",
                                     "_OBJC_INSTANCE_METHODS",
                                     size, initlist);
                                     size, initlist);
      else
      else
        /* We have a category.  */
        /* We have a category.  */
        UOBJC_INSTANCE_METHODS_decl
        UOBJC_INSTANCE_METHODS_decl
          = generate_dispatch_table (method_list_template,
          = generate_dispatch_table (method_list_template,
                                     "_OBJC_CATEGORY_INSTANCE_METHODS",
                                     "_OBJC_CATEGORY_INSTANCE_METHODS",
                                     size, initlist);
                                     size, initlist);
    }
    }
  else
  else
    UOBJC_INSTANCE_METHODS_decl = 0;
    UOBJC_INSTANCE_METHODS_decl = 0;
}
}
 
 
static tree
static tree
generate_protocol_list (tree i_or_p)
generate_protocol_list (tree i_or_p)
{
{
  tree initlist;
  tree initlist;
  tree refs_decl, lproto, e, plist;
  tree refs_decl, lproto, e, plist;
  int size = 0;
  int size = 0;
  const char *ref_name;
  const char *ref_name;
 
 
  if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE
  if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE
      || TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
      || TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
    plist = CLASS_PROTOCOL_LIST (i_or_p);
    plist = CLASS_PROTOCOL_LIST (i_or_p);
  else if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE)
  else if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE)
    plist = PROTOCOL_LIST (i_or_p);
    plist = PROTOCOL_LIST (i_or_p);
  else
  else
    abort ();
    abort ();
 
 
  /* Compute size.  */
  /* Compute size.  */
  for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
  for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
    if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE
    if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE
        && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto)))
        && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto)))
      size++;
      size++;
 
 
  /* Build initializer.  */
  /* Build initializer.  */
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), NULL_TREE);
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), NULL_TREE);
  e = build_int_cst (build_pointer_type (objc_protocol_template), size);
  e = build_int_cst (build_pointer_type (objc_protocol_template), size);
  initlist = tree_cons (NULL_TREE, e, initlist);
  initlist = tree_cons (NULL_TREE, e, initlist);
 
 
  for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
  for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
    {
    {
      tree pval = TREE_VALUE (lproto);
      tree pval = TREE_VALUE (lproto);
 
 
      if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE
      if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE
          && PROTOCOL_FORWARD_DECL (pval))
          && PROTOCOL_FORWARD_DECL (pval))
        {
        {
          e = build_unary_op (input_location, ADDR_EXPR,
          e = build_unary_op (input_location, ADDR_EXPR,
                              PROTOCOL_FORWARD_DECL (pval), 0);
                              PROTOCOL_FORWARD_DECL (pval), 0);
          initlist = tree_cons (NULL_TREE, e, initlist);
          initlist = tree_cons (NULL_TREE, e, initlist);
        }
        }
    }
    }
 
 
  /* static struct objc_protocol *refs[n]; */
  /* static struct objc_protocol *refs[n]; */
 
 
  if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE)
  if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE)
    ref_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS", i_or_p);
    ref_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS", i_or_p);
  else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE)
  else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE)
    ref_name = synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS", i_or_p);
    ref_name = synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS", i_or_p);
  else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
  else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
    ref_name = synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS", i_or_p);
    ref_name = synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS", i_or_p);
  else
  else
    abort ();
    abort ();
 
 
  refs_decl = start_var_decl
  refs_decl = start_var_decl
              (build_array_type
              (build_array_type
               (build_pointer_type (objc_protocol_template),
               (build_pointer_type (objc_protocol_template),
                build_index_type (build_int_cst (NULL_TREE, size + 2))),
                build_index_type (build_int_cst (NULL_TREE, size + 2))),
               ref_name);
               ref_name);
 
 
  finish_var_decl (refs_decl, objc_build_constructor (TREE_TYPE (refs_decl),
  finish_var_decl (refs_decl, objc_build_constructor (TREE_TYPE (refs_decl),
                                                      nreverse (initlist)));
                                                      nreverse (initlist)));
 
 
  return refs_decl;
  return refs_decl;
}
}
 
 
static tree
static tree
build_category_initializer (tree type, tree cat_name, tree class_name,
build_category_initializer (tree type, tree cat_name, tree class_name,
                            tree instance_methods, tree class_methods,
                            tree instance_methods, tree class_methods,
                            tree protocol_list)
                            tree protocol_list)
{
{
  tree initlist = NULL_TREE, expr;
  tree initlist = NULL_TREE, expr;
 
 
  initlist = tree_cons (NULL_TREE, cat_name, initlist);
  initlist = tree_cons (NULL_TREE, cat_name, initlist);
  initlist = tree_cons (NULL_TREE, class_name, initlist);
  initlist = tree_cons (NULL_TREE, class_name, initlist);
 
 
  if (!instance_methods)
  if (!instance_methods)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (objc_method_list_ptr,
      expr = convert (objc_method_list_ptr,
                      build_unary_op (input_location, ADDR_EXPR,
                      build_unary_op (input_location, ADDR_EXPR,
                                      instance_methods, 0));
                                      instance_methods, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
  if (!class_methods)
  if (!class_methods)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (objc_method_list_ptr,
      expr = convert (objc_method_list_ptr,
                      build_unary_op (input_location, ADDR_EXPR,
                      build_unary_op (input_location, ADDR_EXPR,
                                      class_methods, 0));
                                      class_methods, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  /* protocol_list = */
  /* protocol_list = */
  if (!protocol_list)
  if (!protocol_list)
     initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
     initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (build_pointer_type
      expr = convert (build_pointer_type
                      (build_pointer_type
                      (build_pointer_type
                       (objc_protocol_template)),
                       (objc_protocol_template)),
                      build_unary_op (input_location, ADDR_EXPR,
                      build_unary_op (input_location, ADDR_EXPR,
                                      protocol_list, 0));
                                      protocol_list, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  return objc_build_constructor (type, nreverse (initlist));
  return objc_build_constructor (type, nreverse (initlist));
}
}
 
 
/* struct _objc_class {
/* struct _objc_class {
     struct objc_class *isa;
     struct objc_class *isa;
     struct objc_class *super_class;
     struct objc_class *super_class;
     char *name;
     char *name;
     long version;
     long version;
     long info;
     long info;
     long instance_size;
     long instance_size;
     struct objc_ivar_list *ivars;
     struct objc_ivar_list *ivars;
     struct objc_method_list *methods;
     struct objc_method_list *methods;
     if (flag_next_runtime)
     if (flag_next_runtime)
       struct objc_cache *cache;
       struct objc_cache *cache;
     else {
     else {
       struct sarray *dtable;
       struct sarray *dtable;
       struct objc_class *subclass_list;
       struct objc_class *subclass_list;
       struct objc_class *sibling_class;
       struct objc_class *sibling_class;
     }
     }
     struct objc_protocol_list *protocols;
     struct objc_protocol_list *protocols;
     if (flag_next_runtime)
     if (flag_next_runtime)
       void *sel_id;
       void *sel_id;
     void *gc_object_type;
     void *gc_object_type;
   };  */
   };  */
 
 
static tree
static tree
build_shared_structure_initializer (tree type, tree isa, tree super,
build_shared_structure_initializer (tree type, tree isa, tree super,
                                    tree name, tree size, int status,
                                    tree name, tree size, int status,
                                    tree dispatch_table, tree ivar_list,
                                    tree dispatch_table, tree ivar_list,
                                    tree protocol_list)
                                    tree protocol_list)
{
{
  tree initlist = NULL_TREE, expr;
  tree initlist = NULL_TREE, expr;
 
 
  /* isa = */
  /* isa = */
  initlist = tree_cons (NULL_TREE, isa, initlist);
  initlist = tree_cons (NULL_TREE, isa, initlist);
 
 
  /* super_class = */
  /* super_class = */
  initlist = tree_cons (NULL_TREE, super, initlist);
  initlist = tree_cons (NULL_TREE, super, initlist);
 
 
  /* name = */
  /* name = */
  initlist = tree_cons (NULL_TREE, default_conversion (name), initlist);
  initlist = tree_cons (NULL_TREE, default_conversion (name), initlist);
 
 
  /* version = */
  /* version = */
  initlist = tree_cons (NULL_TREE, build_int_cst (long_integer_type_node, 0),
  initlist = tree_cons (NULL_TREE, build_int_cst (long_integer_type_node, 0),
                        initlist);
                        initlist);
 
 
  /* info = */
  /* info = */
  initlist = tree_cons (NULL_TREE,
  initlist = tree_cons (NULL_TREE,
                        build_int_cst (long_integer_type_node, status),
                        build_int_cst (long_integer_type_node, status),
                        initlist);
                        initlist);
 
 
  /* instance_size = */
  /* instance_size = */
  initlist = tree_cons (NULL_TREE, convert (long_integer_type_node, size),
  initlist = tree_cons (NULL_TREE, convert (long_integer_type_node, size),
                        initlist);
                        initlist);
 
 
  /* objc_ivar_list = */
  /* objc_ivar_list = */
  if (!ivar_list)
  if (!ivar_list)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (objc_ivar_list_ptr,
      expr = convert (objc_ivar_list_ptr,
                      build_unary_op (input_location, ADDR_EXPR,
                      build_unary_op (input_location, ADDR_EXPR,
                                      ivar_list, 0));
                                      ivar_list, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  /* objc_method_list = */
  /* objc_method_list = */
  if (!dispatch_table)
  if (!dispatch_table)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (objc_method_list_ptr,
      expr = convert (objc_method_list_ptr,
                      build_unary_op (input_location, ADDR_EXPR,
                      build_unary_op (input_location, ADDR_EXPR,
                                      dispatch_table, 0));
                                      dispatch_table, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    /* method_cache = */
    /* method_cache = */
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      /* dtable = */
      /* dtable = */
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
 
 
      /* subclass_list = */
      /* subclass_list = */
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
 
 
      /* sibling_class = */
      /* sibling_class = */
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
      initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    }
    }
 
 
  /* protocol_list = */
  /* protocol_list = */
  if (! protocol_list)
  if (! protocol_list)
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  else
  else
    {
    {
      expr = convert (build_pointer_type
      expr = convert (build_pointer_type
                      (build_pointer_type
                      (build_pointer_type
                       (objc_protocol_template)),
                       (objc_protocol_template)),
                      build_unary_op (input_location, ADDR_EXPR,
                      build_unary_op (input_location, ADDR_EXPR,
                                      protocol_list, 0));
                                      protocol_list, 0));
      initlist = tree_cons (NULL_TREE, expr, initlist);
      initlist = tree_cons (NULL_TREE, expr, initlist);
    }
    }
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    /* sel_id = NULL */
    /* sel_id = NULL */
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
    initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
 
 
  /* gc_object_type = NULL */
  /* gc_object_type = NULL */
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
 
 
  return objc_build_constructor (type, nreverse (initlist));
  return objc_build_constructor (type, nreverse (initlist));
}
}
 
 
/* Retrieve category interface CAT_NAME (if any) associated with CLASS.  */
/* Retrieve category interface CAT_NAME (if any) associated with CLASS.  */
 
 
static inline tree
static inline tree
lookup_category (tree klass, tree cat_name)
lookup_category (tree klass, tree cat_name)
{
{
  tree category = CLASS_CATEGORY_LIST (klass);
  tree category = CLASS_CATEGORY_LIST (klass);
 
 
  while (category && CLASS_SUPER_NAME (category) != cat_name)
  while (category && CLASS_SUPER_NAME (category) != cat_name)
    category = CLASS_CATEGORY_LIST (category);
    category = CLASS_CATEGORY_LIST (category);
  return category;
  return category;
}
}
 
 
/* static struct objc_category _OBJC_CATEGORY_<name> = { ... };  */
/* static struct objc_category _OBJC_CATEGORY_<name> = { ... };  */
 
 
static void
static void
generate_category (tree cat)
generate_category (tree cat)
{
{
  tree decl;
  tree decl;
  tree initlist, cat_name_expr, class_name_expr;
  tree initlist, cat_name_expr, class_name_expr;
  tree protocol_decl, category;
  tree protocol_decl, category;
 
 
  add_class_reference (CLASS_NAME (cat));
  add_class_reference (CLASS_NAME (cat));
  cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names);
  cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names);
 
 
  class_name_expr = add_objc_string (CLASS_NAME (cat), class_names);
  class_name_expr = add_objc_string (CLASS_NAME (cat), class_names);
 
 
  category = lookup_category (implementation_template,
  category = lookup_category (implementation_template,
                                CLASS_SUPER_NAME (cat));
                                CLASS_SUPER_NAME (cat));
 
 
  if (category && CLASS_PROTOCOL_LIST (category))
  if (category && CLASS_PROTOCOL_LIST (category))
    {
    {
      generate_protocol_references (CLASS_PROTOCOL_LIST (category));
      generate_protocol_references (CLASS_PROTOCOL_LIST (category));
      protocol_decl = generate_protocol_list (category);
      protocol_decl = generate_protocol_list (category);
    }
    }
  else
  else
    protocol_decl = 0;
    protocol_decl = 0;
 
 
  decl = start_var_decl (objc_category_template,
  decl = start_var_decl (objc_category_template,
                         synth_id_with_class_suffix
                         synth_id_with_class_suffix
                         ("_OBJC_CATEGORY", objc_implementation_context));
                         ("_OBJC_CATEGORY", objc_implementation_context));
 
 
  initlist = build_category_initializer (TREE_TYPE (decl),
  initlist = build_category_initializer (TREE_TYPE (decl),
                                         cat_name_expr, class_name_expr,
                                         cat_name_expr, class_name_expr,
                                         UOBJC_INSTANCE_METHODS_decl,
                                         UOBJC_INSTANCE_METHODS_decl,
                                         UOBJC_CLASS_METHODS_decl,
                                         UOBJC_CLASS_METHODS_decl,
                                         protocol_decl);
                                         protocol_decl);
 
 
  finish_var_decl (decl, initlist);
  finish_var_decl (decl, initlist);
}
}
 
 
/* static struct objc_class _OBJC_METACLASS_Foo={ ... };
/* static struct objc_class _OBJC_METACLASS_Foo={ ... };
   static struct objc_class _OBJC_CLASS_Foo={ ... };  */
   static struct objc_class _OBJC_CLASS_Foo={ ... };  */
 
 
static void
static void
generate_shared_structures (int cls_flags)
generate_shared_structures (int cls_flags)
{
{
  tree decl;
  tree decl;
  tree name_expr, super_expr, root_expr;
  tree name_expr, super_expr, root_expr;
  tree my_root_id = NULL_TREE, my_super_id = NULL_TREE;
  tree my_root_id = NULL_TREE, my_super_id = NULL_TREE;
  tree cast_type, initlist, protocol_decl;
  tree cast_type, initlist, protocol_decl;
 
 
  my_super_id = CLASS_SUPER_NAME (implementation_template);
  my_super_id = CLASS_SUPER_NAME (implementation_template);
  if (my_super_id)
  if (my_super_id)
    {
    {
      add_class_reference (my_super_id);
      add_class_reference (my_super_id);
 
 
      /* Compute "my_root_id" - this is required for code generation.
      /* Compute "my_root_id" - this is required for code generation.
         the "isa" for all meta class structures points to the root of
         the "isa" for all meta class structures points to the root of
         the inheritance hierarchy (e.g. "__Object")...  */
         the inheritance hierarchy (e.g. "__Object")...  */
      my_root_id = my_super_id;
      my_root_id = my_super_id;
      do
      do
        {
        {
          tree my_root_int = lookup_interface (my_root_id);
          tree my_root_int = lookup_interface (my_root_id);
 
 
          if (my_root_int && CLASS_SUPER_NAME (my_root_int))
          if (my_root_int && CLASS_SUPER_NAME (my_root_int))
            my_root_id = CLASS_SUPER_NAME (my_root_int);
            my_root_id = CLASS_SUPER_NAME (my_root_int);
          else
          else
            break;
            break;
        }
        }
      while (1);
      while (1);
    }
    }
  else
  else
    /* No super class.  */
    /* No super class.  */
    my_root_id = CLASS_NAME (implementation_template);
    my_root_id = CLASS_NAME (implementation_template);
 
 
  cast_type = build_pointer_type (objc_class_template);
  cast_type = build_pointer_type (objc_class_template);
  name_expr = add_objc_string (CLASS_NAME (implementation_template),
  name_expr = add_objc_string (CLASS_NAME (implementation_template),
                               class_names);
                               class_names);
 
 
  /* Install class `isa' and `super' pointers at runtime.  */
  /* Install class `isa' and `super' pointers at runtime.  */
  if (my_super_id)
  if (my_super_id)
    {
    {
      super_expr = add_objc_string (my_super_id, class_names);
      super_expr = add_objc_string (my_super_id, class_names);
      super_expr = build_c_cast (input_location,
      super_expr = build_c_cast (input_location,
                                 cast_type, super_expr); /* cast! */
                                 cast_type, super_expr); /* cast! */
    }
    }
  else
  else
    super_expr = build_int_cst (NULL_TREE, 0);
    super_expr = build_int_cst (NULL_TREE, 0);
 
 
  root_expr = add_objc_string (my_root_id, class_names);
  root_expr = add_objc_string (my_root_id, class_names);
  root_expr = build_c_cast (input_location, cast_type, root_expr); /* cast! */
  root_expr = build_c_cast (input_location, cast_type, root_expr); /* cast! */
 
 
  if (CLASS_PROTOCOL_LIST (implementation_template))
  if (CLASS_PROTOCOL_LIST (implementation_template))
    {
    {
      generate_protocol_references
      generate_protocol_references
        (CLASS_PROTOCOL_LIST (implementation_template));
        (CLASS_PROTOCOL_LIST (implementation_template));
      protocol_decl = generate_protocol_list (implementation_template);
      protocol_decl = generate_protocol_list (implementation_template);
    }
    }
  else
  else
    protocol_decl = 0;
    protocol_decl = 0;
 
 
  /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */
  /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */
 
 
  decl = start_var_decl (objc_class_template,
  decl = start_var_decl (objc_class_template,
                         IDENTIFIER_POINTER
                         IDENTIFIER_POINTER
                         (DECL_NAME (UOBJC_METACLASS_decl)));
                         (DECL_NAME (UOBJC_METACLASS_decl)));
 
 
  initlist
  initlist
    = build_shared_structure_initializer
    = build_shared_structure_initializer
      (TREE_TYPE (decl),
      (TREE_TYPE (decl),
       root_expr, super_expr, name_expr,
       root_expr, super_expr, name_expr,
       convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)),
       convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)),
       2 /*CLS_META*/,
       2 /*CLS_META*/,
       UOBJC_CLASS_METHODS_decl,
       UOBJC_CLASS_METHODS_decl,
       UOBJC_CLASS_VARIABLES_decl,
       UOBJC_CLASS_VARIABLES_decl,
       protocol_decl);
       protocol_decl);
 
 
  finish_var_decl (decl, initlist);
  finish_var_decl (decl, initlist);
 
 
  /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */
  /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */
 
 
  decl = start_var_decl (objc_class_template,
  decl = start_var_decl (objc_class_template,
                         IDENTIFIER_POINTER
                         IDENTIFIER_POINTER
                         (DECL_NAME (UOBJC_CLASS_decl)));
                         (DECL_NAME (UOBJC_CLASS_decl)));
 
 
  initlist
  initlist
    = build_shared_structure_initializer
    = build_shared_structure_initializer
      (TREE_TYPE (decl),
      (TREE_TYPE (decl),
       build_unary_op (input_location, ADDR_EXPR, UOBJC_METACLASS_decl, 0),
       build_unary_op (input_location, ADDR_EXPR, UOBJC_METACLASS_decl, 0),
       super_expr, name_expr,
       super_expr, name_expr,
       convert (integer_type_node,
       convert (integer_type_node,
                TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE
                TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE
                                (implementation_template))),
                                (implementation_template))),
       1 /*CLS_FACTORY*/ | cls_flags,
       1 /*CLS_FACTORY*/ | cls_flags,
       UOBJC_INSTANCE_METHODS_decl,
       UOBJC_INSTANCE_METHODS_decl,
       UOBJC_INSTANCE_VARIABLES_decl,
       UOBJC_INSTANCE_VARIABLES_decl,
       protocol_decl);
       protocol_decl);
 
 
  finish_var_decl (decl, initlist);
  finish_var_decl (decl, initlist);
}
}
 
 
 
 
static const char *
static const char *
synth_id_with_class_suffix (const char *preamble, tree ctxt)
synth_id_with_class_suffix (const char *preamble, tree ctxt)
{
{
  static char string[BUFSIZE];
  static char string[BUFSIZE];
 
 
  if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE
  if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE
      || TREE_CODE (ctxt) == CLASS_INTERFACE_TYPE)
      || TREE_CODE (ctxt) == CLASS_INTERFACE_TYPE)
    {
    {
      sprintf (string, "%s_%s", preamble,
      sprintf (string, "%s_%s", preamble,
               IDENTIFIER_POINTER (CLASS_NAME (ctxt)));
               IDENTIFIER_POINTER (CLASS_NAME (ctxt)));
    }
    }
  else if (TREE_CODE (ctxt) == CATEGORY_IMPLEMENTATION_TYPE
  else if (TREE_CODE (ctxt) == CATEGORY_IMPLEMENTATION_TYPE
           || TREE_CODE (ctxt) == CATEGORY_INTERFACE_TYPE)
           || TREE_CODE (ctxt) == CATEGORY_INTERFACE_TYPE)
    {
    {
      /* We have a category.  */
      /* We have a category.  */
      const char *const class_name
      const char *const class_name
        = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context));
        = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context));
      const char *const class_super_name
      const char *const class_super_name
        = IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context));
        = IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context));
      sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name);
      sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name);
    }
    }
  else if (TREE_CODE (ctxt) == PROTOCOL_INTERFACE_TYPE)
  else if (TREE_CODE (ctxt) == PROTOCOL_INTERFACE_TYPE)
    {
    {
      const char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt));
      const char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt));
      sprintf (string, "%s_%s", preamble, protocol_name);
      sprintf (string, "%s_%s", preamble, protocol_name);
    }
    }
  else
  else
    abort ();
    abort ();
 
 
  return string;
  return string;
}
}
 
 
/* If type is empty or only type qualifiers are present, add default
/* If type is empty or only type qualifiers are present, add default
   type of id (otherwise grokdeclarator will default to int).  */
   type of id (otherwise grokdeclarator will default to int).  */
 
 
static tree
static tree
adjust_type_for_id_default (tree type)
adjust_type_for_id_default (tree type)
{
{
  if (!type)
  if (!type)
    type = make_node (TREE_LIST);
    type = make_node (TREE_LIST);
 
 
  if (!TREE_VALUE (type))
  if (!TREE_VALUE (type))
    TREE_VALUE (type) = objc_object_type;
    TREE_VALUE (type) = objc_object_type;
  else if (TREE_CODE (TREE_VALUE (type)) == RECORD_TYPE
  else if (TREE_CODE (TREE_VALUE (type)) == RECORD_TYPE
           && TYPED_OBJECT (TREE_VALUE (type)))
           && TYPED_OBJECT (TREE_VALUE (type)))
    error ("can not use an object as parameter to a method");
    error ("can not use an object as parameter to a method");
 
 
  return type;
  return type;
}
}
 
 
/*   Usage:
/*   Usage:
                keyworddecl:
                keyworddecl:
                        selector ':' '(' typename ')' identifier
                        selector ':' '(' typename ')' identifier
 
 
     Purpose:
     Purpose:
                Transform an Objective-C keyword argument into
                Transform an Objective-C keyword argument into
                the C equivalent parameter declarator.
                the C equivalent parameter declarator.
 
 
     In:        key_name, an "identifier_node" (optional).
     In:        key_name, an "identifier_node" (optional).
                arg_type, a  "tree_list" (optional).
                arg_type, a  "tree_list" (optional).
                arg_name, an "identifier_node".
                arg_name, an "identifier_node".
 
 
     Note:      It would be really nice to strongly type the preceding
     Note:      It would be really nice to strongly type the preceding
                arguments in the function prototype; however, then I
                arguments in the function prototype; however, then I
                could not use the "accessor" macros defined in "tree.h".
                could not use the "accessor" macros defined in "tree.h".
 
 
     Out:       an instance of "keyword_decl".  */
     Out:       an instance of "keyword_decl".  */
 
 
tree
tree
objc_build_keyword_decl (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;
  tree keyword_decl;
 
 
  /* If no type is specified, default to "id".  */
  /* If no type is specified, default to "id".  */
  arg_type = adjust_type_for_id_default (arg_type);
  arg_type = adjust_type_for_id_default (arg_type);
 
 
  keyword_decl = make_node (KEYWORD_DECL);
  keyword_decl = make_node (KEYWORD_DECL);
 
 
  TREE_TYPE (keyword_decl) = arg_type;
  TREE_TYPE (keyword_decl) = arg_type;
  KEYWORD_ARG_NAME (keyword_decl) = arg_name;
  KEYWORD_ARG_NAME (keyword_decl) = arg_name;
  KEYWORD_KEY_NAME (keyword_decl) = key_name;
  KEYWORD_KEY_NAME (keyword_decl) = key_name;
 
 
  return keyword_decl;
  return keyword_decl;
}
}
 
 
/* Given a chain of keyword_decl's, synthesize the full keyword selector.  */
/* Given a chain of keyword_decl's, synthesize the full keyword selector.  */
 
 
static tree
static tree
build_keyword_selector (tree selector)
build_keyword_selector (tree selector)
{
{
  int len = 0;
  int len = 0;
  tree key_chain, key_name;
  tree key_chain, key_name;
  char *buf;
  char *buf;
 
 
  /* Scan the selector to see how much space we'll need.  */
  /* Scan the selector to see how much space we'll need.  */
  for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
  for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
    {
    {
      if (TREE_CODE (selector) == KEYWORD_DECL)
      if (TREE_CODE (selector) == KEYWORD_DECL)
        key_name = KEYWORD_KEY_NAME (key_chain);
        key_name = KEYWORD_KEY_NAME (key_chain);
      else if (TREE_CODE (selector) == TREE_LIST)
      else if (TREE_CODE (selector) == TREE_LIST)
        key_name = TREE_PURPOSE (key_chain);
        key_name = TREE_PURPOSE (key_chain);
      else
      else
        abort ();
        abort ();
 
 
      if (key_name)
      if (key_name)
        len += IDENTIFIER_LENGTH (key_name) + 1;
        len += IDENTIFIER_LENGTH (key_name) + 1;
      else
      else
        /* Just a ':' arg.  */
        /* Just a ':' arg.  */
        len++;
        len++;
    }
    }
 
 
  buf = (char *) alloca (len + 1);
  buf = (char *) alloca (len + 1);
  /* Start the buffer out as an empty string.  */
  /* Start the buffer out as an empty string.  */
  buf[0] = '\0';
  buf[0] = '\0';
 
 
  for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
  for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
    {
    {
      if (TREE_CODE (selector) == KEYWORD_DECL)
      if (TREE_CODE (selector) == KEYWORD_DECL)
        key_name = KEYWORD_KEY_NAME (key_chain);
        key_name = KEYWORD_KEY_NAME (key_chain);
      else if (TREE_CODE (selector) == TREE_LIST)
      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
          /* The keyword decl chain will later be used as a function argument
             chain.  Unhook the selector itself so as to not confuse other
             chain.  Unhook the selector itself so as to not confuse other
             parts of the compiler.  */
             parts of the compiler.  */
          TREE_PURPOSE (key_chain) = NULL_TREE;
          TREE_PURPOSE (key_chain) = NULL_TREE;
        }
        }
      else
      else
        abort ();
        abort ();
 
 
      if (key_name)
      if (key_name)
        strcat (buf, IDENTIFIER_POINTER (key_name));
        strcat (buf, IDENTIFIER_POINTER (key_name));
      strcat (buf, ":");
      strcat (buf, ":");
    }
    }
 
 
  return get_identifier (buf);
  return get_identifier (buf);
}
}
 
 
/* Used for declarations and definitions.  */
/* Used for declarations and definitions.  */
 
 
static tree
static tree
build_method_decl (enum tree_code code, tree ret_type, tree selector,
build_method_decl (enum tree_code code, tree ret_type, tree selector,
                   tree add_args, bool ellipsis)
                   tree add_args, bool ellipsis)
{
{
  tree method_decl;
  tree method_decl;
 
 
  /* If no type is specified, default to "id".  */
  /* If no type is specified, default to "id".  */
  ret_type = adjust_type_for_id_default (ret_type);
  ret_type = adjust_type_for_id_default (ret_type);
 
 
  method_decl = make_node (code);
  method_decl = make_node (code);
  TREE_TYPE (method_decl) = ret_type;
  TREE_TYPE (method_decl) = ret_type;
 
 
  /* If we have a keyword selector, create an identifier_node that
  /* If we have a keyword selector, create an identifier_node that
     represents the full selector name (`:' included)...  */
     represents the full selector name (`:' included)...  */
  if (TREE_CODE (selector) == KEYWORD_DECL)
  if (TREE_CODE (selector) == KEYWORD_DECL)
    {
    {
      METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector);
      METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector);
      METHOD_SEL_ARGS (method_decl) = selector;
      METHOD_SEL_ARGS (method_decl) = selector;
      METHOD_ADD_ARGS (method_decl) = add_args;
      METHOD_ADD_ARGS (method_decl) = add_args;
      METHOD_ADD_ARGS_ELLIPSIS_P (method_decl) = ellipsis;
      METHOD_ADD_ARGS_ELLIPSIS_P (method_decl) = ellipsis;
    }
    }
  else
  else
    {
    {
      METHOD_SEL_NAME (method_decl) = selector;
      METHOD_SEL_NAME (method_decl) = selector;
      METHOD_SEL_ARGS (method_decl) = NULL_TREE;
      METHOD_SEL_ARGS (method_decl) = NULL_TREE;
      METHOD_ADD_ARGS (method_decl) = NULL_TREE;
      METHOD_ADD_ARGS (method_decl) = NULL_TREE;
    }
    }
 
 
  return method_decl;
  return method_decl;
}
}
 
 
#define METHOD_DEF 0
#define METHOD_DEF 0
#define METHOD_REF 1
#define METHOD_REF 1
 
 
/* Used by `build_objc_method_call' and `comp_proto_with_proto'.  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
   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
   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
   one.  SUPERFLAG says this is for a send to super; this makes a
   difference for the NeXT calling sequence in which the lookup and
   difference for the NeXT calling sequence in which the lookup and
   the method call are done together.  If METH is null, user-defined
   the method call are done together.  If METH is null, user-defined
   arguments (i.e., beyond self and _cmd) shall be represented by `...'.  */
   arguments (i.e., beyond self and _cmd) shall be represented by `...'.  */
 
 
static tree
static tree
get_arg_type_list (tree meth, int context, int superflag)
get_arg_type_list (tree meth, int context, int superflag)
{
{
  tree arglist, akey;
  tree arglist, akey;
 
 
  /* Receiver type.  */
  /* Receiver type.  */
  if (flag_next_runtime && superflag)
  if (flag_next_runtime && superflag)
    arglist = build_tree_list (NULL_TREE, objc_super_type);
    arglist = build_tree_list (NULL_TREE, objc_super_type);
  else if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL)
  else if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL)
    arglist = build_tree_list (NULL_TREE, objc_instance_type);
    arglist = build_tree_list (NULL_TREE, objc_instance_type);
  else
  else
    arglist = build_tree_list (NULL_TREE, objc_object_type);
    arglist = build_tree_list (NULL_TREE, objc_object_type);
 
 
  /* Selector type - will eventually change to `int'.  */
  /* Selector type - will eventually change to `int'.  */
  chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type));
  chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type));
 
 
  /* No actual method prototype given -- assume that remaining arguments
  /* No actual method prototype given -- assume that remaining arguments
     are `...'.  */
     are `...'.  */
  if (!meth)
  if (!meth)
    return arglist;
    return arglist;
 
 
  /* Build a list of argument types.  */
  /* Build a list of argument types.  */
  for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey))
  for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey))
    {
    {
      tree arg_type = TREE_VALUE (TREE_TYPE (akey));
      tree arg_type = TREE_VALUE (TREE_TYPE (akey));
 
 
      /* Decay arrays and functions into pointers.  */
      /* Decay arrays and functions into pointers.  */
      if (TREE_CODE (arg_type) == ARRAY_TYPE)
      if (TREE_CODE (arg_type) == ARRAY_TYPE)
        arg_type = build_pointer_type (TREE_TYPE (arg_type));
        arg_type = build_pointer_type (TREE_TYPE (arg_type));
      else if (TREE_CODE (arg_type) == FUNCTION_TYPE)
      else if (TREE_CODE (arg_type) == FUNCTION_TYPE)
        arg_type = build_pointer_type (arg_type);
        arg_type = build_pointer_type (arg_type);
 
 
      chainon (arglist, build_tree_list (NULL_TREE, arg_type));
      chainon (arglist, build_tree_list (NULL_TREE, arg_type));
    }
    }
 
 
  if (METHOD_ADD_ARGS (meth))
  if (METHOD_ADD_ARGS (meth))
    {
    {
      for (akey = TREE_CHAIN (METHOD_ADD_ARGS (meth));
      for (akey = TREE_CHAIN (METHOD_ADD_ARGS (meth));
           akey; akey = TREE_CHAIN (akey))
           akey; akey = TREE_CHAIN (akey))
        {
        {
          tree arg_type = TREE_TYPE (TREE_VALUE (akey));
          tree arg_type = TREE_TYPE (TREE_VALUE (akey));
 
 
          chainon (arglist, build_tree_list (NULL_TREE, arg_type));
          chainon (arglist, build_tree_list (NULL_TREE, arg_type));
        }
        }
 
 
      if (!METHOD_ADD_ARGS_ELLIPSIS_P (meth))
      if (!METHOD_ADD_ARGS_ELLIPSIS_P (meth))
        goto lack_of_ellipsis;
        goto lack_of_ellipsis;
    }
    }
  else
  else
    {
    {
     lack_of_ellipsis:
     lack_of_ellipsis:
      chainon (arglist, OBJC_VOID_AT_END);
      chainon (arglist, OBJC_VOID_AT_END);
    }
    }
 
 
  return arglist;
  return arglist;
}
}
 
 
static tree
static tree
check_duplicates (hash hsh, int methods, int is_class)
check_duplicates (hash hsh, int methods, int is_class)
{
{
  tree meth = NULL_TREE;
  tree meth = NULL_TREE;
 
 
  if (hsh)
  if (hsh)
    {
    {
      meth = hsh->key;
      meth = hsh->key;
 
 
      if (hsh->list)
      if (hsh->list)
        {
        {
          /* We have two or more methods with the same name but
          /* We have two or more methods with the same name but
             different types.  */
             different types.  */
          attr loop;
          attr loop;
 
 
          /* But just how different are those types?  If
          /* But just how different are those types?  If
             -Wno-strict-selector-match is specified, we shall not
             -Wno-strict-selector-match is specified, we shall not
             complain if the differences are solely among types with
             complain if the differences are solely among types with
             identical size and alignment.  */
             identical size and alignment.  */
          if (!warn_strict_selector_match)
          if (!warn_strict_selector_match)
            {
            {
              for (loop = hsh->list; loop; loop = loop->next)
              for (loop = hsh->list; loop; loop = loop->next)
                if (!comp_proto_with_proto (meth, loop->value, 0))
                if (!comp_proto_with_proto (meth, loop->value, 0))
                  goto issue_warning;
                  goto issue_warning;
 
 
              return meth;
              return meth;
            }
            }
 
 
        issue_warning:
        issue_warning:
          if (methods)
          if (methods)
            {
            {
              bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
              bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
 
 
              warning_at (input_location, 0,
              warning_at (input_location, 0,
                          "multiple methods named %<%c%E%> found",
                          "multiple methods named %<%c%E%> found",
                          (is_class ? '+' : '-'),
                          (is_class ? '+' : '-'),
                          METHOD_SEL_NAME (meth));
                          METHOD_SEL_NAME (meth));
              inform (DECL_SOURCE_LOCATION (meth), "using %<%c%s%>",
              inform (DECL_SOURCE_LOCATION (meth), "using %<%c%s%>",
                      (type ? '-' : '+'),
                      (type ? '-' : '+'),
                      identifier_to_locale (gen_method_decl (meth)));
                      identifier_to_locale (gen_method_decl (meth)));
            }
            }
          else
          else
            {
            {
              bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
              bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
 
 
              warning_at (input_location, 0,
              warning_at (input_location, 0,
                          "multiple selectors named %<%c%E%> found",
                          "multiple selectors named %<%c%E%> found",
                          (is_class ? '+' : '-'),
                          (is_class ? '+' : '-'),
                          METHOD_SEL_NAME (meth));
                          METHOD_SEL_NAME (meth));
              inform (DECL_SOURCE_LOCATION (meth), "found %<%c%s%>",
              inform (DECL_SOURCE_LOCATION (meth), "found %<%c%s%>",
                      (type ? '-' : '+'),
                      (type ? '-' : '+'),
                      identifier_to_locale (gen_method_decl (meth)));
                      identifier_to_locale (gen_method_decl (meth)));
            }
            }
 
 
          for (loop = hsh->list; loop; loop = loop->next)
          for (loop = hsh->list; loop; loop = loop->next)
            {
            {
              bool type = TREE_CODE (loop->value) == INSTANCE_METHOD_DECL;
              bool type = TREE_CODE (loop->value) == INSTANCE_METHOD_DECL;
 
 
              inform (DECL_SOURCE_LOCATION (loop->value), "also found %<%c%s%>",
              inform (DECL_SOURCE_LOCATION (loop->value), "also found %<%c%s%>",
                      (type ? '-' : '+'),
                      (type ? '-' : '+'),
                      identifier_to_locale (gen_method_decl (loop->value)));
                      identifier_to_locale (gen_method_decl (loop->value)));
            }
            }
        }
        }
    }
    }
  return meth;
  return meth;
}
}
 
 
/* If RECEIVER is a class reference, return the identifier node for
/* If RECEIVER is a class reference, return the identifier node for
   the referenced class.  RECEIVER is created by objc_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
   so we check the exact form created depending on which runtimes are
   used.  */
   used.  */
 
 
static tree
static tree
receiver_is_class_object (tree receiver, int self, int super)
receiver_is_class_object (tree receiver, int self, int super)
{
{
  tree chain, exp, arg;
  tree chain, exp, arg;
 
 
  /* The receiver is 'self' or 'super' in the context of a class method.  */
  /* The receiver is 'self' or 'super' in the context of a class method.  */
  if (objc_method_context
  if (objc_method_context
      && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL
      && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL
      && (self || super))
      && (self || super))
    return (super
    return (super
            ? CLASS_SUPER_NAME (implementation_template)
            ? CLASS_SUPER_NAME (implementation_template)
            : CLASS_NAME (implementation_template));
            : CLASS_NAME (implementation_template));
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      /* The receiver is a variable created by
      /* The receiver is a variable created by
         build_class_reference_decl.  */
         build_class_reference_decl.  */
      if (TREE_CODE (receiver) == VAR_DECL && IS_CLASS (TREE_TYPE (receiver)))
      if (TREE_CODE (receiver) == VAR_DECL && IS_CLASS (TREE_TYPE (receiver)))
        /* Look up the identifier.  */
        /* Look up the identifier.  */
        for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
        for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
          if (TREE_PURPOSE (chain) == receiver)
          if (TREE_PURPOSE (chain) == receiver)
            return TREE_VALUE (chain);
            return TREE_VALUE (chain);
    }
    }
 
 
  /* The receiver is a function call that returns an id.  Check if
  /* 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.  */
     it is a call to objc_getClass, if so, pick up the class name.  */
  if (TREE_CODE (receiver) == CALL_EXPR
  if (TREE_CODE (receiver) == CALL_EXPR
      && (exp = CALL_EXPR_FN (receiver))
      && (exp = CALL_EXPR_FN (receiver))
      && TREE_CODE (exp) == ADDR_EXPR
      && TREE_CODE (exp) == ADDR_EXPR
      && (exp = TREE_OPERAND (exp, 0))
      && (exp = TREE_OPERAND (exp, 0))
      && TREE_CODE (exp) == FUNCTION_DECL
      && TREE_CODE (exp) == FUNCTION_DECL
      /* For some reason, we sometimes wind up with multiple FUNCTION_DECL
      /* For some reason, we sometimes wind up with multiple FUNCTION_DECL
         prototypes for objc_get_class().  Thankfully, they seem to share the
         prototypes for objc_get_class().  Thankfully, they seem to share the
         same function type.  */
         same function type.  */
      && TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl)
      && TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl)
      && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS)
      && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS)
      /* We have a call to objc_get_class/objc_getClass!  */
      /* We have a call to objc_get_class/objc_getClass!  */
      && (arg = CALL_EXPR_ARG (receiver, 0)))
      && (arg = CALL_EXPR_ARG (receiver, 0)))
    {
    {
      STRIP_NOPS (arg);
      STRIP_NOPS (arg);
      if (TREE_CODE (arg) == ADDR_EXPR
      if (TREE_CODE (arg) == ADDR_EXPR
          && (arg = TREE_OPERAND (arg, 0))
          && (arg = TREE_OPERAND (arg, 0))
          && TREE_CODE (arg) == STRING_CST)
          && TREE_CODE (arg) == STRING_CST)
        /* Finally, we have the class name.  */
        /* Finally, we have the class name.  */
        return get_identifier (TREE_STRING_POINTER (arg));
        return get_identifier (TREE_STRING_POINTER (arg));
    }
    }
  return 0;
  return 0;
}
}


/* If we are currently building a message expr, this holds
/* If we are currently building a message expr, this holds
   the identifier of the selector of the message.  This is
   the identifier of the selector of the message.  This is
   used when printing warnings about argument mismatches.  */
   used when printing warnings about argument mismatches.  */
 
 
static tree current_objc_message_selector = 0;
static tree current_objc_message_selector = 0;
 
 
tree
tree
objc_message_selector (void)
objc_message_selector (void)
{
{
  return current_objc_message_selector;
  return current_objc_message_selector;
}
}
 
 
/* Construct an expression for sending a message.
/* Construct an expression for sending a message.
   MESS has the object to send to in TREE_PURPOSE
   MESS has the object to send to in TREE_PURPOSE
   and the argument list (including selector) in TREE_VALUE.
   and the argument list (including selector) in TREE_VALUE.
 
 
   (*(<abstract_decl>(*)())_msg)(receiver, selTransTbl[n], ...);
   (*(<abstract_decl>(*)())_msg)(receiver, selTransTbl[n], ...);
   (*(<abstract_decl>(*)())_msgSuper)(receiver, selTransTbl[n], ...);  */
   (*(<abstract_decl>(*)())_msgSuper)(receiver, selTransTbl[n], ...);  */
 
 
tree
tree
objc_build_message_expr (tree mess)
objc_build_message_expr (tree mess)
{
{
  tree receiver = TREE_PURPOSE (mess);
  tree receiver = TREE_PURPOSE (mess);
  tree sel_name;
  tree sel_name;
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  tree args = TREE_PURPOSE (TREE_VALUE (mess));
  tree args = TREE_PURPOSE (TREE_VALUE (mess));
#else
#else
  tree args = TREE_VALUE (mess);
  tree args = TREE_VALUE (mess);
#endif
#endif
  tree method_params = NULL_TREE;
  tree method_params = NULL_TREE;
 
 
  if (TREE_CODE (receiver) == ERROR_MARK || TREE_CODE (args) == ERROR_MARK)
  if (TREE_CODE (receiver) == ERROR_MARK || TREE_CODE (args) == ERROR_MARK)
    return error_mark_node;
    return error_mark_node;
 
 
  /* Obtain the full selector name.  */
  /* Obtain the full selector name.  */
  if (TREE_CODE (args) == IDENTIFIER_NODE)
  if (TREE_CODE (args) == IDENTIFIER_NODE)
    /* A unary selector.  */
    /* A unary selector.  */
    sel_name = args;
    sel_name = args;
  else if (TREE_CODE (args) == TREE_LIST)
  else if (TREE_CODE (args) == TREE_LIST)
    sel_name = build_keyword_selector (args);
    sel_name = build_keyword_selector (args);
  else
  else
    abort ();
    abort ();
 
 
  /* Build the parameter list to give to the method.  */
  /* Build the parameter list to give to the method.  */
  if (TREE_CODE (args) == TREE_LIST)
  if (TREE_CODE (args) == TREE_LIST)
#ifdef OBJCPLUS
#ifdef OBJCPLUS
    method_params = chainon (args, TREE_VALUE (TREE_VALUE (mess)));
    method_params = chainon (args, TREE_VALUE (TREE_VALUE (mess)));
#else
#else
    {
    {
      tree chain = args, prev = NULL_TREE;
      tree chain = args, prev = NULL_TREE;
 
 
      /* We have a keyword selector--check for comma expressions.  */
      /* We have a keyword selector--check for comma expressions.  */
      while (chain)
      while (chain)
        {
        {
          tree element = TREE_VALUE (chain);
          tree element = TREE_VALUE (chain);
 
 
          /* We have a comma expression, must collapse...  */
          /* We have a comma expression, must collapse...  */
          if (TREE_CODE (element) == TREE_LIST)
          if (TREE_CODE (element) == TREE_LIST)
            {
            {
              if (prev)
              if (prev)
                TREE_CHAIN (prev) = element;
                TREE_CHAIN (prev) = element;
              else
              else
                args = element;
                args = element;
            }
            }
          prev = chain;
          prev = chain;
          chain = TREE_CHAIN (chain);
          chain = TREE_CHAIN (chain);
        }
        }
      method_params = args;
      method_params = args;
    }
    }
#endif
#endif
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (processing_template_decl)
  if (processing_template_decl)
    /* Must wait until template instantiation time.  */
    /* Must wait until template instantiation time.  */
    return build_min_nt (MESSAGE_SEND_EXPR, receiver, sel_name,
    return build_min_nt (MESSAGE_SEND_EXPR, receiver, sel_name,
                         method_params);
                         method_params);
#endif
#endif
 
 
  return objc_finish_message_expr (receiver, sel_name, method_params);
  return objc_finish_message_expr (receiver, sel_name, method_params);
}
}
 
 
/* Look up method SEL_NAME that would be suitable for receiver
/* 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
   of type 'id' (if IS_CLASS is zero) or 'Class' (if IS_CLASS is
   nonzero), and report on any duplicates.  */
   nonzero), and report on any duplicates.  */
 
 
static tree
static tree
lookup_method_in_hash_lists (tree sel_name, int is_class)
lookup_method_in_hash_lists (tree sel_name, int is_class)
{
{
  hash method_prototype = NULL;
  hash method_prototype = NULL;
 
 
  if (!is_class)
  if (!is_class)
    method_prototype = hash_lookup (nst_method_hash_list,
    method_prototype = hash_lookup (nst_method_hash_list,
                                    sel_name);
                                    sel_name);
 
 
  if (!method_prototype)
  if (!method_prototype)
    {
    {
      method_prototype = hash_lookup (cls_method_hash_list,
      method_prototype = hash_lookup (cls_method_hash_list,
                                      sel_name);
                                      sel_name);
      is_class = 1;
      is_class = 1;
    }
    }
 
 
  return check_duplicates (method_prototype, 1, is_class);
  return check_duplicates (method_prototype, 1, is_class);
}
}
 
 
/* The 'objc_finish_message_expr' routine is called from within
/* The 'objc_finish_message_expr' routine is called from within
   'objc_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'
   C++ template functions, it is called from 'build_expr_from_tree'
   (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded.  */
   (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded.  */
 
 
tree
tree
objc_finish_message_expr (tree receiver, tree sel_name, tree method_params)
objc_finish_message_expr (tree receiver, tree sel_name, tree method_params)
{
{
  tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype;
  tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype;
  tree selector, retval, class_tree;
  tree selector, retval, class_tree;
  int self, super, have_cast;
  int self, super, have_cast;
 
 
  /* Extract the receiver of the message, as well as its type
  /* Extract the receiver of the message, as well as its type
     (where the latter may take the form of a cast or be inferred
     (where the latter may take the form of a cast or be inferred
     from the implementation context).  */
     from the implementation context).  */
  rtype = receiver;
  rtype = receiver;
  while (TREE_CODE (rtype) == COMPOUND_EXPR
  while (TREE_CODE (rtype) == COMPOUND_EXPR
              || TREE_CODE (rtype) == MODIFY_EXPR
              || TREE_CODE (rtype) == MODIFY_EXPR
              || CONVERT_EXPR_P (rtype)
              || CONVERT_EXPR_P (rtype)
              || TREE_CODE (rtype) == COMPONENT_REF)
              || TREE_CODE (rtype) == COMPONENT_REF)
    rtype = TREE_OPERAND (rtype, 0);
    rtype = TREE_OPERAND (rtype, 0);
  self = (rtype == self_decl);
  self = (rtype == self_decl);
  super = (rtype == UOBJC_SUPER_decl);
  super = (rtype == UOBJC_SUPER_decl);
  rtype = TREE_TYPE (receiver);
  rtype = TREE_TYPE (receiver);
  have_cast = (TREE_CODE (receiver) == NOP_EXPR
  have_cast = (TREE_CODE (receiver) == NOP_EXPR
               || (TREE_CODE (receiver) == COMPOUND_EXPR
               || (TREE_CODE (receiver) == COMPOUND_EXPR
                   && !IS_SUPER (rtype)));
                   && !IS_SUPER (rtype)));
 
 
  /* If we are calling [super dealloc], reset our warning flag.  */
  /* If we are calling [super dealloc], reset our warning flag.  */
  if (super && !strcmp ("dealloc", IDENTIFIER_POINTER (sel_name)))
  if (super && !strcmp ("dealloc", IDENTIFIER_POINTER (sel_name)))
    should_call_super_dealloc = 0;
    should_call_super_dealloc = 0;
 
 
  /* If the receiver is a class object, retrieve the corresponding
  /* If the receiver is a class object, retrieve the corresponding
     @interface, if one exists. */
     @interface, if one exists. */
  class_tree = receiver_is_class_object (receiver, self, super);
  class_tree = receiver_is_class_object (receiver, self, super);
 
 
  /* Now determine the receiver type (if an explicit cast has not been
  /* Now determine the receiver type (if an explicit cast has not been
     provided).  */
     provided).  */
  if (!have_cast)
  if (!have_cast)
    {
    {
      if (class_tree)
      if (class_tree)
        rtype = lookup_interface (class_tree);
        rtype = lookup_interface (class_tree);
      /* Handle `self' and `super'.  */
      /* Handle `self' and `super'.  */
      else if (super)
      else if (super)
        {
        {
          if (!CLASS_SUPER_NAME (implementation_template))
          if (!CLASS_SUPER_NAME (implementation_template))
            {
            {
              error ("no super class declared in @interface for %qE",
              error ("no super class declared in @interface for %qE",
                     CLASS_NAME (implementation_template));
                     CLASS_NAME (implementation_template));
              return error_mark_node;
              return error_mark_node;
            }
            }
          rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template));
          rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template));
        }
        }
      else if (self)
      else if (self)
        rtype = lookup_interface (CLASS_NAME (implementation_template));
        rtype = lookup_interface (CLASS_NAME (implementation_template));
    }
    }
 
 
  /* If receiver is of type `id' or `Class' (or if the @interface for a
  /* 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
     class is not visible), we shall be satisfied with the existence of
     any instance or class method. */
     any instance or class method. */
  if (objc_is_id (rtype))
  if (objc_is_id (rtype))
    {
    {
      class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE);
      class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE);
      rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype))
      rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype))
                 ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype))
                 ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype))
                 : NULL_TREE);
                 : NULL_TREE);
      rtype = NULL_TREE;
      rtype = NULL_TREE;
 
 
      if (rprotos)
      if (rprotos)
        {
        {
          /* If messaging 'id <Protos>' or 'Class <Proto>', first search
          /* If messaging 'id <Protos>' or 'Class <Proto>', first search
             in protocols themselves for the method prototype.  */
             in protocols themselves for the method prototype.  */
          method_prototype
          method_prototype
            = lookup_method_in_protocol_list (rprotos, sel_name,
            = lookup_method_in_protocol_list (rprotos, sel_name,
                                              class_tree != NULL_TREE);
                                              class_tree != NULL_TREE);
 
 
          /* If messaging 'Class <Proto>' but did not find a class method
          /* If messaging 'Class <Proto>' but did not find a class method
             prototype, search for an instance method instead, and warn
             prototype, search for an instance method instead, and warn
             about having done so.  */
             about having done so.  */
          if (!method_prototype && !rtype && class_tree != NULL_TREE)
          if (!method_prototype && !rtype && class_tree != NULL_TREE)
            {
            {
              method_prototype
              method_prototype
                = lookup_method_in_protocol_list (rprotos, sel_name, 0);
                = lookup_method_in_protocol_list (rprotos, sel_name, 0);
 
 
              if (method_prototype)
              if (method_prototype)
                warning (0, "found %<-%E%> instead of %<+%E%> in protocol(s)",
                warning (0, "found %<-%E%> instead of %<+%E%> in protocol(s)",
                         sel_name, sel_name);
                         sel_name, sel_name);
            }
            }
        }
        }
    }
    }
  else if (rtype)
  else if (rtype)
    {
    {
      tree orig_rtype = rtype;
      tree orig_rtype = rtype;
 
 
      if (TREE_CODE (rtype) == POINTER_TYPE)
      if (TREE_CODE (rtype) == POINTER_TYPE)
        rtype = TREE_TYPE (rtype);
        rtype = TREE_TYPE (rtype);
      /* Traverse typedef aliases */
      /* Traverse typedef aliases */
      while (TREE_CODE (rtype) == RECORD_TYPE && OBJC_TYPE_NAME (rtype)
      while (TREE_CODE (rtype) == RECORD_TYPE && OBJC_TYPE_NAME (rtype)
             && TREE_CODE (OBJC_TYPE_NAME (rtype)) == TYPE_DECL
             && TREE_CODE (OBJC_TYPE_NAME (rtype)) == TYPE_DECL
             && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (rtype)))
             && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (rtype)))
        rtype = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (rtype));
        rtype = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (rtype));
      if (TYPED_OBJECT (rtype))
      if (TYPED_OBJECT (rtype))
        {
        {
          rprotos = TYPE_OBJC_PROTOCOL_LIST (rtype);
          rprotos = TYPE_OBJC_PROTOCOL_LIST (rtype);
          rtype = TYPE_OBJC_INTERFACE (rtype);
          rtype = TYPE_OBJC_INTERFACE (rtype);
        }
        }
      /* If we could not find an @interface declaration, we must have
      /* If we could not find an @interface declaration, we must have
         only seen a @class declaration; so, we cannot say anything
         only seen a @class declaration; so, we cannot say anything
         more intelligent about which methods the receiver will
         more intelligent about which methods the receiver will
         understand. */
         understand. */
      if (!rtype || TREE_CODE (rtype) == IDENTIFIER_NODE)
      if (!rtype || TREE_CODE (rtype) == IDENTIFIER_NODE)
        rtype = NULL_TREE;
        rtype = NULL_TREE;
      else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE
      else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE
          || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE)
          || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE)
        {
        {
          /* We have a valid ObjC class name.  Look up the method name
          /* We have a valid ObjC class name.  Look up the method name
             in the published @interface for the class (and its
             in the published @interface for the class (and its
             superclasses). */
             superclasses). */
          method_prototype
          method_prototype
            = lookup_method_static (rtype, sel_name, class_tree != NULL_TREE);
            = lookup_method_static (rtype, sel_name, class_tree != NULL_TREE);
 
 
          /* If the method was not found in the @interface, it may still
          /* If the method was not found in the @interface, it may still
             exist locally as part of the @implementation.  */
             exist locally as part of the @implementation.  */
          if (!method_prototype && objc_implementation_context
          if (!method_prototype && objc_implementation_context
             && CLASS_NAME (objc_implementation_context)
             && CLASS_NAME (objc_implementation_context)
                == OBJC_TYPE_NAME (rtype))
                == OBJC_TYPE_NAME (rtype))
            method_prototype
            method_prototype
              = lookup_method
              = lookup_method
                ((class_tree
                ((class_tree
                  ? CLASS_CLS_METHODS (objc_implementation_context)
                  ? CLASS_CLS_METHODS (objc_implementation_context)
                  : CLASS_NST_METHODS (objc_implementation_context)),
                  : CLASS_NST_METHODS (objc_implementation_context)),
                  sel_name);
                  sel_name);
 
 
          /* If we haven't found a candidate method by now, try looking for
          /* If we haven't found a candidate method by now, try looking for
             it in the protocol list.  */
             it in the protocol list.  */
          if (!method_prototype && rprotos)
          if (!method_prototype && rprotos)
            method_prototype
            method_prototype
              = lookup_method_in_protocol_list (rprotos, sel_name,
              = lookup_method_in_protocol_list (rprotos, sel_name,
                                                class_tree != NULL_TREE);
                                                class_tree != NULL_TREE);
        }
        }
      else
      else
        {
        {
          warning (0, "invalid receiver type %qs",
          warning (0, "invalid receiver type %qs",
                   identifier_to_locale (gen_type_name (orig_rtype)));
                   identifier_to_locale (gen_type_name (orig_rtype)));
          /* After issuing the "invalid receiver" warning, perform method
          /* After issuing the "invalid receiver" warning, perform method
             lookup as if we were messaging 'id'.  */
             lookup as if we were messaging 'id'.  */
          rtype = rprotos = NULL_TREE;
          rtype = rprotos = NULL_TREE;
        }
        }
    }
    }
 
 
 
 
  /* For 'id' or 'Class' receivers, search in the global hash table
  /* For 'id' or 'Class' receivers, search in the global hash table
     as a last resort.  For all receivers, warn if protocol searches
     as a last resort.  For all receivers, warn if protocol searches
     have failed.  */
     have failed.  */
  if (!method_prototype)
  if (!method_prototype)
    {
    {
      if (rprotos)
      if (rprotos)
        warning (0, "%<%c%E%> not found in protocol(s)",
        warning (0, "%<%c%E%> not found in protocol(s)",
                 (class_tree ? '+' : '-'),
                 (class_tree ? '+' : '-'),
                 sel_name);
                 sel_name);
 
 
      if (!rtype)
      if (!rtype)
        method_prototype
        method_prototype
          = lookup_method_in_hash_lists (sel_name, class_tree != NULL_TREE);
          = lookup_method_in_hash_lists (sel_name, class_tree != NULL_TREE);
    }
    }
 
 
  if (!method_prototype)
  if (!method_prototype)
    {
    {
      static bool warn_missing_methods = false;
      static bool warn_missing_methods = false;
 
 
      if (rtype)
      if (rtype)
        warning (0, "%qE may not respond to %<%c%E%>",
        warning (0, "%qE may not respond to %<%c%E%>",
                 OBJC_TYPE_NAME (rtype),
                 OBJC_TYPE_NAME (rtype),
                 (class_tree ? '+' : '-'),
                 (class_tree ? '+' : '-'),
                 sel_name);
                 sel_name);
      /* If we are messaging an 'id' or 'Class' object and made it here,
      /* If we are messaging an 'id' or 'Class' object and made it here,
         then we have failed to find _any_ instance or class method,
         then we have failed to find _any_ instance or class method,
         respectively.  */
         respectively.  */
      else
      else
        warning (0, "no %<%c%E%> method found",
        warning (0, "no %<%c%E%> method found",
                 (class_tree ? '+' : '-'),
                 (class_tree ? '+' : '-'),
                 sel_name);
                 sel_name);
 
 
      if (!warn_missing_methods)
      if (!warn_missing_methods)
        {
        {
          warning_at (input_location,
          warning_at (input_location,
                      0, "(Messages without a matching method signature");
                      0, "(Messages without a matching method signature");
          warning_at (input_location,
          warning_at (input_location,
                      0, "will be assumed to return %<id%> and accept");
                      0, "will be assumed to return %<id%> and accept");
          warning_at (input_location,
          warning_at (input_location,
                      0, "%<...%> as arguments.)");
                      0, "%<...%> as arguments.)");
          warn_missing_methods = true;
          warn_missing_methods = true;
        }
        }
    }
    }
 
 
  /* Save the selector name for printing error messages.  */
  /* Save the selector name for printing error messages.  */
  current_objc_message_selector = sel_name;
  current_objc_message_selector = sel_name;
 
 
  /* Build the parameters list for looking up the method.
  /* Build the parameters list for looking up the method.
     These are the object itself and the selector.  */
     These are the object itself and the selector.  */
 
 
  if (flag_typed_selectors)
  if (flag_typed_selectors)
    selector = build_typed_selector_reference (input_location,
    selector = build_typed_selector_reference (input_location,
                                               sel_name, method_prototype);
                                               sel_name, method_prototype);
  else
  else
    selector = build_selector_reference (input_location, sel_name);
    selector = build_selector_reference (input_location, sel_name);
 
 
  retval = build_objc_method_call (input_location, super, method_prototype,
  retval = build_objc_method_call (input_location, super, method_prototype,
                                   receiver,
                                   receiver,
                                   selector, method_params);
                                   selector, method_params);
 
 
  current_objc_message_selector = 0;
  current_objc_message_selector = 0;
 
 
  return retval;
  return retval;
}
}


/* Build a tree expression to send OBJECT the operation SELECTOR,
/* Build a tree expression to send OBJECT the operation SELECTOR,
   looking up the method on object LOOKUP_OBJECT (often same as OBJECT),
   looking up the method on object LOOKUP_OBJECT (often same as OBJECT),
   assuming the method has prototype METHOD_PROTOTYPE.
   assuming the method has prototype METHOD_PROTOTYPE.
   (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.)
   (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.)
   LOC is the location of the expression to build.
   LOC is the location of the expression to build.
   Use METHOD_PARAMS as list of args to pass to the method.
   Use METHOD_PARAMS as list of args to pass to the method.
   If SUPER_FLAG is nonzero, we look up the superclass's method.  */
   If SUPER_FLAG is nonzero, we look up the superclass's method.  */
 
 
static tree
static tree
build_objc_method_call (location_t loc, int super_flag, tree method_prototype,
build_objc_method_call (location_t loc, int super_flag, tree method_prototype,
                        tree lookup_object, tree selector,
                        tree lookup_object, tree selector,
                        tree method_params)
                        tree method_params)
{
{
  tree sender = (super_flag ? umsg_super_decl :
  tree sender = (super_flag ? umsg_super_decl :
                 (!flag_next_runtime || flag_nil_receivers
                 (!flag_next_runtime || flag_nil_receivers
                  ? (flag_objc_direct_dispatch
                  ? (flag_objc_direct_dispatch
                     ? umsg_fast_decl
                     ? umsg_fast_decl
                     : umsg_decl)
                     : umsg_decl)
                  : umsg_nonnil_decl));
                  : umsg_nonnil_decl));
  tree rcv_p = (super_flag ? objc_super_type : objc_object_type);
  tree rcv_p = (super_flag ? objc_super_type : objc_object_type);
 
 
  /* If a prototype for the method to be called exists, then cast
  /* 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.
     the sender's return type and arguments to match that of the method.
     Otherwise, leave sender as is.  */
     Otherwise, leave sender as is.  */
  tree ret_type
  tree ret_type
    = (method_prototype
    = (method_prototype
       ? TREE_VALUE (TREE_TYPE (method_prototype))
       ? TREE_VALUE (TREE_TYPE (method_prototype))
       : objc_object_type);
       : objc_object_type);
  tree sender_cast
  tree sender_cast
    = build_pointer_type
    = build_pointer_type
      (build_function_type
      (build_function_type
       (ret_type,
       (ret_type,
        get_arg_type_list
        get_arg_type_list
        (method_prototype, METHOD_REF, super_flag)));
        (method_prototype, METHOD_REF, super_flag)));
  tree method, t;
  tree method, t;
 
 
  lookup_object = build_c_cast (loc, rcv_p, lookup_object);
  lookup_object = build_c_cast (loc, rcv_p, lookup_object);
 
 
  /* Use SAVE_EXPR to avoid evaluating the receiver twice.  */
  /* Use SAVE_EXPR to avoid evaluating the receiver twice.  */
  lookup_object = save_expr (lookup_object);
  lookup_object = save_expr (lookup_object);
 
 
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      /* If we are returning a struct in memory, and the address
      /* If we are returning a struct in memory, and the address
         of that memory location is passed as a hidden first
         of that memory location is passed as a hidden first
         argument, then change which messenger entry point this
         argument, then change which messenger entry point this
         expr will call.  NB: Note that sender_cast remains
         expr will call.  NB: Note that sender_cast remains
         unchanged (it already has a struct return type).  */
         unchanged (it already has a struct return type).  */
      if (!targetm.calls.struct_value_rtx (0, 0)
      if (!targetm.calls.struct_value_rtx (0, 0)
          && (TREE_CODE (ret_type) == RECORD_TYPE
          && (TREE_CODE (ret_type) == RECORD_TYPE
              || TREE_CODE (ret_type) == UNION_TYPE)
              || TREE_CODE (ret_type) == UNION_TYPE)
          && targetm.calls.return_in_memory (ret_type, 0))
          && targetm.calls.return_in_memory (ret_type, 0))
        sender = (super_flag ? umsg_super_stret_decl :
        sender = (super_flag ? umsg_super_stret_decl :
                flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl);
                flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl);
 
 
      method_params = tree_cons (NULL_TREE, lookup_object,
      method_params = tree_cons (NULL_TREE, lookup_object,
                                 tree_cons (NULL_TREE, selector,
                                 tree_cons (NULL_TREE, selector,
                                            method_params));
                                            method_params));
      method = build_fold_addr_expr_loc (input_location, sender);
      method = build_fold_addr_expr_loc (input_location, sender);
    }
    }
  else
  else
    {
    {
      /* This is the portable (GNU) way.  */
      /* This is the portable (GNU) way.  */
      tree object;
      tree object;
 
 
      /* First, call the lookup function to get a pointer to the method,
      /* First, call the lookup function to get a pointer to the method,
         then cast the pointer, then call it with the method arguments.  */
         then cast the pointer, then call it with the method arguments.  */
 
 
      object = (super_flag ? self_decl : lookup_object);
      object = (super_flag ? self_decl : lookup_object);
 
 
      t = tree_cons (NULL_TREE, selector, NULL_TREE);
      t = tree_cons (NULL_TREE, selector, NULL_TREE);
      t = tree_cons (NULL_TREE, lookup_object, t);
      t = tree_cons (NULL_TREE, lookup_object, t);
      method = build_function_call (loc, sender, t);
      method = build_function_call (loc, sender, t);
 
 
      /* Pass the object to the method.  */
      /* Pass the object to the method.  */
      method_params = tree_cons (NULL_TREE, object,
      method_params = tree_cons (NULL_TREE, object,
                                 tree_cons (NULL_TREE, selector,
                                 tree_cons (NULL_TREE, selector,
                                            method_params));
                                            method_params));
    }
    }
 
 
  /* ??? Selector is not at this point something we can use inside
  /* ??? Selector is not at this point something we can use inside
     the compiler itself.  Set it to garbage for the nonce.  */
     the compiler itself.  Set it to garbage for the nonce.  */
  t = build3 (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node);
  t = build3 (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node);
  return build_function_call (loc,
  return build_function_call (loc,
                              t, method_params);
                              t, method_params);
}
}


static void
static void
build_protocol_reference (tree p)
build_protocol_reference (tree p)
{
{
  tree decl;
  tree decl;
  const char *proto_name;
  const char *proto_name;
 
 
  /* static struct _objc_protocol _OBJC_PROTOCOL_<mumble>; */
  /* static struct _objc_protocol _OBJC_PROTOCOL_<mumble>; */
 
 
  proto_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL", p);
  proto_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL", p);
  decl = start_var_decl (objc_protocol_template, proto_name);
  decl = start_var_decl (objc_protocol_template, proto_name);
 
 
  PROTOCOL_FORWARD_DECL (p) = decl;
  PROTOCOL_FORWARD_DECL (p) = decl;
}
}
 
 
/* This function is called by the parser when (and only when) a
/* This function is called by the parser when (and only when) a
   @protocol() expression is found, in order to compile it.  */
   @protocol() expression is found, in order to compile it.  */
tree
tree
objc_build_protocol_expr (tree protoname)
objc_build_protocol_expr (tree protoname)
{
{
  tree expr;
  tree expr;
  tree p = lookup_protocol (protoname);
  tree p = lookup_protocol (protoname);
 
 
  if (!p)
  if (!p)
    {
    {
      error ("cannot find protocol declaration for %qE",
      error ("cannot find protocol declaration for %qE",
             protoname);
             protoname);
      return error_mark_node;
      return error_mark_node;
    }
    }
 
 
  if (!PROTOCOL_FORWARD_DECL (p))
  if (!PROTOCOL_FORWARD_DECL (p))
    build_protocol_reference (p);
    build_protocol_reference (p);
 
 
  expr = build_unary_op (input_location,
  expr = build_unary_op (input_location,
                         ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0);
                         ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0);
 
 
  /* ??? Ideally we'd build the reference with objc_protocol_type directly,
  /* ??? Ideally we'd build the reference with objc_protocol_type directly,
     if we have it, rather than converting it here.  */
     if we have it, rather than converting it here.  */
  expr = convert (objc_protocol_type, expr);
  expr = convert (objc_protocol_type, expr);
 
 
  /* The @protocol() expression is being compiled into a pointer to a
  /* The @protocol() expression is being compiled into a pointer to a
     statically allocated instance of the Protocol class.  To become
     statically allocated instance of the Protocol class.  To become
     usable at runtime, the 'isa' pointer of the instance need to be
     usable at runtime, the 'isa' pointer of the instance need to be
     fixed up at runtime by the runtime library, to point to the
     fixed up at runtime by the runtime library, to point to the
     actual 'Protocol' class.  */
     actual 'Protocol' class.  */
 
 
  /* For the GNU runtime, put the static Protocol instance in the list
  /* For the GNU runtime, put the static Protocol instance in the list
     of statically allocated instances, so that we make sure that its
     of statically allocated instances, so that we make sure that its
     'isa' pointer is fixed up at runtime by the GNU runtime library
     'isa' pointer is fixed up at runtime by the GNU runtime library
     to point to the Protocol class (at runtime, when loading the
     to point to the Protocol class (at runtime, when loading the
     module, the GNU runtime library loops on the statically allocated
     module, the GNU runtime library loops on the statically allocated
     instances (as found in the defs field in objc_symtab) and fixups
     instances (as found in the defs field in objc_symtab) and fixups
     all the 'isa' pointers of those objects).  */
     all the 'isa' pointers of those objects).  */
  if (! flag_next_runtime)
  if (! flag_next_runtime)
    {
    {
      /* This type is a struct containing the fields of a Protocol
      /* This type is a struct containing the fields of a Protocol
        object.  (Cfr. objc_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).  */
        to such a struct).  */
      tree protocol_struct_type = xref_tag
      tree protocol_struct_type = xref_tag
       (RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
       (RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
      tree *chain;
      tree *chain;
 
 
      /* Look for the list of Protocol statically allocated instances
      /* Look for the list of Protocol statically allocated instances
        to fixup at runtime.  Create a new list to hold Protocol
        to fixup at runtime.  Create a new list to hold Protocol
        statically allocated instances, if the list is not found.  At
        statically allocated instances, if the list is not found.  At
        present there is only another list, holding NSConstantString
        present there is only another list, holding NSConstantString
        static instances to be fixed up at runtime.  */
        static instances to be fixed up at runtime.  */
      for (chain = &objc_static_instances;
      for (chain = &objc_static_instances;
           *chain && TREE_VALUE (*chain) != protocol_struct_type;
           *chain && TREE_VALUE (*chain) != protocol_struct_type;
           chain = &TREE_CHAIN (*chain));
           chain = &TREE_CHAIN (*chain));
      if (!*chain)
      if (!*chain)
        {
        {
         *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE);
         *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE);
         add_objc_string (OBJC_TYPE_NAME (protocol_struct_type),
         add_objc_string (OBJC_TYPE_NAME (protocol_struct_type),
                          class_names);
                          class_names);
       }
       }
 
 
      /* Add this statically allocated instance to the Protocol list.  */
      /* 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),
                                         PROTOCOL_FORWARD_DECL (p),
                                         TREE_PURPOSE (*chain));
                                         TREE_PURPOSE (*chain));
    }
    }
 
 
 
 
  return expr;
  return expr;
}
}
 
 
/* This function is called by the parser when a @selector() expression
/* This function is called by the parser when a @selector() expression
   is found, in order to compile it.  It is only called by the parser
   is found, in order to compile it.  It is only called by the parser
   and only to compile a @selector().  LOC is the location of the
   and only to compile a @selector().  LOC is the location of the
   @selector.  */
   @selector.  */
tree
tree
objc_build_selector_expr (location_t loc, tree selnamelist)
objc_build_selector_expr (location_t loc, tree selnamelist)
{
{
  tree selname;
  tree selname;
 
 
  /* Obtain the full selector name.  */
  /* Obtain the full selector name.  */
  if (TREE_CODE (selnamelist) == IDENTIFIER_NODE)
  if (TREE_CODE (selnamelist) == IDENTIFIER_NODE)
    /* A unary selector.  */
    /* A unary selector.  */
    selname = selnamelist;
    selname = selnamelist;
  else if (TREE_CODE (selnamelist) == TREE_LIST)
  else if (TREE_CODE (selnamelist) == TREE_LIST)
    selname = build_keyword_selector (selnamelist);
    selname = build_keyword_selector (selnamelist);
  else
  else
    abort ();
    abort ();
 
 
  /* If we are required to check @selector() expressions as they
  /* If we are required to check @selector() expressions as they
     are found, check that the selector has been declared.  */
     are found, check that the selector has been declared.  */
  if (warn_undeclared_selector)
  if (warn_undeclared_selector)
    {
    {
      /* Look the selector up in the list of all known class and
      /* Look the selector up in the list of all known class and
         instance methods (up to this line) to check that the selector
         instance methods (up to this line) to check that the selector
         exists.  */
         exists.  */
      hash hsh;
      hash hsh;
 
 
      /* First try with instance methods.  */
      /* First try with instance methods.  */
      hsh = hash_lookup (nst_method_hash_list, selname);
      hsh = hash_lookup (nst_method_hash_list, selname);
 
 
      /* If not found, try with class methods.  */
      /* If not found, try with class methods.  */
      if (!hsh)
      if (!hsh)
        {
        {
          hsh = hash_lookup (cls_method_hash_list, selname);
          hsh = hash_lookup (cls_method_hash_list, selname);
        }
        }
 
 
      /* If still not found, print out a warning.  */
      /* If still not found, print out a warning.  */
      if (!hsh)
      if (!hsh)
        {
        {
          warning (0, "undeclared selector %qE", selname);
          warning (0, "undeclared selector %qE", selname);
        }
        }
    }
    }
 
 
 
 
  if (flag_typed_selectors)
  if (flag_typed_selectors)
    return build_typed_selector_reference (loc, selname, 0);
    return build_typed_selector_reference (loc, selname, 0);
  else
  else
    return build_selector_reference (loc, selname);
    return build_selector_reference (loc, selname);
}
}
 
 
tree
tree
objc_build_encode_expr (tree type)
objc_build_encode_expr (tree type)
{
{
  tree result;
  tree result;
  const char *string;
  const char *string;
 
 
  encode_type (type, obstack_object_size (&util_obstack),
  encode_type (type, obstack_object_size (&util_obstack),
               OBJC_ENCODE_INLINE_DEFS);
               OBJC_ENCODE_INLINE_DEFS);
  obstack_1grow (&util_obstack, 0);    /* null terminate string */
  obstack_1grow (&util_obstack, 0);    /* null terminate string */
  string = XOBFINISH (&util_obstack, const char *);
  string = XOBFINISH (&util_obstack, const char *);
 
 
  /* Synthesize a string that represents the encoded struct/union.  */
  /* Synthesize a string that represents the encoded struct/union.  */
  result = my_build_string (strlen (string) + 1, string);
  result = my_build_string (strlen (string) + 1, string);
  obstack_free (&util_obstack, util_firstobj);
  obstack_free (&util_obstack, util_firstobj);
  return result;
  return result;
}
}
 
 
static tree
static tree
build_ivar_reference (tree id)
build_ivar_reference (tree id)
{
{
  if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
  if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
    {
    {
      /* Historically, a class method that produced objects (factory
      /* Historically, a class method that produced objects (factory
         method) would assign `self' to the instance that it
         method) would assign `self' to the instance that it
         allocated.  This would effectively turn the class method into
         allocated.  This would effectively turn the class method into
         an instance method.  Following this assignment, the instance
         an instance method.  Following this assignment, the instance
         variables could be accessed.  That practice, while safe,
         variables could be accessed.  That practice, while safe,
         violates the simple rule that a class method should not refer
         violates the simple rule that a class method should not refer
         to an instance variable.  It's better to catch the cases
         to an instance variable.  It's better to catch the cases
         where this is done unknowingly than to support the above
         where this is done unknowingly than to support the above
         paradigm.  */
         paradigm.  */
      warning (0, "instance variable %qE accessed in class method",
      warning (0, "instance variable %qE accessed in class method",
               id);
               id);
      self_decl = convert (objc_instance_type, self_decl); /* cast */
      self_decl = convert (objc_instance_type, self_decl); /* cast */
    }
    }
 
 
  return objc_build_component_ref (build_indirect_ref (input_location,
  return objc_build_component_ref (build_indirect_ref (input_location,
                                                       self_decl, RO_ARROW),
                                                       self_decl, RO_ARROW),
                                   id);
                                   id);
}
}


/* Compute a hash value for a given method SEL_NAME.  */
/* Compute a hash value for a given method SEL_NAME.  */
 
 
static size_t
static size_t
hash_func (tree sel_name)
hash_func (tree sel_name)
{
{
  const unsigned char *s
  const unsigned char *s
    = (const unsigned char *)IDENTIFIER_POINTER (sel_name);
    = (const unsigned char *)IDENTIFIER_POINTER (sel_name);
  size_t h = 0;
  size_t h = 0;
 
 
  while (*s)
  while (*s)
    h = h * 67 + *s++ - 113;
    h = h * 67 + *s++ - 113;
  return h;
  return h;
}
}
 
 
static void
static void
hash_init (void)
hash_init (void)
{
{
  nst_method_hash_list
  nst_method_hash_list
    = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash));
    = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash));
  cls_method_hash_list
  cls_method_hash_list
    = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash));
    = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash));
 
 
  /* Initialize the hash table used to hold the constant string objects.  */
  /* Initialize the hash table used to hold the constant string objects.  */
  string_htab = htab_create_ggc (31, string_hash,
  string_htab = htab_create_ggc (31, string_hash,
                                   string_eq, NULL);
                                   string_eq, NULL);
 
 
  /* Initialize the hash table used to hold EH-volatilized types.  */
  /* Initialize the hash table used to hold EH-volatilized types.  */
  volatilized_htab = htab_create_ggc (31, volatilized_hash,
  volatilized_htab = htab_create_ggc (31, volatilized_hash,
                                      volatilized_eq, NULL);
                                      volatilized_eq, NULL);
}
}
 
 
/* WARNING!!!!  hash_enter is called with a method, and will peek
/* WARNING!!!!  hash_enter is called with a method, and will peek
   inside to find its selector!  But hash_lookup is given a selector
   inside to find its selector!  But hash_lookup is given a selector
   directly, and looks for the selector that's inside the found
   directly, and looks for the selector that's inside the found
   entry's key (method) for comparison.  */
   entry's key (method) for comparison.  */
 
 
static void
static void
hash_enter (hash *hashlist, tree method)
hash_enter (hash *hashlist, tree method)
{
{
  hash obj;
  hash obj;
  int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
  int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
 
 
  obj = (hash) ggc_alloc (sizeof (struct hashed_entry));
  obj = (hash) ggc_alloc (sizeof (struct hashed_entry));
  obj->list = 0;
  obj->list = 0;
  obj->next = hashlist[slot];
  obj->next = hashlist[slot];
  obj->key = method;
  obj->key = method;
 
 
  hashlist[slot] = obj;         /* append to front */
  hashlist[slot] = obj;         /* append to front */
}
}
 
 
static hash
static hash
hash_lookup (hash *hashlist, tree sel_name)
hash_lookup (hash *hashlist, tree sel_name)
{
{
  hash target;
  hash target;
 
 
  target = hashlist[hash_func (sel_name) % SIZEHASHTABLE];
  target = hashlist[hash_func (sel_name) % SIZEHASHTABLE];
 
 
  while (target)
  while (target)
    {
    {
      if (sel_name == METHOD_SEL_NAME (target->key))
      if (sel_name == METHOD_SEL_NAME (target->key))
        return target;
        return target;
 
 
      target = target->next;
      target = target->next;
    }
    }
  return 0;
  return 0;
}
}
 
 
static void
static void
hash_add_attr (hash entry, tree value)
hash_add_attr (hash entry, tree value)
{
{
  attr obj;
  attr obj;
 
 
  obj = (attr) ggc_alloc (sizeof (struct hashed_attribute));
  obj = (attr) ggc_alloc (sizeof (struct hashed_attribute));
  obj->next = entry->list;
  obj->next = entry->list;
  obj->value = value;
  obj->value = value;
 
 
  entry->list = obj;            /* append to front */
  entry->list = obj;            /* append to front */
}
}


static tree
static tree
lookup_method (tree mchain, tree method)
lookup_method (tree mchain, tree method)
{
{
  tree key;
  tree key;
 
 
  if (TREE_CODE (method) == IDENTIFIER_NODE)
  if (TREE_CODE (method) == IDENTIFIER_NODE)
    key = method;
    key = method;
  else
  else
    key = METHOD_SEL_NAME (method);
    key = METHOD_SEL_NAME (method);
 
 
  while (mchain)
  while (mchain)
    {
    {
      if (METHOD_SEL_NAME (mchain) == key)
      if (METHOD_SEL_NAME (mchain) == key)
        return mchain;
        return mchain;
 
 
      mchain = TREE_CHAIN (mchain);
      mchain = TREE_CHAIN (mchain);
    }
    }
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Look up a class (if OBJC_LOOKUP_CLASS is set in FLAGS) or instance method
/* Look up a class (if OBJC_LOOKUP_CLASS is set in FLAGS) or instance method
   in INTERFACE, along with any categories and protocols attached thereto.
   in INTERFACE, along with any categories and protocols attached thereto.
   If method is not found, and the OBJC_LOOKUP_NO_SUPER is _not_ set in FLAGS,
   If method is not found, and the OBJC_LOOKUP_NO_SUPER is _not_ set in FLAGS,
   recursively examine the INTERFACE's superclass.  If OBJC_LOOKUP_CLASS is
   recursively examine the INTERFACE's superclass.  If OBJC_LOOKUP_CLASS is
   set, OBJC_LOOKUP_NO_SUPER is cleared, and no suitable class method could
   set, OBJC_LOOKUP_NO_SUPER is cleared, and no suitable class method could
   be found in INTERFACE or any of its superclasses, look for an _instance_
   be found in INTERFACE or any of its superclasses, look for an _instance_
   method of the same name in the root class as a last resort.
   method of the same name in the root class as a last resort.
 
 
   If a suitable method cannot be found, return NULL_TREE.  */
   If a suitable method cannot be found, return NULL_TREE.  */
 
 
static tree
static tree
lookup_method_static (tree interface, tree ident, int flags)
lookup_method_static (tree interface, tree ident, int flags)
{
{
  tree meth = NULL_TREE, root_inter = NULL_TREE;
  tree meth = NULL_TREE, root_inter = NULL_TREE;
  tree inter = interface;
  tree inter = interface;
  int is_class = (flags & OBJC_LOOKUP_CLASS);
  int is_class = (flags & OBJC_LOOKUP_CLASS);
  int no_superclasses = (flags & OBJC_LOOKUP_NO_SUPER);
  int no_superclasses = (flags & OBJC_LOOKUP_NO_SUPER);
 
 
  while (inter)
  while (inter)
    {
    {
      tree chain = is_class ? CLASS_CLS_METHODS (inter) : CLASS_NST_METHODS (inter);
      tree chain = is_class ? CLASS_CLS_METHODS (inter) : CLASS_NST_METHODS (inter);
      tree category = inter;
      tree category = inter;
 
 
      /* First, look up the method in the class itself.  */
      /* First, look up the method in the class itself.  */
      if ((meth = lookup_method (chain, ident)))
      if ((meth = lookup_method (chain, ident)))
        return meth;
        return meth;
 
 
      /* Failing that, look for the method in each category of the class.  */
      /* Failing that, look for the method in each category of the class.  */
      while ((category = CLASS_CATEGORY_LIST (category)))
      while ((category = CLASS_CATEGORY_LIST (category)))
        {
        {
          chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category);
          chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category);
 
 
          /* Check directly in each category.  */
          /* Check directly in each category.  */
          if ((meth = lookup_method (chain, ident)))
          if ((meth = lookup_method (chain, ident)))
            return meth;
            return meth;
 
 
          /* Failing that, check in each category's protocols.  */
          /* Failing that, check in each category's protocols.  */
          if (CLASS_PROTOCOL_LIST (category))
          if (CLASS_PROTOCOL_LIST (category))
            {
            {
              if ((meth = (lookup_method_in_protocol_list
              if ((meth = (lookup_method_in_protocol_list
                           (CLASS_PROTOCOL_LIST (category), ident, is_class))))
                           (CLASS_PROTOCOL_LIST (category), ident, is_class))))
                return meth;
                return meth;
            }
            }
        }
        }
 
 
      /* If not found in categories, check in protocols of the main class.  */
      /* If not found in categories, check in protocols of the main class.  */
      if (CLASS_PROTOCOL_LIST (inter))
      if (CLASS_PROTOCOL_LIST (inter))
        {
        {
          if ((meth = (lookup_method_in_protocol_list
          if ((meth = (lookup_method_in_protocol_list
                       (CLASS_PROTOCOL_LIST (inter), ident, is_class))))
                       (CLASS_PROTOCOL_LIST (inter), ident, is_class))))
            return meth;
            return meth;
        }
        }
 
 
      /* If we were instructed not to look in superclasses, don't.  */
      /* If we were instructed not to look in superclasses, don't.  */
      if (no_superclasses)
      if (no_superclasses)
        return NULL_TREE;
        return NULL_TREE;
 
 
      /* Failing that, climb up the inheritance hierarchy.  */
      /* Failing that, climb up the inheritance hierarchy.  */
      root_inter = inter;
      root_inter = inter;
      inter = lookup_interface (CLASS_SUPER_NAME (inter));
      inter = lookup_interface (CLASS_SUPER_NAME (inter));
    }
    }
  while (inter);
  while (inter);
 
 
  /* If no class (factory) method was found, check if an _instance_
  /* If no class (factory) method was found, check if an _instance_
     method of the same name exists in the root class.  This is what
     method of the same name exists in the root class.  This is what
     the Objective-C runtime will do.  If an instance method was not
     the Objective-C runtime will do.  If an instance method was not
     found, return 0.  */
     found, return 0.  */
  return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE;
  return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE;
}
}
 
 
/* Add the method to the hash list if it doesn't contain an identical
/* Add the method to the hash list if it doesn't contain an identical
   method already. */
   method already. */
 
 
static void
static void
add_method_to_hash_list (hash *hash_list, tree method)
add_method_to_hash_list (hash *hash_list, tree method)
{
{
  hash hsh;
  hash hsh;
 
 
  if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method))))
  if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method))))
    {
    {
      /* Install on a global chain.  */
      /* Install on a global chain.  */
      hash_enter (hash_list, method);
      hash_enter (hash_list, method);
    }
    }
  else
  else
    {
    {
      /* Check types against those; if different, add to a list.  */
      /* Check types against those; if different, add to a list.  */
      attr loop;
      attr loop;
      int already_there = comp_proto_with_proto (method, hsh->key, 1);
      int already_there = comp_proto_with_proto (method, hsh->key, 1);
      for (loop = hsh->list; !already_there && loop; loop = loop->next)
      for (loop = hsh->list; !already_there && loop; loop = loop->next)
        already_there |= comp_proto_with_proto (method, loop->value, 1);
        already_there |= comp_proto_with_proto (method, loop->value, 1);
      if (!already_there)
      if (!already_there)
        hash_add_attr (hsh, method);
        hash_add_attr (hsh, method);
    }
    }
}
}
 
 
static tree
static tree
objc_add_method (tree klass, tree method, int is_class)
objc_add_method (tree klass, tree method, int is_class)
{
{
  tree mth;
  tree mth;
 
 
  if (!(mth = lookup_method (is_class
  if (!(mth = lookup_method (is_class
                             ? CLASS_CLS_METHODS (klass)
                             ? CLASS_CLS_METHODS (klass)
                             : CLASS_NST_METHODS (klass), method)))
                             : CLASS_NST_METHODS (klass), method)))
    {
    {
      /* put method on list in reverse order */
      /* put method on list in reverse order */
      if (is_class)
      if (is_class)
        {
        {
          TREE_CHAIN (method) = CLASS_CLS_METHODS (klass);
          TREE_CHAIN (method) = CLASS_CLS_METHODS (klass);
          CLASS_CLS_METHODS (klass) = method;
          CLASS_CLS_METHODS (klass) = method;
        }
        }
      else
      else
        {
        {
          TREE_CHAIN (method) = CLASS_NST_METHODS (klass);
          TREE_CHAIN (method) = CLASS_NST_METHODS (klass);
          CLASS_NST_METHODS (klass) = method;
          CLASS_NST_METHODS (klass) = method;
        }
        }
    }
    }
  else
  else
    {
    {
      /* When processing an @interface for a class or category, give hard
      /* When processing an @interface for a class or category, give hard
         errors on methods with identical selectors but differing argument
         errors on methods with identical selectors but differing argument
         and/or return types. We do not do this for @implementations, because
         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
         C/C++ will do it for us (i.e., there will be duplicate function
         definition errors).  */
         definition errors).  */
      if ((TREE_CODE (klass) == CLASS_INTERFACE_TYPE
      if ((TREE_CODE (klass) == CLASS_INTERFACE_TYPE
           || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE)
           || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE)
          && !comp_proto_with_proto (method, mth, 1))
          && !comp_proto_with_proto (method, mth, 1))
        error ("duplicate declaration of method %<%c%E%>",
        error ("duplicate declaration of method %<%c%E%>",
                is_class ? '+' : '-',
                is_class ? '+' : '-',
                METHOD_SEL_NAME (mth));
                METHOD_SEL_NAME (mth));
    }
    }
 
 
  if (is_class)
  if (is_class)
    add_method_to_hash_list (cls_method_hash_list, method);
    add_method_to_hash_list (cls_method_hash_list, method);
  else
  else
    {
    {
      add_method_to_hash_list (nst_method_hash_list, method);
      add_method_to_hash_list (nst_method_hash_list, method);
 
 
      /* Instance methods in root classes (and categories thereof)
      /* Instance methods in root classes (and categories thereof)
         may act as class methods as a last resort.  We also add
         may act as class methods as a last resort.  We also add
         instance methods listed in @protocol declarations to
         instance methods listed in @protocol declarations to
         the class hash table, on the assumption that @protocols
         the class hash table, on the assumption that @protocols
         may be adopted by root classes or categories.  */
         may be adopted by root classes or categories.  */
      if (TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE
      if (TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE
          || TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE)
          || TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE)
        klass = lookup_interface (CLASS_NAME (klass));
        klass = lookup_interface (CLASS_NAME (klass));
 
 
      if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE
      if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE
          || !CLASS_SUPER_NAME (klass))
          || !CLASS_SUPER_NAME (klass))
        add_method_to_hash_list (cls_method_hash_list, method);
        add_method_to_hash_list (cls_method_hash_list, method);
    }
    }
 
 
  return method;
  return method;
}
}
 
 
static tree
static tree
add_class (tree class_name, tree name)
add_class (tree class_name, tree name)
{
{
  struct interface_tuple **slot;
  struct interface_tuple **slot;
 
 
  /* Put interfaces on list in reverse order.  */
  /* Put interfaces on list in reverse order.  */
  TREE_CHAIN (class_name) = interface_chain;
  TREE_CHAIN (class_name) = interface_chain;
  interface_chain = class_name;
  interface_chain = class_name;
 
 
  if (interface_htab == NULL)
  if (interface_htab == NULL)
    interface_htab = htab_create_ggc (31, hash_interface, eq_interface, NULL);
    interface_htab = htab_create_ggc (31, hash_interface, eq_interface, NULL);
  slot = (struct interface_tuple **)
  slot = (struct interface_tuple **)
    htab_find_slot_with_hash (interface_htab, name,
    htab_find_slot_with_hash (interface_htab, name,
                              IDENTIFIER_HASH_VALUE (name),
                              IDENTIFIER_HASH_VALUE (name),
                              INSERT);
                              INSERT);
  if (!*slot)
  if (!*slot)
    {
    {
      *slot = (struct interface_tuple *) ggc_alloc_cleared (sizeof (struct interface_tuple));
      *slot = (struct interface_tuple *) ggc_alloc_cleared (sizeof (struct interface_tuple));
      (*slot)->id = name;
      (*slot)->id = name;
    }
    }
  (*slot)->class_name = class_name;
  (*slot)->class_name = class_name;
 
 
  return interface_chain;
  return interface_chain;
}
}
 
 
static void
static void
add_category (tree klass, tree category)
add_category (tree klass, tree category)
{
{
  /* Put categories on list in reverse order.  */
  /* Put categories on list in reverse order.  */
  tree cat = lookup_category (klass, CLASS_SUPER_NAME (category));
  tree cat = lookup_category (klass, CLASS_SUPER_NAME (category));
 
 
  if (cat)
  if (cat)
    {
    {
      warning (0, "duplicate interface declaration for category %<%E(%E)%>",
      warning (0, "duplicate interface declaration for category %<%E(%E)%>",
               CLASS_NAME (klass),
               CLASS_NAME (klass),
               CLASS_SUPER_NAME (category));
               CLASS_SUPER_NAME (category));
    }
    }
  else
  else
    {
    {
      CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (klass);
      CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (klass);
      CLASS_CATEGORY_LIST (klass) = category;
      CLASS_CATEGORY_LIST (klass) = category;
    }
    }
}
}
 
 
/* Called after parsing each instance variable declaration. Necessary to
/* Called after parsing each instance variable declaration. Necessary to
   preserve typedefs and implement public/private...
   preserve typedefs and implement public/private...
 
 
   VISIBILITY is 1 for public, 0 for protected, and 2 for private.  */
   VISIBILITY is 1 for public, 0 for protected, and 2 for private.  */
 
 
static tree
static tree
add_instance_variable (tree klass, int visibility, tree field_decl)
add_instance_variable (tree klass, int visibility, tree field_decl)
{
{
  tree field_type = TREE_TYPE (field_decl);
  tree field_type = TREE_TYPE (field_decl);
  const char *ivar_name = DECL_NAME (field_decl)
  const char *ivar_name = DECL_NAME (field_decl)
                          ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (field_decl)))
                          ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (field_decl)))
                          : _("<unnamed>");
                          : _("<unnamed>");
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (TREE_CODE (field_type) == REFERENCE_TYPE)
  if (TREE_CODE (field_type) == REFERENCE_TYPE)
    {
    {
      error ("illegal reference type specified for instance variable %qs",
      error ("illegal reference type specified for instance variable %qs",
             ivar_name);
             ivar_name);
      /* Return class as is without adding this ivar.  */
      /* Return class as is without adding this ivar.  */
      return klass;
      return klass;
    }
    }
#endif
#endif
 
 
  if (field_type == error_mark_node || !TYPE_SIZE (field_type)
  if (field_type == error_mark_node || !TYPE_SIZE (field_type)
      || TYPE_SIZE (field_type) == error_mark_node)
      || TYPE_SIZE (field_type) == error_mark_node)
      /* 'type[0]' is allowed, but 'type[]' is not! */
      /* 'type[0]' is allowed, but 'type[]' is not! */
    {
    {
      error ("instance variable %qs has unknown size", ivar_name);
      error ("instance variable %qs has unknown size", ivar_name);
      /* Return class as is without adding this ivar.  */
      /* Return class as is without adding this ivar.  */
      return klass;
      return klass;
    }
    }
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  /* Check if the ivar being added has a non-POD C++ type.   If so, we will
  /* Check if the ivar being added has a non-POD C++ type.   If so, we will
     need to either (1) warn the user about it or (2) generate suitable
     need to either (1) warn the user about it or (2) generate suitable
     constructor/destructor call from '- .cxx_construct' or '- .cxx_destruct'
     constructor/destructor call from '- .cxx_construct' or '- .cxx_destruct'
     methods (if '-fobjc-call-cxx-cdtors' was specified).  */
     methods (if '-fobjc-call-cxx-cdtors' was specified).  */
  if (MAYBE_CLASS_TYPE_P (field_type)
  if (MAYBE_CLASS_TYPE_P (field_type)
      && (TYPE_NEEDS_CONSTRUCTING (field_type)
      && (TYPE_NEEDS_CONSTRUCTING (field_type)
          || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)
          || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)
          || TYPE_POLYMORPHIC_P (field_type)))
          || TYPE_POLYMORPHIC_P (field_type)))
    {
    {
      tree type_name = OBJC_TYPE_NAME (field_type);
      tree type_name = OBJC_TYPE_NAME (field_type);
 
 
      if (flag_objc_call_cxx_cdtors)
      if (flag_objc_call_cxx_cdtors)
        {
        {
          /* Since the ObjC runtime will be calling the constructors and
          /* Since the ObjC runtime will be calling the constructors and
             destructors for us, the only thing we can't handle is the lack
             destructors for us, the only thing we can't handle is the lack
             of a default constructor.  */
             of a default constructor.  */
          if (TYPE_NEEDS_CONSTRUCTING (field_type)
          if (TYPE_NEEDS_CONSTRUCTING (field_type)
              && !TYPE_HAS_DEFAULT_CONSTRUCTOR (field_type))
              && !TYPE_HAS_DEFAULT_CONSTRUCTOR (field_type))
            {
            {
              warning (0, "type %qE has no default constructor to call",
              warning (0, "type %qE has no default constructor to call",
                       type_name);
                       type_name);
 
 
              /* If we cannot call a constructor, we should also avoid
              /* If we cannot call a constructor, we should also avoid
                 calling the destructor, for symmetry.  */
                 calling the destructor, for symmetry.  */
              if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type))
              if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type))
                warning (0, "destructor for %qE shall not be run either",
                warning (0, "destructor for %qE shall not be run either",
                         type_name);
                         type_name);
            }
            }
        }
        }
      else
      else
        {
        {
          static bool warn_cxx_ivars = false;
          static bool warn_cxx_ivars = false;
 
 
          if (TYPE_POLYMORPHIC_P (field_type))
          if (TYPE_POLYMORPHIC_P (field_type))
            {
            {
              /* Vtable pointers are Real Bad(tm), since Obj-C cannot
              /* Vtable pointers are Real Bad(tm), since Obj-C cannot
                 initialize them.  */
                 initialize them.  */
              error ("type %qE has virtual member functions", type_name);
              error ("type %qE has virtual member functions", type_name);
              error ("illegal aggregate type %qE specified "
              error ("illegal aggregate type %qE specified "
                     "for instance variable %qs",
                     "for instance variable %qs",
                     type_name, ivar_name);
                     type_name, ivar_name);
              /* Return class as is without adding this ivar.  */
              /* Return class as is without adding this ivar.  */
              return klass;
              return klass;
            }
            }
 
 
          /* User-defined constructors and destructors are not known to Obj-C
          /* 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. */
             and hence will not be called.  This may or may not be a problem. */
          if (TYPE_NEEDS_CONSTRUCTING (field_type))
          if (TYPE_NEEDS_CONSTRUCTING (field_type))
            warning (0, "type %qE has a user-defined constructor", type_name);
            warning (0, "type %qE has a user-defined constructor", type_name);
          if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type))
          if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type))
            warning (0, "type %qE has a user-defined destructor", type_name);
            warning (0, "type %qE has a user-defined destructor", type_name);
 
 
          if (!warn_cxx_ivars)
          if (!warn_cxx_ivars)
            {
            {
              warning (0, "C++ constructors and destructors will not "
              warning (0, "C++ constructors and destructors will not "
                       "be invoked for Objective-C fields");
                       "be invoked for Objective-C fields");
              warn_cxx_ivars = true;
              warn_cxx_ivars = true;
            }
            }
        }
        }
    }
    }
#endif
#endif
 
 
  /* Overload the public attribute, it is not used for FIELD_DECLs.  */
  /* Overload the public attribute, it is not used for FIELD_DECLs.  */
  switch (visibility)
  switch (visibility)
    {
    {
    case 0:
    case 0:
      TREE_PUBLIC (field_decl) = 0;
      TREE_PUBLIC (field_decl) = 0;
      TREE_PRIVATE (field_decl) = 0;
      TREE_PRIVATE (field_decl) = 0;
      TREE_PROTECTED (field_decl) = 1;
      TREE_PROTECTED (field_decl) = 1;
      break;
      break;
 
 
    case 1:
    case 1:
      TREE_PUBLIC (field_decl) = 1;
      TREE_PUBLIC (field_decl) = 1;
      TREE_PRIVATE (field_decl) = 0;
      TREE_PRIVATE (field_decl) = 0;
      TREE_PROTECTED (field_decl) = 0;
      TREE_PROTECTED (field_decl) = 0;
      break;
      break;
 
 
    case 2:
    case 2:
      TREE_PUBLIC (field_decl) = 0;
      TREE_PUBLIC (field_decl) = 0;
      TREE_PRIVATE (field_decl) = 1;
      TREE_PRIVATE (field_decl) = 1;
      TREE_PROTECTED (field_decl) = 0;
      TREE_PROTECTED (field_decl) = 0;
      break;
      break;
 
 
    }
    }
 
 
  CLASS_RAW_IVARS (klass) = chainon (CLASS_RAW_IVARS (klass), field_decl);
  CLASS_RAW_IVARS (klass) = chainon (CLASS_RAW_IVARS (klass), field_decl);
 
 
  return klass;
  return klass;
}
}


static tree
static tree
is_ivar (tree decl_chain, tree ident)
is_ivar (tree decl_chain, tree ident)
{
{
  for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain))
  for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain))
    if (DECL_NAME (decl_chain) == ident)
    if (DECL_NAME (decl_chain) == ident)
      return decl_chain;
      return decl_chain;
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* True if the ivar is private and we are not in its implementation.  */
/* True if the ivar is private and we are not in its implementation.  */
 
 
static int
static int
is_private (tree decl)
is_private (tree decl)
{
{
  return (TREE_PRIVATE (decl)
  return (TREE_PRIVATE (decl)
          && ! is_ivar (CLASS_IVARS (implementation_template),
          && ! is_ivar (CLASS_IVARS (implementation_template),
                        DECL_NAME (decl)));
                        DECL_NAME (decl)));
}
}
 
 
/* We have an instance variable reference;, check to see if it is public.  */
/* We have an instance variable reference;, check to see if it is public.  */
 
 
int
int
objc_is_public (tree expr, tree identifier)
objc_is_public (tree expr, tree identifier)
{
{
  tree basetype, decl;
  tree basetype, decl;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (processing_template_decl)
  if (processing_template_decl)
    return 1;
    return 1;
#endif
#endif
 
 
  if (TREE_TYPE (expr) == error_mark_node)
  if (TREE_TYPE (expr) == error_mark_node)
    return 1;
    return 1;
 
 
  basetype = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
  basetype = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
 
 
  if (basetype && TREE_CODE (basetype) == RECORD_TYPE)
  if (basetype && TREE_CODE (basetype) == RECORD_TYPE)
    {
    {
      if (TYPE_HAS_OBJC_INFO (basetype) && TYPE_OBJC_INTERFACE (basetype))
      if (TYPE_HAS_OBJC_INFO (basetype) && TYPE_OBJC_INTERFACE (basetype))
        {
        {
          tree klass = lookup_interface (OBJC_TYPE_NAME (basetype));
          tree klass = lookup_interface (OBJC_TYPE_NAME (basetype));
 
 
          if (!klass)
          if (!klass)
            {
            {
              error ("cannot find interface declaration for %qE",
              error ("cannot find interface declaration for %qE",
                     OBJC_TYPE_NAME (basetype));
                     OBJC_TYPE_NAME (basetype));
              return 0;
              return 0;
            }
            }
 
 
          if ((decl = is_ivar (get_class_ivars (klass, true), identifier)))
          if ((decl = is_ivar (get_class_ivars (klass, true), identifier)))
            {
            {
              if (TREE_PUBLIC (decl))
              if (TREE_PUBLIC (decl))
                return 1;
                return 1;
 
 
              /* Important difference between the Stepstone translator:
              /* Important difference between the Stepstone translator:
                 all instance variables should be public within the context
                 all instance variables should be public within the context
                 of the implementation.  */
                 of the implementation.  */
              if (objc_implementation_context
              if (objc_implementation_context
                 && ((TREE_CODE (objc_implementation_context)
                 && ((TREE_CODE (objc_implementation_context)
                      == CLASS_IMPLEMENTATION_TYPE)
                      == CLASS_IMPLEMENTATION_TYPE)
                     || (TREE_CODE (objc_implementation_context)
                     || (TREE_CODE (objc_implementation_context)
                         == CATEGORY_IMPLEMENTATION_TYPE)))
                         == CATEGORY_IMPLEMENTATION_TYPE)))
                {
                {
                  tree curtype = TYPE_MAIN_VARIANT
                  tree curtype = TYPE_MAIN_VARIANT
                                 (CLASS_STATIC_TEMPLATE
                                 (CLASS_STATIC_TEMPLATE
                                  (implementation_template));
                                  (implementation_template));
 
 
                  if (basetype == curtype
                  if (basetype == curtype
                      || DERIVED_FROM_P (basetype, curtype))
                      || DERIVED_FROM_P (basetype, curtype))
                    {
                    {
                      int priv = is_private (decl);
                      int priv = is_private (decl);
 
 
                      if (priv)
                      if (priv)
                        error ("instance variable %qE is declared private",
                        error ("instance variable %qE is declared private",
                               DECL_NAME (decl));
                               DECL_NAME (decl));
 
 
                      return !priv;
                      return !priv;
                    }
                    }
                }
                }
 
 
              /* The 2.95.2 compiler sometimes allowed C functions to access
              /* The 2.95.2 compiler sometimes allowed C functions to access
                 non-@public ivars.  We will let this slide for now...  */
                 non-@public ivars.  We will let this slide for now...  */
              if (!objc_method_context)
              if (!objc_method_context)
              {
              {
                warning (0, "instance variable %qE is %s; "
                warning (0, "instance variable %qE is %s; "
                         "this will be a hard error in the future",
                         "this will be a hard error in the future",
                         identifier,
                         identifier,
                         TREE_PRIVATE (decl) ? "@private" : "@protected");
                         TREE_PRIVATE (decl) ? "@private" : "@protected");
                return 1;
                return 1;
              }
              }
 
 
              error ("instance variable %qE is declared %s",
              error ("instance variable %qE is declared %s",
                     identifier,
                     identifier,
                     TREE_PRIVATE (decl) ? "private" : "protected");
                     TREE_PRIVATE (decl) ? "private" : "protected");
              return 0;
              return 0;
            }
            }
        }
        }
    }
    }
 
 
  return 1;
  return 1;
}
}


/* Make sure all entries in CHAIN are also in LIST.  */
/* Make sure all entries in CHAIN are also in LIST.  */
 
 
static int
static int
check_methods (tree chain, tree list, int mtype)
check_methods (tree chain, tree list, int mtype)
{
{
  int first = 1;
  int first = 1;
 
 
  while (chain)
  while (chain)
    {
    {
      if (!lookup_method (list, chain))
      if (!lookup_method (list, chain))
        {
        {
          if (first)
          if (first)
            {
            {
              if (TREE_CODE (objc_implementation_context)
              if (TREE_CODE (objc_implementation_context)
                  == CLASS_IMPLEMENTATION_TYPE)
                  == CLASS_IMPLEMENTATION_TYPE)
                warning (0, "incomplete implementation of class %qE",
                warning (0, "incomplete implementation of class %qE",
                         CLASS_NAME (objc_implementation_context));
                         CLASS_NAME (objc_implementation_context));
              else if (TREE_CODE (objc_implementation_context)
              else if (TREE_CODE (objc_implementation_context)
                       == CATEGORY_IMPLEMENTATION_TYPE)
                       == CATEGORY_IMPLEMENTATION_TYPE)
                warning (0, "incomplete implementation of category %qE",
                warning (0, "incomplete implementation of category %qE",
                         CLASS_SUPER_NAME (objc_implementation_context));
                         CLASS_SUPER_NAME (objc_implementation_context));
              first = 0;
              first = 0;
            }
            }
 
 
          warning (0, "method definition for %<%c%E%> not found",
          warning (0, "method definition for %<%c%E%> not found",
                   mtype, METHOD_SEL_NAME (chain));
                   mtype, METHOD_SEL_NAME (chain));
        }
        }
 
 
      chain = TREE_CHAIN (chain);
      chain = TREE_CHAIN (chain);
    }
    }
 
 
    return first;
    return first;
}
}
 
 
/* Check if KLASS, or its superclasses, explicitly conforms to PROTOCOL.  */
/* Check if KLASS, or its superclasses, explicitly conforms to PROTOCOL.  */
 
 
static int
static int
conforms_to_protocol (tree klass, tree protocol)
conforms_to_protocol (tree klass, tree protocol)
{
{
   if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE)
   if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE)
     {
     {
       tree p = CLASS_PROTOCOL_LIST (klass);
       tree p = CLASS_PROTOCOL_LIST (klass);
       while (p && TREE_VALUE (p) != protocol)
       while (p && TREE_VALUE (p) != protocol)
         p = TREE_CHAIN (p);
         p = TREE_CHAIN (p);
 
 
       if (!p)
       if (!p)
         {
         {
           tree super = (CLASS_SUPER_NAME (klass)
           tree super = (CLASS_SUPER_NAME (klass)
                         ? lookup_interface (CLASS_SUPER_NAME (klass))
                         ? lookup_interface (CLASS_SUPER_NAME (klass))
                         : NULL_TREE);
                         : NULL_TREE);
           int tmp = super ? conforms_to_protocol (super, protocol) : 0;
           int tmp = super ? conforms_to_protocol (super, protocol) : 0;
           if (!tmp)
           if (!tmp)
             return 0;
             return 0;
         }
         }
     }
     }
 
 
   return 1;
   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.  */
   CONTEXT.  This is one of two mechanisms to check protocol integrity.  */
 
 
static int
static int
check_methods_accessible (tree chain, tree context, int mtype)
check_methods_accessible (tree chain, tree context, int mtype)
{
{
  int first = 1;
  int first = 1;
  tree list;
  tree list;
  tree base_context = context;
  tree base_context = context;
 
 
  while (chain)
  while (chain)
    {
    {
      context = base_context;
      context = base_context;
      while (context)
      while (context)
        {
        {
          if (mtype == '+')
          if (mtype == '+')
            list = CLASS_CLS_METHODS (context);
            list = CLASS_CLS_METHODS (context);
          else
          else
            list = CLASS_NST_METHODS (context);
            list = CLASS_NST_METHODS (context);
 
 
          if (lookup_method (list, chain))
          if (lookup_method (list, chain))
              break;
              break;
 
 
          else if (TREE_CODE (context) == CLASS_IMPLEMENTATION_TYPE
          else if (TREE_CODE (context) == CLASS_IMPLEMENTATION_TYPE
                   || TREE_CODE (context) == CLASS_INTERFACE_TYPE)
                   || TREE_CODE (context) == CLASS_INTERFACE_TYPE)
            context = (CLASS_SUPER_NAME (context)
            context = (CLASS_SUPER_NAME (context)
                       ? lookup_interface (CLASS_SUPER_NAME (context))
                       ? lookup_interface (CLASS_SUPER_NAME (context))
                       : NULL_TREE);
                       : NULL_TREE);
 
 
          else if (TREE_CODE (context) == CATEGORY_IMPLEMENTATION_TYPE
          else if (TREE_CODE (context) == CATEGORY_IMPLEMENTATION_TYPE
                   || TREE_CODE (context) == CATEGORY_INTERFACE_TYPE)
                   || TREE_CODE (context) == CATEGORY_INTERFACE_TYPE)
            context = (CLASS_NAME (context)
            context = (CLASS_NAME (context)
                       ? lookup_interface (CLASS_NAME (context))
                       ? lookup_interface (CLASS_NAME (context))
                       : NULL_TREE);
                       : NULL_TREE);
          else
          else
            abort ();
            abort ();
        }
        }
 
 
      if (context == NULL_TREE)
      if (context == NULL_TREE)
        {
        {
          if (first)
          if (first)
            {
            {
              if (TREE_CODE (objc_implementation_context)
              if (TREE_CODE (objc_implementation_context)
                  == CLASS_IMPLEMENTATION_TYPE)
                  == CLASS_IMPLEMENTATION_TYPE)
                warning (0, "incomplete implementation of class %qE",
                warning (0, "incomplete implementation of class %qE",
                         CLASS_NAME (objc_implementation_context));
                         CLASS_NAME (objc_implementation_context));
              else if (TREE_CODE (objc_implementation_context)
              else if (TREE_CODE (objc_implementation_context)
                       == CATEGORY_IMPLEMENTATION_TYPE)
                       == CATEGORY_IMPLEMENTATION_TYPE)
                warning (0, "incomplete implementation of category %qE",
                warning (0, "incomplete implementation of category %qE",
                         CLASS_SUPER_NAME (objc_implementation_context));
                         CLASS_SUPER_NAME (objc_implementation_context));
              first = 0;
              first = 0;
            }
            }
          warning (0, "method definition for %<%c%E%> not found",
          warning (0, "method definition for %<%c%E%> not found",
                   mtype, METHOD_SEL_NAME (chain));
                   mtype, METHOD_SEL_NAME (chain));
        }
        }
 
 
      chain = TREE_CHAIN (chain); /* next method...  */
      chain = TREE_CHAIN (chain); /* next method...  */
    }
    }
  return first;
  return first;
}
}
 
 
/* Check whether the current interface (accessible via
/* Check whether the current interface (accessible via
   'objc_implementation_context') actually implements protocol P, along
   'objc_implementation_context') actually implements protocol P, along
   with any protocols that P inherits.  */
   with any protocols that P inherits.  */
 
 
static void
static void
check_protocol (tree p, const char *type, tree name)
check_protocol (tree p, const char *type, tree name)
{
{
  if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
  if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
    {
    {
      int f1, f2;
      int f1, f2;
 
 
      /* Ensure that all protocols have bodies!  */
      /* Ensure that all protocols have bodies!  */
      if (warn_protocol)
      if (warn_protocol)
        {
        {
          f1 = check_methods (PROTOCOL_CLS_METHODS (p),
          f1 = check_methods (PROTOCOL_CLS_METHODS (p),
                              CLASS_CLS_METHODS (objc_implementation_context),
                              CLASS_CLS_METHODS (objc_implementation_context),
                              '+');
                              '+');
          f2 = check_methods (PROTOCOL_NST_METHODS (p),
          f2 = check_methods (PROTOCOL_NST_METHODS (p),
                              CLASS_NST_METHODS (objc_implementation_context),
                              CLASS_NST_METHODS (objc_implementation_context),
                              '-');
                              '-');
        }
        }
      else
      else
        {
        {
          f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p),
          f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p),
                                         objc_implementation_context,
                                         objc_implementation_context,
                                         '+');
                                         '+');
          f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p),
          f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p),
                                         objc_implementation_context,
                                         objc_implementation_context,
                                         '-');
                                         '-');
        }
        }
 
 
      if (!f1 || !f2)
      if (!f1 || !f2)
        warning (0, "%s %qE does not fully implement the %qE protocol",
        warning (0, "%s %qE does not fully implement the %qE protocol",
                 type, name, PROTOCOL_NAME (p));
                 type, name, PROTOCOL_NAME (p));
    }
    }
 
 
  /* Check protocols recursively.  */
  /* Check protocols recursively.  */
  if (PROTOCOL_LIST (p))
  if (PROTOCOL_LIST (p))
    {
    {
      tree subs = PROTOCOL_LIST (p);
      tree subs = PROTOCOL_LIST (p);
      tree super_class =
      tree super_class =
        lookup_interface (CLASS_SUPER_NAME (implementation_template));
        lookup_interface (CLASS_SUPER_NAME (implementation_template));
 
 
      while (subs)
      while (subs)
        {
        {
          tree sub = TREE_VALUE (subs);
          tree sub = TREE_VALUE (subs);
 
 
          /* If the superclass does not conform to the protocols
          /* If the superclass does not conform to the protocols
             inherited by P, then we must!  */
             inherited by P, then we must!  */
          if (!super_class || !conforms_to_protocol (super_class, sub))
          if (!super_class || !conforms_to_protocol (super_class, sub))
            check_protocol (sub, type, name);
            check_protocol (sub, type, name);
          subs = TREE_CHAIN (subs);
          subs = TREE_CHAIN (subs);
        }
        }
    }
    }
}
}
 
 
/* Check whether the current interface (accessible via
/* Check whether the current interface (accessible via
   'objc_implementation_context') actually implements the protocols listed
   'objc_implementation_context') actually implements the protocols listed
   in PROTO_LIST.  */
   in PROTO_LIST.  */
 
 
static void
static void
check_protocols (tree proto_list, const char *type, tree name)
check_protocols (tree proto_list, const char *type, tree name)
{
{
  for ( ; proto_list; proto_list = TREE_CHAIN (proto_list))
  for ( ; proto_list; proto_list = TREE_CHAIN (proto_list))
    {
    {
      tree p = TREE_VALUE (proto_list);
      tree p = TREE_VALUE (proto_list);
 
 
      check_protocol (p, type, name);
      check_protocol (p, type, name);
    }
    }
}
}


/* Make sure that the class CLASS_NAME is defined
/* Make sure that the class CLASS_NAME is defined
   CODE says which kind of thing CLASS_NAME ought to be.
   CODE says which kind of thing CLASS_NAME ought to be.
   It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
   It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
   CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE.  */
   CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE.  */
 
 
static tree
static tree
start_class (enum tree_code code, tree class_name, tree super_name,
start_class (enum tree_code code, tree class_name, tree super_name,
             tree protocol_list)
             tree protocol_list)
{
{
  tree klass, decl;
  tree klass, decl;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (current_namespace != global_namespace) {
  if (current_namespace != global_namespace) {
    error ("Objective-C declarations may only appear in global scope");
    error ("Objective-C declarations may only appear in global scope");
  }
  }
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
  if (objc_implementation_context)
  if (objc_implementation_context)
    {
    {
      warning (0, "%<@end%> missing in implementation context");
      warning (0, "%<@end%> missing in implementation context");
      finish_class (objc_implementation_context);
      finish_class (objc_implementation_context);
      objc_ivar_chain = NULL_TREE;
      objc_ivar_chain = NULL_TREE;
      objc_implementation_context = NULL_TREE;
      objc_implementation_context = NULL_TREE;
    }
    }
 
 
  klass = make_node (code);
  klass = make_node (code);
  TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
  TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
 
 
  /* Check for existence of the super class, if one was specified.  Note
  /* Check for existence of the super class, if one was specified.  Note
     that we must have seen an @interface, not just a @class.  If we
     that we must have seen an @interface, not just a @class.  If we
     are looking at a @compatibility_alias, traverse it first.  */
     are looking at a @compatibility_alias, traverse it first.  */
  if ((code == CLASS_INTERFACE_TYPE || code == CLASS_IMPLEMENTATION_TYPE)
  if ((code == CLASS_INTERFACE_TYPE || code == CLASS_IMPLEMENTATION_TYPE)
      && super_name)
      && super_name)
    {
    {
      tree super = objc_is_class_name (super_name);
      tree super = objc_is_class_name (super_name);
 
 
      if (!super || !lookup_interface (super))
      if (!super || !lookup_interface (super))
        {
        {
          error ("cannot find interface declaration for %qE, superclass of %qE",
          error ("cannot find interface declaration for %qE, superclass of %qE",
                 super ? super : super_name,
                 super ? super : super_name,
                 class_name);
                 class_name);
          super_name = NULL_TREE;
          super_name = NULL_TREE;
        }
        }
      else
      else
        super_name = super;
        super_name = super;
    }
    }
 
 
  CLASS_NAME (klass) = class_name;
  CLASS_NAME (klass) = class_name;
  CLASS_SUPER_NAME (klass) = super_name;
  CLASS_SUPER_NAME (klass) = super_name;
  CLASS_CLS_METHODS (klass) = NULL_TREE;
  CLASS_CLS_METHODS (klass) = NULL_TREE;
 
 
  if (! objc_is_class_name (class_name)
  if (! objc_is_class_name (class_name)
      && (decl = lookup_name (class_name)))
      && (decl = lookup_name (class_name)))
    {
    {
      error ("%qE redeclared as different kind of symbol",
      error ("%qE redeclared as different kind of symbol",
             class_name);
             class_name);
      error ("previous declaration of %q+D",
      error ("previous declaration of %q+D",
             decl);
             decl);
    }
    }
 
 
  if (code == CLASS_IMPLEMENTATION_TYPE)
  if (code == CLASS_IMPLEMENTATION_TYPE)
    {
    {
      {
      {
        tree chain;
        tree chain;
 
 
        for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain))
        for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain))
           if (TREE_VALUE (chain) == class_name)
           if (TREE_VALUE (chain) == class_name)
             {
             {
               error ("reimplementation of class %qE",
               error ("reimplementation of class %qE",
                      class_name);
                      class_name);
               return error_mark_node;
               return error_mark_node;
             }
             }
        implemented_classes = tree_cons (NULL_TREE, class_name,
        implemented_classes = tree_cons (NULL_TREE, class_name,
                                         implemented_classes);
                                         implemented_classes);
      }
      }
 
 
      /* Reset for multiple classes per file.  */
      /* Reset for multiple classes per file.  */
      method_slot = 0;
      method_slot = 0;
 
 
      objc_implementation_context = klass;
      objc_implementation_context = klass;
 
 
      /* Lookup the interface for this implementation.  */
      /* Lookup the interface for this implementation.  */
 
 
      if (!(implementation_template = lookup_interface (class_name)))
      if (!(implementation_template = lookup_interface (class_name)))
        {
        {
          warning (0, "cannot find interface declaration for %qE",
          warning (0, "cannot find interface declaration for %qE",
                   class_name);
                   class_name);
          add_class (implementation_template = objc_implementation_context,
          add_class (implementation_template = objc_implementation_context,
                     class_name);
                     class_name);
        }
        }
 
 
      /* If a super class has been specified in the implementation,
      /* If a super class has been specified in the implementation,
         insure it conforms to the one specified in the interface.  */
         insure it conforms to the one specified in the interface.  */
 
 
      if (super_name
      if (super_name
          && (super_name != CLASS_SUPER_NAME (implementation_template)))
          && (super_name != CLASS_SUPER_NAME (implementation_template)))
        {
        {
          tree previous_name = CLASS_SUPER_NAME (implementation_template);
          tree previous_name = CLASS_SUPER_NAME (implementation_template);
          error ("conflicting super class name %qE",
          error ("conflicting super class name %qE",
                 super_name);
                 super_name);
          if (previous_name)
          if (previous_name)
            error ("previous declaration of %qE", previous_name);
            error ("previous declaration of %qE", previous_name);
          else
          else
            error ("previous declaration");
            error ("previous declaration");
        }
        }
 
 
      else if (! super_name)
      else if (! super_name)
        {
        {
          CLASS_SUPER_NAME (objc_implementation_context)
          CLASS_SUPER_NAME (objc_implementation_context)
            = CLASS_SUPER_NAME (implementation_template);
            = CLASS_SUPER_NAME (implementation_template);
        }
        }
    }
    }
 
 
  else if (code == CLASS_INTERFACE_TYPE)
  else if (code == CLASS_INTERFACE_TYPE)
    {
    {
      if (lookup_interface (class_name))
      if (lookup_interface (class_name))
#ifdef OBJCPLUS
#ifdef OBJCPLUS
        error ("duplicate interface declaration for class %qE",
        error ("duplicate interface declaration for class %qE",
#else
#else
        warning (0, "duplicate interface declaration for class %qE",
        warning (0, "duplicate interface declaration for class %qE",
#endif
#endif
        class_name);
        class_name);
      else
      else
        add_class (klass, class_name);
        add_class (klass, class_name);
 
 
      if (protocol_list)
      if (protocol_list)
        CLASS_PROTOCOL_LIST (klass)
        CLASS_PROTOCOL_LIST (klass)
          = lookup_and_install_protocols (protocol_list);
          = lookup_and_install_protocols (protocol_list);
    }
    }
 
 
  else if (code == CATEGORY_INTERFACE_TYPE)
  else if (code == CATEGORY_INTERFACE_TYPE)
    {
    {
      tree class_category_is_assoc_with;
      tree class_category_is_assoc_with;
 
 
      /* For a category, class_name is really the name of the class that
      /* For a category, class_name is really the name of the class that
         the following set of methods will be associated with. We must
         the following set of methods will be associated with. We must
         find the interface so that can derive the objects template.  */
         find the interface so that can derive the objects template.  */
 
 
      if (!(class_category_is_assoc_with = lookup_interface (class_name)))
      if (!(class_category_is_assoc_with = lookup_interface (class_name)))
        {
        {
          error ("cannot find interface declaration for %qE",
          error ("cannot find interface declaration for %qE",
                 class_name);
                 class_name);
          exit (FATAL_EXIT_CODE);
          exit (FATAL_EXIT_CODE);
        }
        }
      else
      else
        add_category (class_category_is_assoc_with, klass);
        add_category (class_category_is_assoc_with, klass);
 
 
      if (protocol_list)
      if (protocol_list)
        CLASS_PROTOCOL_LIST (klass)
        CLASS_PROTOCOL_LIST (klass)
          = lookup_and_install_protocols (protocol_list);
          = lookup_and_install_protocols (protocol_list);
    }
    }
 
 
  else if (code == CATEGORY_IMPLEMENTATION_TYPE)
  else if (code == CATEGORY_IMPLEMENTATION_TYPE)
    {
    {
      /* Reset for multiple classes per file.  */
      /* Reset for multiple classes per file.  */
      method_slot = 0;
      method_slot = 0;
 
 
      objc_implementation_context = klass;
      objc_implementation_context = klass;
 
 
      /* For a category, class_name is really the name of the class that
      /* For a category, class_name is really the name of the class that
         the following set of methods will be associated with.  We must
         the following set of methods will be associated with.  We must
         find the interface so that can derive the objects template.  */
         find the interface so that can derive the objects template.  */
 
 
      if (!(implementation_template = lookup_interface (class_name)))
      if (!(implementation_template = lookup_interface (class_name)))
        {
        {
          error ("cannot find interface declaration for %qE",
          error ("cannot find interface declaration for %qE",
                 class_name);
                 class_name);
          exit (FATAL_EXIT_CODE);
          exit (FATAL_EXIT_CODE);
        }
        }
    }
    }
  return klass;
  return klass;
}
}
 
 
static tree
static tree
continue_class (tree klass)
continue_class (tree klass)
{
{
  if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE
  if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE
      || TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE)
      || TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE)
    {
    {
      struct imp_entry *imp_entry;
      struct imp_entry *imp_entry;
 
 
      /* Check consistency of the instance variables.  */
      /* Check consistency of the instance variables.  */
 
 
      if (CLASS_RAW_IVARS (klass))
      if (CLASS_RAW_IVARS (klass))
        check_ivars (implementation_template, klass);
        check_ivars (implementation_template, klass);
 
 
      /* code generation */
      /* code generation */
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      push_lang_context (lang_name_c);
      push_lang_context (lang_name_c);
#endif
#endif
 
 
      build_private_template (implementation_template);
      build_private_template (implementation_template);
      uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template);
      uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template);
      objc_instance_type = build_pointer_type (uprivate_record);
      objc_instance_type = build_pointer_type (uprivate_record);
 
 
      imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry));
      imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry));
 
 
      imp_entry->next = imp_list;
      imp_entry->next = imp_list;
      imp_entry->imp_context = klass;
      imp_entry->imp_context = klass;
      imp_entry->imp_template = implementation_template;
      imp_entry->imp_template = implementation_template;
 
 
      synth_forward_declarations ();
      synth_forward_declarations ();
      imp_entry->class_decl = UOBJC_CLASS_decl;
      imp_entry->class_decl = UOBJC_CLASS_decl;
      imp_entry->meta_decl = UOBJC_METACLASS_decl;
      imp_entry->meta_decl = UOBJC_METACLASS_decl;
      imp_entry->has_cxx_cdtors = 0;
      imp_entry->has_cxx_cdtors = 0;
 
 
      /* Append to front and increment count.  */
      /* Append to front and increment count.  */
      imp_list = imp_entry;
      imp_list = imp_entry;
      if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE)
      if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE)
        imp_count++;
        imp_count++;
      else
      else
        cat_count++;
        cat_count++;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      pop_lang_context ();
      pop_lang_context ();
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
      return get_class_ivars (implementation_template, true);
      return get_class_ivars (implementation_template, true);
    }
    }
 
 
  else if (TREE_CODE (klass) == CLASS_INTERFACE_TYPE)
  else if (TREE_CODE (klass) == CLASS_INTERFACE_TYPE)
    {
    {
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      push_lang_context (lang_name_c);
      push_lang_context (lang_name_c);
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
      build_private_template (klass);
      build_private_template (klass);
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      pop_lang_context ();
      pop_lang_context ();
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
      return NULL_TREE;
      return NULL_TREE;
    }
    }
 
 
  else
  else
    return error_mark_node;
    return error_mark_node;
}
}
 
 
/* This is called once we see the "@end" in an interface/implementation.  */
/* This is called once we see the "@end" in an interface/implementation.  */
 
 
static void
static void
finish_class (tree klass)
finish_class (tree klass)
{
{
  if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE)
  if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE)
    {
    {
      /* All code generation is done in finish_objc.  */
      /* All code generation is done in finish_objc.  */
 
 
      if (implementation_template != objc_implementation_context)
      if (implementation_template != objc_implementation_context)
        {
        {
          /* Ensure that all method listed in the interface contain bodies.  */
          /* Ensure that all method listed in the interface contain bodies.  */
          check_methods (CLASS_CLS_METHODS (implementation_template),
          check_methods (CLASS_CLS_METHODS (implementation_template),
                         CLASS_CLS_METHODS (objc_implementation_context), '+');
                         CLASS_CLS_METHODS (objc_implementation_context), '+');
          check_methods (CLASS_NST_METHODS (implementation_template),
          check_methods (CLASS_NST_METHODS (implementation_template),
                         CLASS_NST_METHODS (objc_implementation_context), '-');
                         CLASS_NST_METHODS (objc_implementation_context), '-');
 
 
          if (CLASS_PROTOCOL_LIST (implementation_template))
          if (CLASS_PROTOCOL_LIST (implementation_template))
            check_protocols (CLASS_PROTOCOL_LIST (implementation_template),
            check_protocols (CLASS_PROTOCOL_LIST (implementation_template),
                             "class",
                             "class",
                             CLASS_NAME (objc_implementation_context));
                             CLASS_NAME (objc_implementation_context));
        }
        }
    }
    }
 
 
  else if (TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE)
  else if (TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE)
    {
    {
      tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (klass));
      tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (klass));
 
 
      if (category)
      if (category)
        {
        {
          /* Ensure all method listed in the interface contain bodies.  */
          /* Ensure all method listed in the interface contain bodies.  */
          check_methods (CLASS_CLS_METHODS (category),
          check_methods (CLASS_CLS_METHODS (category),
                         CLASS_CLS_METHODS (objc_implementation_context), '+');
                         CLASS_CLS_METHODS (objc_implementation_context), '+');
          check_methods (CLASS_NST_METHODS (category),
          check_methods (CLASS_NST_METHODS (category),
                         CLASS_NST_METHODS (objc_implementation_context), '-');
                         CLASS_NST_METHODS (objc_implementation_context), '-');
 
 
          if (CLASS_PROTOCOL_LIST (category))
          if (CLASS_PROTOCOL_LIST (category))
            check_protocols (CLASS_PROTOCOL_LIST (category),
            check_protocols (CLASS_PROTOCOL_LIST (category),
                             "category",
                             "category",
                             CLASS_SUPER_NAME (objc_implementation_context));
                             CLASS_SUPER_NAME (objc_implementation_context));
        }
        }
    }
    }
}
}
 
 
static tree
static tree
add_protocol (tree protocol)
add_protocol (tree protocol)
{
{
  /* Put protocol on list in reverse order.  */
  /* Put protocol on list in reverse order.  */
  TREE_CHAIN (protocol) = protocol_chain;
  TREE_CHAIN (protocol) = protocol_chain;
  protocol_chain = protocol;
  protocol_chain = protocol;
  return protocol_chain;
  return protocol_chain;
}
}
 
 
static tree
static tree
lookup_protocol (tree ident)
lookup_protocol (tree ident)
{
{
  tree chain;
  tree chain;
 
 
  for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
  for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
    if (ident == PROTOCOL_NAME (chain))
    if (ident == PROTOCOL_NAME (chain))
      return chain;
      return chain;
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* This function forward declares the protocols named by NAMES.  If
/* This function forward declares the protocols named by NAMES.  If
   they are already declared or defined, the function has no effect.  */
   they are already declared or defined, the function has no effect.  */
 
 
void
void
objc_declare_protocols (tree names)
objc_declare_protocols (tree names)
{
{
  tree list;
  tree list;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (current_namespace != global_namespace) {
  if (current_namespace != global_namespace) {
    error ("Objective-C declarations may only appear in global scope");
    error ("Objective-C declarations may only appear in global scope");
  }
  }
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
  for (list = names; list; list = TREE_CHAIN (list))
  for (list = names; list; list = TREE_CHAIN (list))
    {
    {
      tree name = TREE_VALUE (list);
      tree name = TREE_VALUE (list);
 
 
      if (lookup_protocol (name) == NULL_TREE)
      if (lookup_protocol (name) == NULL_TREE)
        {
        {
          tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
          tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
 
 
          TYPE_LANG_SLOT_1 (protocol)
          TYPE_LANG_SLOT_1 (protocol)
            = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
            = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
          PROTOCOL_NAME (protocol) = name;
          PROTOCOL_NAME (protocol) = name;
          PROTOCOL_LIST (protocol) = NULL_TREE;
          PROTOCOL_LIST (protocol) = NULL_TREE;
          add_protocol (protocol);
          add_protocol (protocol);
          PROTOCOL_DEFINED (protocol) = 0;
          PROTOCOL_DEFINED (protocol) = 0;
          PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
          PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
        }
        }
    }
    }
}
}
 
 
static tree
static tree
start_protocol (enum tree_code code, tree name, tree list)
start_protocol (enum tree_code code, tree name, tree list)
{
{
  tree protocol;
  tree protocol;
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  if (current_namespace != global_namespace) {
  if (current_namespace != global_namespace) {
    error ("Objective-C declarations may only appear in global scope");
    error ("Objective-C declarations may only appear in global scope");
  }
  }
#endif /* OBJCPLUS */
#endif /* OBJCPLUS */
 
 
  protocol = lookup_protocol (name);
  protocol = lookup_protocol (name);
 
 
  if (!protocol)
  if (!protocol)
    {
    {
      protocol = make_node (code);
      protocol = make_node (code);
      TYPE_LANG_SLOT_1 (protocol) = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
      TYPE_LANG_SLOT_1 (protocol) = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
 
 
      PROTOCOL_NAME (protocol) = name;
      PROTOCOL_NAME (protocol) = name;
      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
      add_protocol (protocol);
      add_protocol (protocol);
      PROTOCOL_DEFINED (protocol) = 1;
      PROTOCOL_DEFINED (protocol) = 1;
      PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
      PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
 
 
      check_protocol_recursively (protocol, list);
      check_protocol_recursively (protocol, list);
    }
    }
  else if (! PROTOCOL_DEFINED (protocol))
  else if (! PROTOCOL_DEFINED (protocol))
    {
    {
      PROTOCOL_DEFINED (protocol) = 1;
      PROTOCOL_DEFINED (protocol) = 1;
      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
 
 
      check_protocol_recursively (protocol, list);
      check_protocol_recursively (protocol, list);
    }
    }
  else
  else
    {
    {
      warning (0, "duplicate declaration for protocol %qE",
      warning (0, "duplicate declaration for protocol %qE",
               name);
               name);
    }
    }
  return protocol;
  return protocol;
}
}
 
 


/* "Encode" a data type into a string, which grows in util_obstack.
/* "Encode" a data type into a string, which grows in util_obstack.
   ??? What is the FORMAT?  Someone please document this!  */
   ??? What is the FORMAT?  Someone please document this!  */
 
 
static void
static void
encode_type_qualifiers (tree declspecs)
encode_type_qualifiers (tree declspecs)
{
{
  tree spec;
  tree spec;
 
 
  for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
  for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
    {
    {
      if (ridpointers[(int) RID_IN] == TREE_VALUE (spec))
      if (ridpointers[(int) RID_IN] == TREE_VALUE (spec))
        obstack_1grow (&util_obstack, 'n');
        obstack_1grow (&util_obstack, 'n');
      else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec))
      else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec))
        obstack_1grow (&util_obstack, 'N');
        obstack_1grow (&util_obstack, 'N');
      else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec))
      else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec))
        obstack_1grow (&util_obstack, 'o');
        obstack_1grow (&util_obstack, 'o');
      else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec))
      else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec))
        obstack_1grow (&util_obstack, 'O');
        obstack_1grow (&util_obstack, 'O');
      else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec))
      else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec))
        obstack_1grow (&util_obstack, 'R');
        obstack_1grow (&util_obstack, 'R');
      else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec))
      else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec))
        obstack_1grow (&util_obstack, 'V');
        obstack_1grow (&util_obstack, 'V');
    }
    }
}
}
 
 
/* Encode a pointer type.  */
/* Encode a pointer type.  */
 
 
static void
static void
encode_pointer (tree type, int curtype, int format)
encode_pointer (tree type, int curtype, int format)
{
{
  tree pointer_to = TREE_TYPE (type);
  tree pointer_to = TREE_TYPE (type);
 
 
  if (TREE_CODE (pointer_to) == RECORD_TYPE)
  if (TREE_CODE (pointer_to) == RECORD_TYPE)
    {
    {
      if (OBJC_TYPE_NAME (pointer_to)
      if (OBJC_TYPE_NAME (pointer_to)
          && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
          && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
        {
        {
          const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to));
          const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to));
 
 
          if (strcmp (name, TAG_OBJECT) == 0) /* '@' */
          if (strcmp (name, TAG_OBJECT) == 0) /* '@' */
            {
            {
              obstack_1grow (&util_obstack, '@');
              obstack_1grow (&util_obstack, '@');
              return;
              return;
            }
            }
          else if (TYPE_HAS_OBJC_INFO (pointer_to)
          else if (TYPE_HAS_OBJC_INFO (pointer_to)
                   && TYPE_OBJC_INTERFACE (pointer_to))
                   && TYPE_OBJC_INTERFACE (pointer_to))
            {
            {
              if (generating_instance_variables)
              if (generating_instance_variables)
                {
                {
                  obstack_1grow (&util_obstack, '@');
                  obstack_1grow (&util_obstack, '@');
                  obstack_1grow (&util_obstack, '"');
                  obstack_1grow (&util_obstack, '"');
                  obstack_grow (&util_obstack, name, strlen (name));
                  obstack_grow (&util_obstack, name, strlen (name));
                  obstack_1grow (&util_obstack, '"');
                  obstack_1grow (&util_obstack, '"');
                  return;
                  return;
                }
                }
              else
              else
                {
                {
                  obstack_1grow (&util_obstack, '@');
                  obstack_1grow (&util_obstack, '@');
                  return;
                  return;
                }
                }
            }
            }
          else if (strcmp (name, TAG_CLASS) == 0) /* '#' */
          else if (strcmp (name, TAG_CLASS) == 0) /* '#' */
            {
            {
              obstack_1grow (&util_obstack, '#');
              obstack_1grow (&util_obstack, '#');
              return;
              return;
            }
            }
          else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */
          else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */
            {
            {
              obstack_1grow (&util_obstack, ':');
              obstack_1grow (&util_obstack, ':');
              return;
              return;
            }
            }
        }
        }
    }
    }
  else if (TREE_CODE (pointer_to) == INTEGER_TYPE
  else if (TREE_CODE (pointer_to) == INTEGER_TYPE
           && TYPE_MODE (pointer_to) == QImode)
           && TYPE_MODE (pointer_to) == QImode)
    {
    {
      tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE
      tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE
                  ? OBJC_TYPE_NAME (pointer_to)
                  ? OBJC_TYPE_NAME (pointer_to)
                  : DECL_NAME (OBJC_TYPE_NAME (pointer_to));
                  : DECL_NAME (OBJC_TYPE_NAME (pointer_to));
 
 
      if (!flag_next_runtime || strcmp (IDENTIFIER_POINTER (pname), "BOOL"))
      if (!flag_next_runtime || strcmp (IDENTIFIER_POINTER (pname), "BOOL"))
        {
        {
          /* It appears that "r*" means "const char *" rather than
          /* It appears that "r*" means "const char *" rather than
             "char *const".  */
             "char *const".  */
          if (TYPE_READONLY (pointer_to))
          if (TYPE_READONLY (pointer_to))
            obstack_1grow (&util_obstack, 'r');
            obstack_1grow (&util_obstack, 'r');
 
 
          obstack_1grow (&util_obstack, '*');
          obstack_1grow (&util_obstack, '*');
          return;
          return;
        }
        }
    }
    }
 
 
  /* We have a type that does not get special treatment.  */
  /* We have a type that does not get special treatment.  */
 
 
  /* NeXT extension */
  /* NeXT extension */
  obstack_1grow (&util_obstack, '^');
  obstack_1grow (&util_obstack, '^');
  encode_type (pointer_to, curtype, format);
  encode_type (pointer_to, curtype, format);
}
}
 
 
static void
static void
encode_array (tree type, int curtype, int format)
encode_array (tree type, int curtype, int format)
{
{
  tree an_int_cst = TYPE_SIZE (type);
  tree an_int_cst = TYPE_SIZE (type);
  tree array_of = TREE_TYPE (type);
  tree array_of = TREE_TYPE (type);
  char buffer[40];
  char buffer[40];
 
 
  /* An incomplete array is treated like a pointer.  */
  /* An incomplete array is treated like a pointer.  */
  if (an_int_cst == NULL)
  if (an_int_cst == NULL)
    {
    {
      encode_pointer (type, curtype, format);
      encode_pointer (type, curtype, format);
      return;
      return;
    }
    }
 
 
  if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0)
  if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0)
   sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
   sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
  else
  else
    sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC,
    sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC,
             TREE_INT_CST_LOW (an_int_cst)
             TREE_INT_CST_LOW (an_int_cst)
              / TREE_INT_CST_LOW (TYPE_SIZE (array_of)));
              / TREE_INT_CST_LOW (TYPE_SIZE (array_of)));
 
 
  obstack_grow (&util_obstack, buffer, strlen (buffer));
  obstack_grow (&util_obstack, buffer, strlen (buffer));
  encode_type (array_of, curtype, format);
  encode_type (array_of, curtype, format);
  obstack_1grow (&util_obstack, ']');
  obstack_1grow (&util_obstack, ']');
  return;
  return;
}
}


static void
static void
encode_aggregate_fields (tree type, int pointed_to, int curtype, int format)
encode_aggregate_fields (tree type, int pointed_to, int curtype, int format)
{
{
  tree field = TYPE_FIELDS (type);
  tree field = TYPE_FIELDS (type);
 
 
  for (; field; field = TREE_CHAIN (field))
  for (; field; field = TREE_CHAIN (field))
    {
    {
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      /* C++ static members, and things that are not field at all,
      /* C++ static members, and things that are not field at all,
         should not appear in the encoding.  */
         should not appear in the encoding.  */
      if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field))
      if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field))
        continue;
        continue;
#endif
#endif
 
 
      /* Recursively encode fields of embedded base classes.  */
      /* Recursively encode fields of embedded base classes.  */
      if (DECL_ARTIFICIAL (field) && !DECL_NAME (field)
      if (DECL_ARTIFICIAL (field) && !DECL_NAME (field)
          && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
          && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
        {
        {
          encode_aggregate_fields (TREE_TYPE (field),
          encode_aggregate_fields (TREE_TYPE (field),
                                   pointed_to, curtype, format);
                                   pointed_to, curtype, format);
          continue;
          continue;
        }
        }
 
 
      if (generating_instance_variables && !pointed_to)
      if (generating_instance_variables && !pointed_to)
        {
        {
          tree fname = DECL_NAME (field);
          tree fname = DECL_NAME (field);
 
 
          obstack_1grow (&util_obstack, '"');
          obstack_1grow (&util_obstack, '"');
 
 
          if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
          if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
            obstack_grow (&util_obstack,
            obstack_grow (&util_obstack,
                          IDENTIFIER_POINTER (fname),
                          IDENTIFIER_POINTER (fname),
                          strlen (IDENTIFIER_POINTER (fname)));
                          strlen (IDENTIFIER_POINTER (fname)));
 
 
          obstack_1grow (&util_obstack, '"');
          obstack_1grow (&util_obstack, '"');
        }
        }
 
 
      encode_field_decl (field, curtype, format);
      encode_field_decl (field, curtype, format);
    }
    }
}
}
 
 
static void
static void
encode_aggregate_within (tree type, int curtype, int format, int left,
encode_aggregate_within (tree type, int curtype, int format, int left,
                         int right)
                         int right)
{
{
  tree name;
  tree name;
  /* NB: aggregates that are pointed to have slightly different encoding
  /* NB: aggregates that are pointed to have slightly different encoding
     rules in that you never encode the names of instance variables.  */
     rules in that you never encode the names of instance variables.  */
  int ob_size = obstack_object_size (&util_obstack);
  int ob_size = obstack_object_size (&util_obstack);
  char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0;
  char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0;
  char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0;
  char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0;
  int pointed_to = (c0 == '^' || (c1 == '^' && c0 == 'r'));
  int pointed_to = (c0 == '^' || (c1 == '^' && c0 == 'r'));
  int inline_contents
  int inline_contents
   = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
   = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
      && (!pointed_to || ob_size - curtype == (c1 == 'r' ? 2 : 1)));
      && (!pointed_to || ob_size - curtype == (c1 == 'r' ? 2 : 1)));
 
 
  /* Traverse struct aliases; it is important to get the
  /* Traverse struct aliases; it is important to get the
     original struct and its tag name (if any).  */
     original struct and its tag name (if any).  */
  type = TYPE_MAIN_VARIANT (type);
  type = TYPE_MAIN_VARIANT (type);
  name = OBJC_TYPE_NAME (type);
  name = OBJC_TYPE_NAME (type);
  /* Open parenth/bracket.  */
  /* Open parenth/bracket.  */
  obstack_1grow (&util_obstack, left);
  obstack_1grow (&util_obstack, left);
 
 
  /* Encode the struct/union tag name, or '?' if a tag was
  /* Encode the struct/union tag name, or '?' if a tag was
     not provided.  Typedef aliases do not qualify.  */
     not provided.  Typedef aliases do not qualify.  */
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  /* For compatibility with the NeXT runtime, ObjC++ encodes template
  /* For compatibility with the NeXT runtime, ObjC++ encodes template
     args as a composite struct tag name. */
     args as a composite struct tag name. */
  if (name && TREE_CODE (name) == IDENTIFIER_NODE
  if (name && TREE_CODE (name) == IDENTIFIER_NODE
      /* Did this struct have a tag?  */
      /* Did this struct have a tag?  */
      && !TYPE_WAS_ANONYMOUS (type))
      && !TYPE_WAS_ANONYMOUS (type))
    obstack_grow (&util_obstack,
    obstack_grow (&util_obstack,
                  decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME),
                  decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME),
                  strlen (decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME)));
                  strlen (decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME)));
#else
#else
  if (name && TREE_CODE (name) == IDENTIFIER_NODE)
  if (name && TREE_CODE (name) == IDENTIFIER_NODE)
    obstack_grow (&util_obstack,
    obstack_grow (&util_obstack,
                  IDENTIFIER_POINTER (name),
                  IDENTIFIER_POINTER (name),
                  strlen (IDENTIFIER_POINTER (name)));
                  strlen (IDENTIFIER_POINTER (name)));
#endif
#endif
  else
  else
    obstack_1grow (&util_obstack, '?');
    obstack_1grow (&util_obstack, '?');
 
 
  /* Encode the types (and possibly names) of the inner fields,
  /* Encode the types (and possibly names) of the inner fields,
     if required.  */
     if required.  */
  if (inline_contents)
  if (inline_contents)
    {
    {
      obstack_1grow (&util_obstack, '=');
      obstack_1grow (&util_obstack, '=');
      encode_aggregate_fields (type, pointed_to, curtype, format);
      encode_aggregate_fields (type, pointed_to, curtype, format);
    }
    }
  /* Close parenth/bracket.  */
  /* Close parenth/bracket.  */
  obstack_1grow (&util_obstack, right);
  obstack_1grow (&util_obstack, right);
}
}
 
 
static void
static void
encode_aggregate (tree type, int curtype, int format)
encode_aggregate (tree type, int curtype, int format)
{
{
  enum tree_code code = TREE_CODE (type);
  enum tree_code code = TREE_CODE (type);
 
 
  switch (code)
  switch (code)
    {
    {
    case RECORD_TYPE:
    case RECORD_TYPE:
      {
      {
        encode_aggregate_within (type, curtype, format, '{', '}');
        encode_aggregate_within (type, curtype, format, '{', '}');
        break;
        break;
      }
      }
    case UNION_TYPE:
    case UNION_TYPE:
      {
      {
        encode_aggregate_within (type, curtype, format, '(', ')');
        encode_aggregate_within (type, curtype, format, '(', ')');
        break;
        break;
      }
      }
 
 
    case ENUMERAL_TYPE:
    case ENUMERAL_TYPE:
      obstack_1grow (&util_obstack, 'i');
      obstack_1grow (&util_obstack, 'i');
      break;
      break;
 
 
    default:
    default:
      break;
      break;
    }
    }
}
}
 
 
/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying
/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying
   field type.  */
   field type.  */
 
 
static void
static void
encode_next_bitfield (int width)
encode_next_bitfield (int width)
{
{
  char buffer[40];
  char buffer[40];
  sprintf (buffer, "b%d", width);
  sprintf (buffer, "b%d", width);
  obstack_grow (&util_obstack, buffer, strlen (buffer));
  obstack_grow (&util_obstack, buffer, strlen (buffer));
}
}


/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS.  */
/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS.  */
static void
static void
encode_type (tree type, int curtype, int format)
encode_type (tree type, int curtype, int format)
{
{
  enum tree_code code = TREE_CODE (type);
  enum tree_code code = TREE_CODE (type);
  char c;
  char c;
 
 
  if (type == error_mark_node)
  if (type == error_mark_node)
    return;
    return;
 
 
  if (TYPE_READONLY (type))
  if (TYPE_READONLY (type))
    obstack_1grow (&util_obstack, 'r');
    obstack_1grow (&util_obstack, 'r');
 
 
  if (code == INTEGER_TYPE)
  if (code == INTEGER_TYPE)
    {
    {
      switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
      switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
        {
        {
        case 8:  c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
        case 8:  c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
        case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
        case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
        case 32:
        case 32:
          if (type == long_unsigned_type_node
          if (type == long_unsigned_type_node
              || type == long_integer_type_node)
              || type == long_integer_type_node)
                 c = TYPE_UNSIGNED (type) ? 'L' : 'l';
                 c = TYPE_UNSIGNED (type) ? 'L' : 'l';
          else
          else
                 c = TYPE_UNSIGNED (type) ? 'I' : 'i';
                 c = TYPE_UNSIGNED (type) ? 'I' : 'i';
          break;
          break;
        case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
        case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
        default: abort ();
        default: abort ();
        }
        }
      obstack_1grow (&util_obstack, c);
      obstack_1grow (&util_obstack, c);
    }
    }
 
 
  else if (code == REAL_TYPE)
  else if (code == REAL_TYPE)
    {
    {
      /* Floating point types.  */
      /* Floating point types.  */
      switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
      switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
        {
        {
        case 32:  c = 'f'; break;
        case 32:  c = 'f'; break;
        case 64:
        case 64:
        case 96:
        case 96:
        case 128: c = 'd'; break;
        case 128: c = 'd'; break;
        default: abort ();
        default: abort ();
        }
        }
      obstack_1grow (&util_obstack, c);
      obstack_1grow (&util_obstack, c);
    }
    }
 
 
  else if (code == VOID_TYPE)
  else if (code == VOID_TYPE)
    obstack_1grow (&util_obstack, 'v');
    obstack_1grow (&util_obstack, 'v');
 
 
  else if (code == BOOLEAN_TYPE)
  else if (code == BOOLEAN_TYPE)
    obstack_1grow (&util_obstack, 'B');
    obstack_1grow (&util_obstack, 'B');
 
 
  else if (code == ARRAY_TYPE)
  else if (code == ARRAY_TYPE)
    encode_array (type, curtype, format);
    encode_array (type, curtype, format);
 
 
  else if (code == POINTER_TYPE)
  else if (code == POINTER_TYPE)
    encode_pointer (type, curtype, format);
    encode_pointer (type, curtype, format);
 
 
  else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
  else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
    encode_aggregate (type, curtype, format);
    encode_aggregate (type, curtype, format);
 
 
  else if (code == FUNCTION_TYPE) /* '?' */
  else if (code == FUNCTION_TYPE) /* '?' */
    obstack_1grow (&util_obstack, '?');
    obstack_1grow (&util_obstack, '?');
 
 
  else if (code == COMPLEX_TYPE)
  else if (code == COMPLEX_TYPE)
    {
    {
      obstack_1grow (&util_obstack, 'j');
      obstack_1grow (&util_obstack, 'j');
      encode_type (TREE_TYPE (type), curtype, format);
      encode_type (TREE_TYPE (type), curtype, format);
    }
    }
}
}
 
 
static void
static void
encode_gnu_bitfield (int position, tree type, int size)
encode_gnu_bitfield (int position, tree type, int size)
{
{
  enum tree_code code = TREE_CODE (type);
  enum tree_code code = TREE_CODE (type);
  char buffer[40];
  char buffer[40];
  char charType = '?';
  char charType = '?';
 
 
  if (code == INTEGER_TYPE)
  if (code == INTEGER_TYPE)
    {
    {
      if (integer_zerop (TYPE_MIN_VALUE (type)))
      if (integer_zerop (TYPE_MIN_VALUE (type)))
        {
        {
          /* Unsigned integer types.  */
          /* Unsigned integer types.  */
 
 
          if (TYPE_MODE (type) == QImode)
          if (TYPE_MODE (type) == QImode)
            charType = 'C';
            charType = 'C';
          else if (TYPE_MODE (type) == HImode)
          else if (TYPE_MODE (type) == HImode)
            charType = 'S';
            charType = 'S';
          else if (TYPE_MODE (type) == SImode)
          else if (TYPE_MODE (type) == SImode)
            {
            {
              if (type == long_unsigned_type_node)
              if (type == long_unsigned_type_node)
                charType = 'L';
                charType = 'L';
              else
              else
                charType = 'I';
                charType = 'I';
            }
            }
          else if (TYPE_MODE (type) == DImode)
          else if (TYPE_MODE (type) == DImode)
            charType = 'Q';
            charType = 'Q';
        }
        }
 
 
      else
      else
        /* Signed integer types.  */
        /* Signed integer types.  */
        {
        {
          if (TYPE_MODE (type) == QImode)
          if (TYPE_MODE (type) == QImode)
            charType = 'c';
            charType = 'c';
          else if (TYPE_MODE (type) == HImode)
          else if (TYPE_MODE (type) == HImode)
            charType = 's';
            charType = 's';
          else if (TYPE_MODE (type) == SImode)
          else if (TYPE_MODE (type) == SImode)
            {
            {
              if (type == long_integer_type_node)
              if (type == long_integer_type_node)
                charType = 'l';
                charType = 'l';
              else
              else
                charType = 'i';
                charType = 'i';
            }
            }
 
 
          else if (TYPE_MODE (type) == DImode)
          else if (TYPE_MODE (type) == DImode)
            charType = 'q';
            charType = 'q';
        }
        }
    }
    }
  else if (code == ENUMERAL_TYPE)
  else if (code == ENUMERAL_TYPE)
    charType = 'i';
    charType = 'i';
  else
  else
    abort ();
    abort ();
 
 
  sprintf (buffer, "b%d%c%d", position, charType, size);
  sprintf (buffer, "b%d%c%d", position, charType, size);
  obstack_grow (&util_obstack, buffer, strlen (buffer));
  obstack_grow (&util_obstack, buffer, strlen (buffer));
}
}
 
 
static void
static void
encode_field_decl (tree field_decl, int curtype, int format)
encode_field_decl (tree field_decl, int curtype, int format)
{
{
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  /* C++ static members, and things that are not fields at all,
  /* C++ static members, and things that are not fields at all,
     should not appear in the encoding.  */
     should not appear in the encoding.  */
  if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl))
  if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl))
    return;
    return;
#endif
#endif
 
 
  /* Generate the bitfield typing information, if needed.  Note the difference
  /* Generate the bitfield typing information, if needed.  Note the difference
     between GNU and NeXT runtimes.  */
     between GNU and NeXT runtimes.  */
  if (DECL_BIT_FIELD_TYPE (field_decl))
  if (DECL_BIT_FIELD_TYPE (field_decl))
    {
    {
      int size = tree_low_cst (DECL_SIZE (field_decl), 1);
      int size = tree_low_cst (DECL_SIZE (field_decl), 1);
 
 
      if (flag_next_runtime)
      if (flag_next_runtime)
        encode_next_bitfield (size);
        encode_next_bitfield (size);
      else
      else
        encode_gnu_bitfield (int_bit_position (field_decl),
        encode_gnu_bitfield (int_bit_position (field_decl),
                                  DECL_BIT_FIELD_TYPE (field_decl), size);
                                  DECL_BIT_FIELD_TYPE (field_decl), size);
    }
    }
  else
  else
    encode_type (TREE_TYPE (field_decl), curtype, format);
    encode_type (TREE_TYPE (field_decl), curtype, format);
}
}
 
 
static GTY(()) tree objc_parmlist = NULL_TREE;
static GTY(()) tree objc_parmlist = NULL_TREE;
 
 
/* Append PARM to a list of formal parameters of a method, making a necessary
/* Append PARM to a list of formal parameters of a method, making a necessary
   array-to-pointer adjustment along the way.  */
   array-to-pointer adjustment along the way.  */
 
 
static void
static void
objc_push_parm (tree parm)
objc_push_parm (tree parm)
{
{
  bool relayout_needed = false;
  bool relayout_needed = false;
 
 
  if (TREE_TYPE (parm) == error_mark_node)
  if (TREE_TYPE (parm) == error_mark_node)
    {
    {
      objc_parmlist = chainon (objc_parmlist, parm);
      objc_parmlist = chainon (objc_parmlist, parm);
      return;
      return;
    }
    }
 
 
  /* Decay arrays and functions into pointers.  */
  /* Decay arrays and functions into pointers.  */
  if (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE)
  if (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE)
    {
    {
      TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (TREE_TYPE (parm)));
      TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (TREE_TYPE (parm)));
      relayout_needed = true;
      relayout_needed = true;
    }
    }
  else if (TREE_CODE (TREE_TYPE (parm)) == FUNCTION_TYPE)
  else if (TREE_CODE (TREE_TYPE (parm)) == FUNCTION_TYPE)
    {
    {
      TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (parm));
      TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (parm));
      relayout_needed = true;
      relayout_needed = true;
    }
    }
 
 
  if (relayout_needed)
  if (relayout_needed)
    relayout_decl (parm);
    relayout_decl (parm);
 
 
 
 
  DECL_ARG_TYPE (parm)
  DECL_ARG_TYPE (parm)
    = lang_hooks.types.type_promotes_to (TREE_TYPE (parm));
    = lang_hooks.types.type_promotes_to (TREE_TYPE (parm));
 
 
  /* Record constancy and volatility.  */
  /* Record constancy and volatility.  */
  c_apply_type_quals_to_decl
  c_apply_type_quals_to_decl
  ((TYPE_READONLY (TREE_TYPE (parm)) ? TYPE_QUAL_CONST : 0)
  ((TYPE_READONLY (TREE_TYPE (parm)) ? TYPE_QUAL_CONST : 0)
   | (TYPE_RESTRICT (TREE_TYPE (parm)) ? TYPE_QUAL_RESTRICT : 0)
   | (TYPE_RESTRICT (TREE_TYPE (parm)) ? TYPE_QUAL_RESTRICT : 0)
   | (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm);
   | (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm);
 
 
  objc_parmlist = chainon (objc_parmlist, parm);
  objc_parmlist = chainon (objc_parmlist, parm);
}
}
 
 
/* Retrieve the formal parameter list constructed via preceding calls to
/* Retrieve the formal parameter list constructed via preceding calls to
   objc_push_parm().  */
   objc_push_parm().  */
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
static tree
static tree
objc_get_parm_info (int have_ellipsis ATTRIBUTE_UNUSED)
objc_get_parm_info (int have_ellipsis ATTRIBUTE_UNUSED)
#else
#else
static struct c_arg_info *
static struct c_arg_info *
objc_get_parm_info (int have_ellipsis)
objc_get_parm_info (int have_ellipsis)
#endif
#endif
{
{
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  tree parm_info = objc_parmlist;
  tree parm_info = objc_parmlist;
  objc_parmlist = NULL_TREE;
  objc_parmlist = NULL_TREE;
 
 
  return parm_info;
  return parm_info;
#else
#else
  tree parm_info = objc_parmlist;
  tree parm_info = objc_parmlist;
  struct c_arg_info *arg_info;
  struct c_arg_info *arg_info;
  /* The C front-end requires an elaborate song and dance at
  /* The C front-end requires an elaborate song and dance at
     this point.  */
     this point.  */
  push_scope ();
  push_scope ();
  declare_parm_level ();
  declare_parm_level ();
  while (parm_info)
  while (parm_info)
    {
    {
      tree next = TREE_CHAIN (parm_info);
      tree next = TREE_CHAIN (parm_info);
 
 
      TREE_CHAIN (parm_info) = NULL_TREE;
      TREE_CHAIN (parm_info) = NULL_TREE;
      parm_info = pushdecl (parm_info);
      parm_info = pushdecl (parm_info);
      finish_decl (parm_info, input_location, NULL_TREE, NULL_TREE, NULL_TREE);
      finish_decl (parm_info, input_location, NULL_TREE, NULL_TREE, NULL_TREE);
      parm_info = next;
      parm_info = next;
    }
    }
  arg_info = get_parm_info (have_ellipsis);
  arg_info = get_parm_info (have_ellipsis);
  pop_scope ();
  pop_scope ();
  objc_parmlist = NULL_TREE;
  objc_parmlist = NULL_TREE;
  return arg_info;
  return arg_info;
#endif
#endif
}
}
 
 
/* Synthesize the formal parameters 'id self' and 'SEL _cmd' needed for ObjC
/* Synthesize the formal parameters 'id self' and 'SEL _cmd' needed for ObjC
   method definitions.  In the case of instance methods, we can be more
   method definitions.  In the case of instance methods, we can be more
   specific as to the type of 'self'.  */
   specific as to the type of 'self'.  */
 
 
static void
static void
synth_self_and_ucmd_args (void)
synth_self_and_ucmd_args (void)
{
{
  tree self_type;
  tree self_type;
 
 
  if (objc_method_context
  if (objc_method_context
      && TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL)
      && TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL)
    self_type = objc_instance_type;
    self_type = objc_instance_type;
  else
  else
    /* Really a `struct objc_class *'. However, we allow people to
    /* Really a `struct objc_class *'. However, we allow people to
       assign to self, which changes its type midstream.  */
       assign to self, which changes its type midstream.  */
    self_type = objc_object_type;
    self_type = objc_object_type;
 
 
  /* id self; */
  /* id self; */
  objc_push_parm (build_decl (input_location,
  objc_push_parm (build_decl (input_location,
                              PARM_DECL, self_id, self_type));
                              PARM_DECL, self_id, self_type));
 
 
  /* SEL _cmd; */
  /* SEL _cmd; */
  objc_push_parm (build_decl (input_location,
  objc_push_parm (build_decl (input_location,
                              PARM_DECL, ucmd_id, objc_selector_type));
                              PARM_DECL, ucmd_id, objc_selector_type));
}
}
 
 
/* Transform an Objective-C method definition into a static C function
/* Transform an Objective-C method definition into a static C function
   definition, synthesizing the first two arguments, "self" and "_cmd",
   definition, synthesizing the first two arguments, "self" and "_cmd",
   in the process.  */
   in the process.  */
 
 
static void
static void
start_method_def (tree method)
start_method_def (tree method)
{
{
  tree parmlist;
  tree parmlist;
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  tree parm_info;
  tree parm_info;
#else
#else
  struct c_arg_info *parm_info;
  struct c_arg_info *parm_info;
#endif
#endif
  int have_ellipsis = 0;
  int have_ellipsis = 0;
 
 
  /* If we are defining a "dealloc" method in a non-root class, we
  /* If we are defining a "dealloc" method in a non-root class, we
     will need to check if a [super dealloc] is missing, and warn if
     will need to check if a [super dealloc] is missing, and warn if
     it is.  */
     it is.  */
  if(CLASS_SUPER_NAME (objc_implementation_context)
  if(CLASS_SUPER_NAME (objc_implementation_context)
     && !strcmp ("dealloc", IDENTIFIER_POINTER (METHOD_SEL_NAME (method))))
     && !strcmp ("dealloc", IDENTIFIER_POINTER (METHOD_SEL_NAME (method))))
    should_call_super_dealloc = 1;
    should_call_super_dealloc = 1;
  else
  else
    should_call_super_dealloc = 0;
    should_call_super_dealloc = 0;
 
 
  /* Required to implement _msgSuper.  */
  /* Required to implement _msgSuper.  */
  objc_method_context = method;
  objc_method_context = method;
  UOBJC_SUPER_decl = NULL_TREE;
  UOBJC_SUPER_decl = NULL_TREE;
 
 
  /* Generate prototype declarations for arguments..."new-style".  */
  /* Generate prototype declarations for arguments..."new-style".  */
  synth_self_and_ucmd_args ();
  synth_self_and_ucmd_args ();
 
 
  /* Generate argument declarations if a keyword_decl.  */
  /* Generate argument declarations if a keyword_decl.  */
  parmlist = METHOD_SEL_ARGS (method);
  parmlist = METHOD_SEL_ARGS (method);
  while (parmlist)
  while (parmlist)
    {
    {
      tree type = TREE_VALUE (TREE_TYPE (parmlist)), parm;
      tree type = TREE_VALUE (TREE_TYPE (parmlist)), parm;
 
 
      parm = build_decl (input_location,
      parm = build_decl (input_location,
                         PARM_DECL, KEYWORD_ARG_NAME (parmlist), type);
                         PARM_DECL, KEYWORD_ARG_NAME (parmlist), type);
      objc_push_parm (parm);
      objc_push_parm (parm);
      parmlist = TREE_CHAIN (parmlist);
      parmlist = TREE_CHAIN (parmlist);
    }
    }
 
 
  if (METHOD_ADD_ARGS (method))
  if (METHOD_ADD_ARGS (method))
    {
    {
      tree akey;
      tree akey;
 
 
      for (akey = TREE_CHAIN (METHOD_ADD_ARGS (method));
      for (akey = TREE_CHAIN (METHOD_ADD_ARGS (method));
           akey; akey = TREE_CHAIN (akey))
           akey; akey = TREE_CHAIN (akey))
        {
        {
          objc_push_parm (TREE_VALUE (akey));
          objc_push_parm (TREE_VALUE (akey));
        }
        }
 
 
      if (METHOD_ADD_ARGS_ELLIPSIS_P (method))
      if (METHOD_ADD_ARGS_ELLIPSIS_P (method))
        have_ellipsis = 1;
        have_ellipsis = 1;
    }
    }
 
 
  parm_info = objc_get_parm_info (have_ellipsis);
  parm_info = objc_get_parm_info (have_ellipsis);
 
 
  really_start_method (objc_method_context, parm_info);
  really_start_method (objc_method_context, parm_info);
}
}
 
 
/* Return 1 if TYPE1 is equivalent to TYPE2
/* Return 1 if TYPE1 is equivalent to TYPE2
   for purposes of method overloading.  */
   for purposes of method overloading.  */
 
 
static int
static int
objc_types_are_equivalent (tree type1, tree type2)
objc_types_are_equivalent (tree type1, tree type2)
{
{
  if (type1 == type2)
  if (type1 == type2)
    return 1;
    return 1;
 
 
  /* Strip away indirections.  */
  /* Strip away indirections.  */
  while ((TREE_CODE (type1) == ARRAY_TYPE || TREE_CODE (type1) == POINTER_TYPE)
  while ((TREE_CODE (type1) == ARRAY_TYPE || TREE_CODE (type1) == POINTER_TYPE)
         && (TREE_CODE (type1) == TREE_CODE (type2)))
         && (TREE_CODE (type1) == TREE_CODE (type2)))
    type1 = TREE_TYPE (type1), type2 = TREE_TYPE (type2);
    type1 = TREE_TYPE (type1), type2 = TREE_TYPE (type2);
  if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
  if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
    return 0;
    return 0;
 
 
  type1 = (TYPE_HAS_OBJC_INFO (type1)
  type1 = (TYPE_HAS_OBJC_INFO (type1)
           ? TYPE_OBJC_PROTOCOL_LIST (type1)
           ? TYPE_OBJC_PROTOCOL_LIST (type1)
           : NULL_TREE);
           : NULL_TREE);
  type2 = (TYPE_HAS_OBJC_INFO (type2)
  type2 = (TYPE_HAS_OBJC_INFO (type2)
           ? TYPE_OBJC_PROTOCOL_LIST (type2)
           ? TYPE_OBJC_PROTOCOL_LIST (type2)
           : NULL_TREE);
           : NULL_TREE);
 
 
  if (list_length (type1) == list_length (type2))
  if (list_length (type1) == list_length (type2))
    {
    {
      for (; type2; type2 = TREE_CHAIN (type2))
      for (; type2; type2 = TREE_CHAIN (type2))
        if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2)))
        if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2)))
          return 0;
          return 0;
      return 1;
      return 1;
    }
    }
  return 0;
  return 0;
}
}
 
 
/* Return 1 if TYPE1 has the same size and alignment as TYPE2.  */
/* Return 1 if TYPE1 has the same size and alignment as TYPE2.  */
 
 
static int
static int
objc_types_share_size_and_alignment (tree type1, tree type2)
objc_types_share_size_and_alignment (tree type1, tree type2)
{
{
  return (simple_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))
  return (simple_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))
          && TYPE_ALIGN (type1) == TYPE_ALIGN (type2));
          && TYPE_ALIGN (type1) == TYPE_ALIGN (type2));
}
}
 
 
/* Return 1 if PROTO1 is equivalent to PROTO2
/* Return 1 if PROTO1 is equivalent to PROTO2
   for purposes of method overloading.  Ordinarily, the type signatures
   for purposes of method overloading.  Ordinarily, the type signatures
   should match up exactly, unless STRICT is zero, in which case we
   should match up exactly, unless STRICT is zero, in which case we
   shall allow differences in which the size and alignment of a type
   shall allow differences in which the size and alignment of a type
   is the same.  */
   is the same.  */
 
 
static int
static int
comp_proto_with_proto (tree proto1, tree proto2, int strict)
comp_proto_with_proto (tree proto1, tree proto2, int strict)
{
{
  tree type1, type2;
  tree type1, type2;
 
 
  /* The following test is needed in case there are hashing
  /* The following test is needed in case there are hashing
     collisions.  */
     collisions.  */
  if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2))
  if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2))
    return 0;
    return 0;
 
 
  /* Compare return types.  */
  /* Compare return types.  */
  type1 = TREE_VALUE (TREE_TYPE (proto1));
  type1 = TREE_VALUE (TREE_TYPE (proto1));
  type2 = TREE_VALUE (TREE_TYPE (proto2));
  type2 = TREE_VALUE (TREE_TYPE (proto2));
 
 
  if (!objc_types_are_equivalent (type1, type2)
  if (!objc_types_are_equivalent (type1, type2)
      && (strict || !objc_types_share_size_and_alignment (type1, type2)))
      && (strict || !objc_types_share_size_and_alignment (type1, type2)))
    return 0;
    return 0;
 
 
  /* Compare argument types.  */
  /* Compare argument types.  */
  for (type1 = get_arg_type_list (proto1, METHOD_REF, 0),
  for (type1 = get_arg_type_list (proto1, METHOD_REF, 0),
       type2 = get_arg_type_list (proto2, METHOD_REF, 0);
       type2 = get_arg_type_list (proto2, METHOD_REF, 0);
       type1 && type2;
       type1 && type2;
       type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2))
       type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2))
    {
    {
      if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2))
      if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2))
          && (strict
          && (strict
              || !objc_types_share_size_and_alignment (TREE_VALUE (type1),
              || !objc_types_share_size_and_alignment (TREE_VALUE (type1),
                                                       TREE_VALUE (type2))))
                                                       TREE_VALUE (type2))))
        return 0;
        return 0;
    }
    }
 
 
  return (!type1 && !type2);
  return (!type1 && !type2);
}
}
 
 
/* Fold an OBJ_TYPE_REF expression for ObjC method dispatches, where
/* Fold an OBJ_TYPE_REF expression for ObjC method dispatches, where
   this occurs.  ObjC method dispatches are _not_ like C++ virtual
   this occurs.  ObjC method dispatches are _not_ like C++ virtual
   member function dispatches, and we account for the difference here.  */
   member function dispatches, and we account for the difference here.  */
tree
tree
#ifdef OBJCPLUS
#ifdef OBJCPLUS
objc_fold_obj_type_ref (tree ref, tree known_type)
objc_fold_obj_type_ref (tree ref, tree known_type)
#else
#else
objc_fold_obj_type_ref (tree ref ATTRIBUTE_UNUSED,
objc_fold_obj_type_ref (tree ref ATTRIBUTE_UNUSED,
                        tree known_type ATTRIBUTE_UNUSED)
                        tree known_type ATTRIBUTE_UNUSED)
#endif
#endif
{
{
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  tree v = BINFO_VIRTUALS (TYPE_BINFO (known_type));
  tree v = BINFO_VIRTUALS (TYPE_BINFO (known_type));
 
 
  /* If the receiver does not have virtual member functions, there
  /* If the receiver does not have virtual member functions, there
     is nothing we can (or need to) do here.  */
     is nothing we can (or need to) do here.  */
  if (!v)
  if (!v)
    return NULL_TREE;
    return NULL_TREE;
 
 
  /* Let C++ handle C++ virtual functions.  */
  /* Let C++ handle C++ virtual functions.  */
  return cp_fold_obj_type_ref (ref, known_type);
  return cp_fold_obj_type_ref (ref, known_type);
#else
#else
  /* For plain ObjC, we currently do not need to do anything.  */
  /* For plain ObjC, we currently do not need to do anything.  */
  return NULL_TREE;
  return NULL_TREE;
#endif
#endif
}
}
 
 
static void
static void
objc_start_function (tree name, tree type, tree attrs,
objc_start_function (tree name, tree type, tree attrs,
#ifdef OBJCPLUS
#ifdef OBJCPLUS
                     tree params
                     tree params
#else
#else
                     struct c_arg_info *params
                     struct c_arg_info *params
#endif
#endif
                     )
                     )
{
{
  tree fndecl = build_decl (input_location,
  tree fndecl = build_decl (input_location,
                            FUNCTION_DECL, name, type);
                            FUNCTION_DECL, name, type);
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  DECL_ARGUMENTS (fndecl) = params;
  DECL_ARGUMENTS (fndecl) = params;
  DECL_INITIAL (fndecl) = error_mark_node;
  DECL_INITIAL (fndecl) = error_mark_node;
  DECL_EXTERNAL (fndecl) = 0;
  DECL_EXTERNAL (fndecl) = 0;
  TREE_STATIC (fndecl) = 1;
  TREE_STATIC (fndecl) = 1;
  retrofit_lang_decl (fndecl);
  retrofit_lang_decl (fndecl);
  cplus_decl_attributes (&fndecl, attrs, 0);
  cplus_decl_attributes (&fndecl, attrs, 0);
  start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT);
  start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT);
#else
#else
  current_function_returns_value = 0;  /* Assume, until we see it does.  */
  current_function_returns_value = 0;  /* Assume, until we see it does.  */
  current_function_returns_null = 0;
  current_function_returns_null = 0;
 
 
  decl_attributes (&fndecl, attrs, 0);
  decl_attributes (&fndecl, attrs, 0);
  announce_function (fndecl);
  announce_function (fndecl);
  DECL_INITIAL (fndecl) = error_mark_node;
  DECL_INITIAL (fndecl) = error_mark_node;
  DECL_EXTERNAL (fndecl) = 0;
  DECL_EXTERNAL (fndecl) = 0;
  TREE_STATIC (fndecl) = 1;
  TREE_STATIC (fndecl) = 1;
  current_function_decl = pushdecl (fndecl);
  current_function_decl = pushdecl (fndecl);
  push_scope ();
  push_scope ();
  declare_parm_level ();
  declare_parm_level ();
  DECL_RESULT (current_function_decl)
  DECL_RESULT (current_function_decl)
    = build_decl (input_location,
    = build_decl (input_location,
                  RESULT_DECL, NULL_TREE,
                  RESULT_DECL, NULL_TREE,
                  TREE_TYPE (TREE_TYPE (current_function_decl)));
                  TREE_TYPE (TREE_TYPE (current_function_decl)));
  DECL_ARTIFICIAL (DECL_RESULT (current_function_decl)) = 1;
  DECL_ARTIFICIAL (DECL_RESULT (current_function_decl)) = 1;
  DECL_IGNORED_P (DECL_RESULT (current_function_decl)) = 1;
  DECL_IGNORED_P (DECL_RESULT (current_function_decl)) = 1;
  start_fname_decls ();
  start_fname_decls ();
  store_parm_decls_from (params);
  store_parm_decls_from (params);
#endif
#endif
 
 
  TREE_USED (current_function_decl) = 1;
  TREE_USED (current_function_decl) = 1;
}
}
 
 
/* - Generate an identifier for the function. the format is "_n_cls",
/* - Generate an identifier for the function. the format is "_n_cls",
     where 1 <= n <= nMethods, and cls is the name the implementation we
     where 1 <= n <= nMethods, and cls is the name the implementation we
     are processing.
     are processing.
   - Install the return type from the method declaration.
   - Install the return type from the method declaration.
   - If we have a prototype, check for type consistency.  */
   - If we have a prototype, check for type consistency.  */
 
 
static void
static void
really_start_method (tree method,
really_start_method (tree method,
#ifdef OBJCPLUS
#ifdef OBJCPLUS
                     tree parmlist
                     tree parmlist
#else
#else
                     struct c_arg_info *parmlist
                     struct c_arg_info *parmlist
#endif
#endif
                     )
                     )
{
{
  tree ret_type, meth_type;
  tree ret_type, meth_type;
  tree method_id;
  tree method_id;
  const char *sel_name, *class_name, *cat_name;
  const char *sel_name, *class_name, *cat_name;
  char *buf;
  char *buf;
 
 
  /* Synth the storage class & assemble the return type.  */
  /* Synth the storage class & assemble the return type.  */
  ret_type = TREE_VALUE (TREE_TYPE (method));
  ret_type = TREE_VALUE (TREE_TYPE (method));
 
 
  sel_name = IDENTIFIER_POINTER (METHOD_SEL_NAME (method));
  sel_name = IDENTIFIER_POINTER (METHOD_SEL_NAME (method));
  class_name = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context));
  class_name = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context));
  cat_name = ((TREE_CODE (objc_implementation_context)
  cat_name = ((TREE_CODE (objc_implementation_context)
               == CLASS_IMPLEMENTATION_TYPE)
               == CLASS_IMPLEMENTATION_TYPE)
              ? NULL
              ? NULL
              : IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)));
              : IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)));
  method_slot++;
  method_slot++;
 
 
  /* Make sure this is big enough for any plausible method label.  */
  /* Make sure this is big enough for any plausible method label.  */
  buf = (char *) alloca (50 + strlen (sel_name) + strlen (class_name)
  buf = (char *) alloca (50 + strlen (sel_name) + strlen (class_name)
                         + (cat_name ? strlen (cat_name) : 0));
                         + (cat_name ? strlen (cat_name) : 0));
 
 
  OBJC_GEN_METHOD_LABEL (buf, TREE_CODE (method) == INSTANCE_METHOD_DECL,
  OBJC_GEN_METHOD_LABEL (buf, TREE_CODE (method) == INSTANCE_METHOD_DECL,
                         class_name, cat_name, sel_name, method_slot);
                         class_name, cat_name, sel_name, method_slot);
 
 
  method_id = get_identifier (buf);
  method_id = get_identifier (buf);
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  /* Objective-C methods cannot be overloaded, so we don't need
  /* Objective-C methods cannot be overloaded, so we don't need
     the type encoding appended.  It looks bad anyway... */
     the type encoding appended.  It looks bad anyway... */
  push_lang_context (lang_name_c);
  push_lang_context (lang_name_c);
#endif
#endif
 
 
  meth_type
  meth_type
    = build_function_type (ret_type,
    = build_function_type (ret_type,
                           get_arg_type_list (method, METHOD_DEF, 0));
                           get_arg_type_list (method, METHOD_DEF, 0));
  objc_start_function (method_id, meth_type, NULL_TREE, parmlist);
  objc_start_function (method_id, meth_type, NULL_TREE, parmlist);
 
 
  /* Set self_decl from the first argument.  */
  /* Set self_decl from the first argument.  */
  self_decl = DECL_ARGUMENTS (current_function_decl);
  self_decl = DECL_ARGUMENTS (current_function_decl);
 
 
  /* Suppress unused warnings.  */
  /* Suppress unused warnings.  */
  TREE_USED (self_decl) = 1;
  TREE_USED (self_decl) = 1;
  TREE_USED (TREE_CHAIN (self_decl)) = 1;
  TREE_USED (TREE_CHAIN (self_decl)) = 1;
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  pop_lang_context ();
  pop_lang_context ();
#endif
#endif
 
 
  METHOD_DEFINITION (method) = current_function_decl;
  METHOD_DEFINITION (method) = current_function_decl;
 
 
  /* Check consistency...start_function, pushdecl, duplicate_decls.  */
  /* Check consistency...start_function, pushdecl, duplicate_decls.  */
 
 
  if (implementation_template != objc_implementation_context)
  if (implementation_template != objc_implementation_context)
    {
    {
      tree proto
      tree proto
        = lookup_method_static (implementation_template,
        = lookup_method_static (implementation_template,
                                METHOD_SEL_NAME (method),
                                METHOD_SEL_NAME (method),
                                ((TREE_CODE (method) == CLASS_METHOD_DECL)
                                ((TREE_CODE (method) == CLASS_METHOD_DECL)
                                 | OBJC_LOOKUP_NO_SUPER));
                                 | OBJC_LOOKUP_NO_SUPER));
 
 
      if (proto)
      if (proto)
        {
        {
          if (!comp_proto_with_proto (method, proto, 1))
          if (!comp_proto_with_proto (method, proto, 1))
            {
            {
              bool type = TREE_CODE (method) == INSTANCE_METHOD_DECL;
              bool type = TREE_CODE (method) == INSTANCE_METHOD_DECL;
 
 
              warning_at (DECL_SOURCE_LOCATION (method), 0,
              warning_at (DECL_SOURCE_LOCATION (method), 0,
                          "conflicting types for %<%c%s%>",
                          "conflicting types for %<%c%s%>",
                          (type ? '-' : '+'),
                          (type ? '-' : '+'),
                          identifier_to_locale (gen_method_decl (method)));
                          identifier_to_locale (gen_method_decl (method)));
              inform (DECL_SOURCE_LOCATION (proto),
              inform (DECL_SOURCE_LOCATION (proto),
                      "previous declaration of %<%c%s%>",
                      "previous declaration of %<%c%s%>",
                      (type ? '-' : '+'),
                      (type ? '-' : '+'),
                      identifier_to_locale (gen_method_decl (proto)));
                      identifier_to_locale (gen_method_decl (proto)));
            }
            }
        }
        }
      else
      else
        {
        {
          /* We have a method @implementation even though we did not
          /* We have a method @implementation even though we did not
             see a corresponding @interface declaration (which is allowed
             see a corresponding @interface declaration (which is allowed
             by Objective-C rules).  Go ahead and place the method in
             by Objective-C rules).  Go ahead and place the method in
             the @interface anyway, so that message dispatch lookups
             the @interface anyway, so that message dispatch lookups
             will see it.  */
             will see it.  */
          tree interface = implementation_template;
          tree interface = implementation_template;
 
 
          if (TREE_CODE (objc_implementation_context)
          if (TREE_CODE (objc_implementation_context)
              == CATEGORY_IMPLEMENTATION_TYPE)
              == CATEGORY_IMPLEMENTATION_TYPE)
            interface = lookup_category
            interface = lookup_category
                        (interface,
                        (interface,
                         CLASS_SUPER_NAME (objc_implementation_context));
                         CLASS_SUPER_NAME (objc_implementation_context));
 
 
          if (interface)
          if (interface)
            objc_add_method (interface, copy_node (method),
            objc_add_method (interface, copy_node (method),
                             TREE_CODE (method) == CLASS_METHOD_DECL);
                             TREE_CODE (method) == CLASS_METHOD_DECL);
        }
        }
    }
    }
}
}
 
 
static void *UOBJC_SUPER_scope = 0;
static void *UOBJC_SUPER_scope = 0;
 
 
/* _n_Method (id self, SEL sel, ...)
/* _n_Method (id self, SEL sel, ...)
     {
     {
       struct objc_super _S;
       struct objc_super _S;
       _msgSuper ((_S.self = self, _S.class = _cls, &_S), ...);
       _msgSuper ((_S.self = self, _S.class = _cls, &_S), ...);
     }  */
     }  */
 
 
static tree
static tree
get_super_receiver (void)
get_super_receiver (void)
{
{
  if (objc_method_context)
  if (objc_method_context)
    {
    {
      tree super_expr, super_expr_list;
      tree super_expr, super_expr_list;
 
 
      if (!UOBJC_SUPER_decl)
      if (!UOBJC_SUPER_decl)
      {
      {
        UOBJC_SUPER_decl = build_decl (input_location,
        UOBJC_SUPER_decl = build_decl (input_location,
                                       VAR_DECL, get_identifier (TAG_SUPER),
                                       VAR_DECL, get_identifier (TAG_SUPER),
                                       objc_super_template);
                                       objc_super_template);
        /* This prevents `unused variable' warnings when compiling with -Wall.  */
        /* This prevents `unused variable' warnings when compiling with -Wall.  */
        TREE_USED (UOBJC_SUPER_decl) = 1;
        TREE_USED (UOBJC_SUPER_decl) = 1;
        lang_hooks.decls.pushdecl (UOBJC_SUPER_decl);
        lang_hooks.decls.pushdecl (UOBJC_SUPER_decl);
        finish_decl (UOBJC_SUPER_decl, input_location, NULL_TREE, NULL_TREE,
        finish_decl (UOBJC_SUPER_decl, input_location, NULL_TREE, NULL_TREE,
                     NULL_TREE);
                     NULL_TREE);
        UOBJC_SUPER_scope = objc_get_current_scope ();
        UOBJC_SUPER_scope = objc_get_current_scope ();
      }
      }
 
 
      /* Set receiver to self.  */
      /* Set receiver to self.  */
      super_expr = objc_build_component_ref (UOBJC_SUPER_decl, self_id);
      super_expr = objc_build_component_ref (UOBJC_SUPER_decl, self_id);
      super_expr = build_modify_expr (input_location, super_expr, NULL_TREE,
      super_expr = build_modify_expr (input_location, super_expr, NULL_TREE,
                                      NOP_EXPR, input_location, self_decl,
                                      NOP_EXPR, input_location, self_decl,
                                      NULL_TREE);
                                      NULL_TREE);
      super_expr_list = super_expr;
      super_expr_list = super_expr;
 
 
      /* Set class to begin searching.  */
      /* Set class to begin searching.  */
      super_expr = objc_build_component_ref (UOBJC_SUPER_decl,
      super_expr = objc_build_component_ref (UOBJC_SUPER_decl,
                                             get_identifier ("super_class"));
                                             get_identifier ("super_class"));
 
 
      if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
      if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
        {
        {
          /* [_cls, __cls]Super are "pre-built" in
          /* [_cls, __cls]Super are "pre-built" in
             synth_forward_declarations.  */
             synth_forward_declarations.  */
 
 
          super_expr = build_modify_expr (input_location, super_expr,
          super_expr = build_modify_expr (input_location, super_expr,
                                          NULL_TREE, NOP_EXPR,
                                          NULL_TREE, NOP_EXPR,
                                          input_location,
                                          input_location,
                                          ((TREE_CODE (objc_method_context)
                                          ((TREE_CODE (objc_method_context)
                                            == INSTANCE_METHOD_DECL)
                                            == INSTANCE_METHOD_DECL)
                                           ? ucls_super_ref
                                           ? ucls_super_ref
                                           : uucls_super_ref),
                                           : uucls_super_ref),
                                          NULL_TREE);
                                          NULL_TREE);
        }
        }
 
 
      else
      else
        /* We have a category.  */
        /* We have a category.  */
        {
        {
          tree super_name = CLASS_SUPER_NAME (implementation_template);
          tree super_name = CLASS_SUPER_NAME (implementation_template);
          tree super_class;
          tree super_class;
 
 
          /* Barf if super used in a category of Object.  */
          /* Barf if super used in a category of Object.  */
          if (!super_name)
          if (!super_name)
            {
            {
              error ("no super class declared in interface for %qE",
              error ("no super class declared in interface for %qE",
                     CLASS_NAME (implementation_template));
                     CLASS_NAME (implementation_template));
              return error_mark_node;
              return error_mark_node;
            }
            }
 
 
          if (flag_next_runtime && !flag_zero_link)
          if (flag_next_runtime && !flag_zero_link)
            {
            {
              super_class = objc_get_class_reference (super_name);
              super_class = objc_get_class_reference (super_name);
              if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
              if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
                /* If we are in a class method, we must retrieve the
                /* If we are in a class method, we must retrieve the
                   _metaclass_ for the current class, pointed at by
                   _metaclass_ for the current class, pointed at by
                   the class's "isa" pointer.  The following assumes that
                   the class's "isa" pointer.  The following assumes that
                   "isa" is the first ivar in a class (which it must be).  */
                   "isa" is the first ivar in a class (which it must be).  */
                super_class
                super_class
                  = build_indirect_ref
                  = build_indirect_ref
                      (input_location,
                      (input_location,
                       build_c_cast (input_location,
                       build_c_cast (input_location,
                                     build_pointer_type (objc_class_type),
                                     build_pointer_type (objc_class_type),
                                     super_class), RO_UNARY_STAR);
                                     super_class), RO_UNARY_STAR);
            }
            }
          else
          else
            {
            {
              add_class_reference (super_name);
              add_class_reference (super_name);
              super_class = (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL
              super_class = (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL
                             ? objc_get_class_decl : objc_get_meta_class_decl);
                             ? objc_get_class_decl : objc_get_meta_class_decl);
              assemble_external (super_class);
              assemble_external (super_class);
              super_class
              super_class
                = build_function_call
                = build_function_call
                  (input_location,
                  (input_location,
                   super_class,
                   super_class,
                   build_tree_list
                   build_tree_list
                   (NULL_TREE,
                   (NULL_TREE,
                    my_build_string_pointer
                    my_build_string_pointer
                    (IDENTIFIER_LENGTH (super_name) + 1,
                    (IDENTIFIER_LENGTH (super_name) + 1,
                     IDENTIFIER_POINTER (super_name))));
                     IDENTIFIER_POINTER (super_name))));
            }
            }
 
 
          super_expr
          super_expr
            = build_modify_expr (input_location, super_expr, NULL_TREE,
            = build_modify_expr (input_location, super_expr, NULL_TREE,
                                 NOP_EXPR,
                                 NOP_EXPR,
                                 input_location,
                                 input_location,
                                 build_c_cast (input_location,
                                 build_c_cast (input_location,
                                               TREE_TYPE (super_expr),
                                               TREE_TYPE (super_expr),
                                               super_class),
                                               super_class),
                                 NULL_TREE);
                                 NULL_TREE);
        }
        }
 
 
      super_expr_list = build_compound_expr (input_location,
      super_expr_list = build_compound_expr (input_location,
                                             super_expr_list, super_expr);
                                             super_expr_list, super_expr);
 
 
      super_expr = build_unary_op (input_location,
      super_expr = build_unary_op (input_location,
                                   ADDR_EXPR, UOBJC_SUPER_decl, 0);
                                   ADDR_EXPR, UOBJC_SUPER_decl, 0);
      super_expr_list = build_compound_expr (input_location,
      super_expr_list = build_compound_expr (input_location,
                                             super_expr_list, super_expr);
                                             super_expr_list, super_expr);
 
 
      return super_expr_list;
      return super_expr_list;
    }
    }
  else
  else
    {
    {
      error ("[super ...] must appear in a method context");
      error ("[super ...] must appear in a method context");
      return error_mark_node;
      return error_mark_node;
    }
    }
}
}
 
 
/* When exiting a scope, sever links to a 'super' declaration (if any)
/* When exiting a scope, sever links to a 'super' declaration (if any)
   therein contained.  */
   therein contained.  */
 
 
void
void
objc_clear_super_receiver (void)
objc_clear_super_receiver (void)
{
{
  if (objc_method_context
  if (objc_method_context
      && UOBJC_SUPER_scope == objc_get_current_scope ()) {
      && UOBJC_SUPER_scope == objc_get_current_scope ()) {
    UOBJC_SUPER_decl = 0;
    UOBJC_SUPER_decl = 0;
    UOBJC_SUPER_scope = 0;
    UOBJC_SUPER_scope = 0;
  }
  }
}
}
 
 
void
void
objc_finish_method_definition (tree fndecl)
objc_finish_method_definition (tree fndecl)
{
{
  /* We cannot validly inline ObjC methods, at least not without a language
  /* We cannot validly inline ObjC methods, at least not without a language
     extension to declare that a method need not be dynamically
     extension to declare that a method need not be dynamically
     dispatched, so suppress all thoughts of doing so.  */
     dispatched, so suppress all thoughts of doing so.  */
  DECL_UNINLINABLE (fndecl) = 1;
  DECL_UNINLINABLE (fndecl) = 1;
 
 
#ifndef OBJCPLUS
#ifndef OBJCPLUS
  /* The C++ front-end will have called finish_function() for us.  */
  /* The C++ front-end will have called finish_function() for us.  */
  finish_function ();
  finish_function ();
#endif
#endif
 
 
  METHOD_ENCODING (objc_method_context)
  METHOD_ENCODING (objc_method_context)
    = encode_method_prototype (objc_method_context);
    = encode_method_prototype (objc_method_context);
 
 
  /* Required to implement _msgSuper. This must be done AFTER finish_function,
  /* Required to implement _msgSuper. This must be done AFTER finish_function,
     since the optimizer may find "may be used before set" errors.  */
     since the optimizer may find "may be used before set" errors.  */
  objc_method_context = NULL_TREE;
  objc_method_context = NULL_TREE;
 
 
  if (should_call_super_dealloc)
  if (should_call_super_dealloc)
    warning (0, "method possibly missing a [super dealloc] call");
    warning (0, "method possibly missing a [super dealloc] call");
}
}
 
 
/* Given a tree DECL node, produce a printable description of it in the given
/* Given a tree DECL node, produce a printable description of it in the given
   buffer, overwriting the buffer.  */
   buffer, overwriting the buffer.  */
 
 
static char *
static char *
gen_declaration (tree decl)
gen_declaration (tree decl)
{
{
  errbuf[0] = '\0';
  errbuf[0] = '\0';
 
 
  if (DECL_P (decl))
  if (DECL_P (decl))
    {
    {
      gen_type_name_0 (TREE_TYPE (decl));
      gen_type_name_0 (TREE_TYPE (decl));
 
 
      if (DECL_NAME (decl))
      if (DECL_NAME (decl))
        {
        {
          if (!POINTER_TYPE_P (TREE_TYPE (decl)))
          if (!POINTER_TYPE_P (TREE_TYPE (decl)))
            strcat (errbuf, " ");
            strcat (errbuf, " ");
 
 
          strcat (errbuf, IDENTIFIER_POINTER (DECL_NAME (decl)));
          strcat (errbuf, IDENTIFIER_POINTER (DECL_NAME (decl)));
        }
        }
 
 
      if (DECL_INITIAL (decl)
      if (DECL_INITIAL (decl)
          && TREE_CODE (DECL_INITIAL (decl)) == INTEGER_CST)
          && TREE_CODE (DECL_INITIAL (decl)) == INTEGER_CST)
        sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC,
        sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC,
                 TREE_INT_CST_LOW (DECL_INITIAL (decl)));
                 TREE_INT_CST_LOW (DECL_INITIAL (decl)));
    }
    }
 
 
  return errbuf;
  return errbuf;
}
}
 
 
/* Given a tree TYPE node, produce a printable description of it in the given
/* Given a tree TYPE node, produce a printable description of it in the given
   buffer, overwriting the buffer.  */
   buffer, overwriting the buffer.  */
 
 
static char *
static char *
gen_type_name_0 (tree type)
gen_type_name_0 (tree type)
{
{
  tree orig = type, proto;
  tree orig = type, proto;
 
 
  if (TYPE_P (type) && TYPE_NAME (type))
  if (TYPE_P (type) && TYPE_NAME (type))
    type = TYPE_NAME (type);
    type = TYPE_NAME (type);
  else if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
  else if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
    {
    {
      tree inner = TREE_TYPE (type);
      tree inner = TREE_TYPE (type);
 
 
      while (TREE_CODE (inner) == ARRAY_TYPE)
      while (TREE_CODE (inner) == ARRAY_TYPE)
        inner = TREE_TYPE (inner);
        inner = TREE_TYPE (inner);
 
 
      gen_type_name_0 (inner);
      gen_type_name_0 (inner);
 
 
      if (!POINTER_TYPE_P (inner))
      if (!POINTER_TYPE_P (inner))
        strcat (errbuf, " ");
        strcat (errbuf, " ");
 
 
      if (POINTER_TYPE_P (type))
      if (POINTER_TYPE_P (type))
        strcat (errbuf, "*");
        strcat (errbuf, "*");
      else
      else
        while (type != inner)
        while (type != inner)
          {
          {
            strcat (errbuf, "[");
            strcat (errbuf, "[");
 
 
            if (TYPE_DOMAIN (type))
            if (TYPE_DOMAIN (type))
              {
              {
                char sz[20];
                char sz[20];
 
 
                sprintf (sz, HOST_WIDE_INT_PRINT_DEC,
                sprintf (sz, HOST_WIDE_INT_PRINT_DEC,
                         (TREE_INT_CST_LOW
                         (TREE_INT_CST_LOW
                          (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1));
                          (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1));
                strcat (errbuf, sz);
                strcat (errbuf, sz);
              }
              }
 
 
            strcat (errbuf, "]");
            strcat (errbuf, "]");
            type = TREE_TYPE (type);
            type = TREE_TYPE (type);
          }
          }
 
 
      goto exit_function;
      goto exit_function;
    }
    }
 
 
  if (TREE_CODE (type) == TYPE_DECL && DECL_NAME (type))
  if (TREE_CODE (type) == TYPE_DECL && DECL_NAME (type))
    type = DECL_NAME (type);
    type = DECL_NAME (type);
 
 
  strcat (errbuf, TREE_CODE (type) == IDENTIFIER_NODE
  strcat (errbuf, TREE_CODE (type) == IDENTIFIER_NODE
                  ? IDENTIFIER_POINTER (type)
                  ? IDENTIFIER_POINTER (type)
                  : "");
                  : "");
 
 
  /* For 'id' and 'Class', adopted protocols are stored in the pointee.  */
  /* For 'id' and 'Class', adopted protocols are stored in the pointee.  */
  if (objc_is_id (orig))
  if (objc_is_id (orig))
    orig = TREE_TYPE (orig);
    orig = TREE_TYPE (orig);
 
 
  proto = TYPE_HAS_OBJC_INFO (orig) ? TYPE_OBJC_PROTOCOL_LIST (orig) : NULL_TREE;
  proto = TYPE_HAS_OBJC_INFO (orig) ? TYPE_OBJC_PROTOCOL_LIST (orig) : NULL_TREE;
 
 
  if (proto)
  if (proto)
    {
    {
      strcat (errbuf, " <");
      strcat (errbuf, " <");
 
 
      while (proto) {
      while (proto) {
        strcat (errbuf,
        strcat (errbuf,
                IDENTIFIER_POINTER (PROTOCOL_NAME (TREE_VALUE (proto))));
                IDENTIFIER_POINTER (PROTOCOL_NAME (TREE_VALUE (proto))));
        proto = TREE_CHAIN (proto);
        proto = TREE_CHAIN (proto);
        strcat (errbuf, proto ? ", " : ">");
        strcat (errbuf, proto ? ", " : ">");
      }
      }
    }
    }
 
 
 exit_function:
 exit_function:
  return errbuf;
  return errbuf;
}
}
 
 
static char *
static char *
gen_type_name (tree type)
gen_type_name (tree type)
{
{
  errbuf[0] = '\0';
  errbuf[0] = '\0';
 
 
  return gen_type_name_0 (type);
  return gen_type_name_0 (type);
}
}
 
 
/* Given a method tree, put a printable description into the given
/* Given a method tree, put a printable description into the given
   buffer (overwriting) and return a pointer to the buffer.  */
   buffer (overwriting) and return a pointer to the buffer.  */
 
 
static char *
static char *
gen_method_decl (tree method)
gen_method_decl (tree method)
{
{
  tree chain;
  tree chain;
 
 
  strcpy (errbuf, "(");  /* NB: Do _not_ call strcat() here.  */
  strcpy (errbuf, "(");  /* NB: Do _not_ call strcat() here.  */
  gen_type_name_0 (TREE_VALUE (TREE_TYPE (method)));
  gen_type_name_0 (TREE_VALUE (TREE_TYPE (method)));
  strcat (errbuf, ")");
  strcat (errbuf, ")");
  chain = METHOD_SEL_ARGS (method);
  chain = METHOD_SEL_ARGS (method);
 
 
  if (chain)
  if (chain)
    {
    {
      /* We have a chain of keyword_decls.  */
      /* We have a chain of keyword_decls.  */
      do
      do
        {
        {
          if (KEYWORD_KEY_NAME (chain))
          if (KEYWORD_KEY_NAME (chain))
            strcat (errbuf, IDENTIFIER_POINTER (KEYWORD_KEY_NAME (chain)));
            strcat (errbuf, IDENTIFIER_POINTER (KEYWORD_KEY_NAME (chain)));
 
 
          strcat (errbuf, ":(");
          strcat (errbuf, ":(");
          gen_type_name_0 (TREE_VALUE (TREE_TYPE (chain)));
          gen_type_name_0 (TREE_VALUE (TREE_TYPE (chain)));
          strcat (errbuf, ")");
          strcat (errbuf, ")");
 
 
          strcat (errbuf, IDENTIFIER_POINTER (KEYWORD_ARG_NAME (chain)));
          strcat (errbuf, IDENTIFIER_POINTER (KEYWORD_ARG_NAME (chain)));
          if ((chain = TREE_CHAIN (chain)))
          if ((chain = TREE_CHAIN (chain)))
            strcat (errbuf, " ");
            strcat (errbuf, " ");
        }
        }
      while (chain);
      while (chain);
 
 
      if (METHOD_ADD_ARGS (method))
      if (METHOD_ADD_ARGS (method))
        {
        {
          chain = TREE_CHAIN (METHOD_ADD_ARGS (method));
          chain = TREE_CHAIN (METHOD_ADD_ARGS (method));
 
 
          /* Know we have a chain of parm_decls.  */
          /* Know we have a chain of parm_decls.  */
          while (chain)
          while (chain)
            {
            {
              strcat (errbuf, ", ");
              strcat (errbuf, ", ");
              gen_type_name_0 (TREE_TYPE (TREE_VALUE (chain)));
              gen_type_name_0 (TREE_TYPE (TREE_VALUE (chain)));
              chain = TREE_CHAIN (chain);
              chain = TREE_CHAIN (chain);
            }
            }
 
 
          if (METHOD_ADD_ARGS_ELLIPSIS_P (method))
          if (METHOD_ADD_ARGS_ELLIPSIS_P (method))
            strcat (errbuf, ", ...");
            strcat (errbuf, ", ...");
        }
        }
    }
    }
 
 
  else
  else
    /* We have a unary selector.  */
    /* We have a unary selector.  */
    strcat (errbuf, IDENTIFIER_POINTER (METHOD_SEL_NAME (method)));
    strcat (errbuf, IDENTIFIER_POINTER (METHOD_SEL_NAME (method)));
 
 
  return errbuf;
  return errbuf;
}
}


/* Debug info.  */
/* Debug info.  */
 
 
 
 
/* Dump an @interface declaration of the supplied class CHAIN to the
/* Dump an @interface declaration of the supplied class CHAIN to the
   supplied file FP.  Used to implement the -gen-decls option (which
   supplied file FP.  Used to implement the -gen-decls option (which
   prints out an @interface declaration of all classes compiled in
   prints out an @interface declaration of all classes compiled in
   this run); potentially useful for debugging the compiler too.  */
   this run); potentially useful for debugging the compiler too.  */
static void
static void
dump_interface (FILE *fp, tree chain)
dump_interface (FILE *fp, tree chain)
{
{
  /* FIXME: A heap overflow here whenever a method (or ivar)
  /* FIXME: A heap overflow here whenever a method (or ivar)
     declaration is so long that it doesn't fit in the buffer.  The
     declaration is so long that it doesn't fit in the buffer.  The
     code and all the related functions should be rewritten to avoid
     code and all the related functions should be rewritten to avoid
     using fixed size buffers.  */
     using fixed size buffers.  */
  const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain));
  const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain));
  tree ivar_decls = CLASS_RAW_IVARS (chain);
  tree ivar_decls = CLASS_RAW_IVARS (chain);
  tree nst_methods = CLASS_NST_METHODS (chain);
  tree nst_methods = CLASS_NST_METHODS (chain);
  tree cls_methods = CLASS_CLS_METHODS (chain);
  tree cls_methods = CLASS_CLS_METHODS (chain);
 
 
  fprintf (fp, "\n@interface %s", my_name);
  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.  */
     classes, and the category name for categories.  */
  if (CLASS_SUPER_NAME (chain))
  if (CLASS_SUPER_NAME (chain))
    {
    {
      const char *name = IDENTIFIER_POINTER (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)
          || TREE_CODE (chain) == CATEGORY_INTERFACE_TYPE)
        {
        {
          fprintf (fp, " (%s)\n", name);
          fprintf (fp, " (%s)\n", name);
        }
        }
      else
      else
        {
        {
          fprintf (fp, " : %s\n", name);
          fprintf (fp, " : %s\n", name);
        }
        }
    }
    }
  else
  else
    fprintf (fp, "\n");
    fprintf (fp, "\n");
 
 
  /* FIXME - the following doesn't seem to work at the moment.  */
  /* FIXME - the following doesn't seem to work at the moment.  */
  if (ivar_decls)
  if (ivar_decls)
    {
    {
      fprintf (fp, "{\n");
      fprintf (fp, "{\n");
      do
      do
        {
        {
          fprintf (fp, "\t%s;\n", gen_declaration (ivar_decls));
          fprintf (fp, "\t%s;\n", gen_declaration (ivar_decls));
          ivar_decls = TREE_CHAIN (ivar_decls);
          ivar_decls = TREE_CHAIN (ivar_decls);
        }
        }
      while (ivar_decls);
      while (ivar_decls);
      fprintf (fp, "}\n");
      fprintf (fp, "}\n");
    }
    }
 
 
  while (nst_methods)
  while (nst_methods)
    {
    {
      fprintf (fp, "- %s;\n", gen_method_decl (nst_methods));
      fprintf (fp, "- %s;\n", gen_method_decl (nst_methods));
      nst_methods = TREE_CHAIN (nst_methods);
      nst_methods = TREE_CHAIN (nst_methods);
    }
    }
 
 
  while (cls_methods)
  while (cls_methods)
    {
    {
      fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods));
      fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods));
      cls_methods = TREE_CHAIN (cls_methods);
      cls_methods = TREE_CHAIN (cls_methods);
    }
    }
 
 
  fprintf (fp, "@end\n");
  fprintf (fp, "@end\n");
}
}
 
 
/* Demangle function for Objective-C */
/* Demangle function for Objective-C */
static const char *
static const char *
objc_demangle (const char *mangled)
objc_demangle (const char *mangled)
{
{
  char *demangled, *cp;
  char *demangled, *cp;
 
 
  if (mangled[0] == '_' &&
  if (mangled[0] == '_' &&
      (mangled[1] == 'i' || mangled[1] == 'c') &&
      (mangled[1] == 'i' || mangled[1] == 'c') &&
      mangled[2] == '_')
      mangled[2] == '_')
    {
    {
      cp = demangled = XNEWVEC (char, strlen(mangled) + 2);
      cp = demangled = XNEWVEC (char, strlen(mangled) + 2);
      if (mangled[1] == 'i')
      if (mangled[1] == 'i')
        *cp++ = '-';            /* for instance method */
        *cp++ = '-';            /* for instance method */
      else
      else
        *cp++ = '+';            /* for class method */
        *cp++ = '+';            /* for class method */
      *cp++ = '[';              /* opening left brace */
      *cp++ = '[';              /* opening left brace */
      strcpy(cp, mangled+3);    /* tack on the rest of the mangled name */
      strcpy(cp, mangled+3);    /* tack on the rest of the mangled name */
      while (*cp && *cp == '_')
      while (*cp && *cp == '_')
        cp++;                   /* skip any initial underbars in class name */
        cp++;                   /* skip any initial underbars in class name */
      cp = strchr(cp, '_');     /* find first non-initial underbar */
      cp = strchr(cp, '_');     /* find first non-initial underbar */
      if (cp == NULL)
      if (cp == NULL)
        {
        {
          free(demangled);      /* not mangled name */
          free(demangled);      /* not mangled name */
          return mangled;
          return mangled;
        }
        }
      if (cp[1] == '_')  /* easy case: no category name */
      if (cp[1] == '_')  /* easy case: no category name */
        {
        {
          *cp++ = ' ';            /* replace two '_' with one ' ' */
          *cp++ = ' ';            /* replace two '_' with one ' ' */
          strcpy(cp, mangled + (cp - demangled) + 2);
          strcpy(cp, mangled + (cp - demangled) + 2);
        }
        }
      else
      else
        {
        {
          *cp++ = '(';            /* less easy case: category name */
          *cp++ = '(';            /* less easy case: category name */
          cp = strchr(cp, '_');
          cp = strchr(cp, '_');
          if (cp == 0)
          if (cp == 0)
            {
            {
              free(demangled);    /* not mangled name */
              free(demangled);    /* not mangled name */
              return mangled;
              return mangled;
            }
            }
          *cp++ = ')';
          *cp++ = ')';
          *cp++ = ' ';            /* overwriting 1st char of method name... */
          *cp++ = ' ';            /* overwriting 1st char of method name... */
          strcpy(cp, mangled + (cp - demangled)); /* get it back */
          strcpy(cp, mangled + (cp - demangled)); /* get it back */
        }
        }
      while (*cp && *cp == '_')
      while (*cp && *cp == '_')
        cp++;                   /* skip any initial underbars in method name */
        cp++;                   /* skip any initial underbars in method name */
      for (; *cp; cp++)
      for (; *cp; cp++)
        if (*cp == '_')
        if (*cp == '_')
          *cp = ':';            /* replace remaining '_' with ':' */
          *cp = ':';            /* replace remaining '_' with ':' */
      *cp++ = ']';              /* closing right brace */
      *cp++ = ']';              /* closing right brace */
      *cp++ = 0;                /* string terminator */
      *cp++ = 0;                /* string terminator */
      return demangled;
      return demangled;
    }
    }
  else
  else
    return mangled;             /* not an objc mangled name */
    return mangled;             /* not an objc mangled name */
}
}
 
 
const char *
const char *
objc_printable_name (tree decl, int kind ATTRIBUTE_UNUSED)
objc_printable_name (tree decl, int kind ATTRIBUTE_UNUSED)
{
{
  return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)));
  return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)));
}
}
 
 
static void
static void
init_objc (void)
init_objc (void)
{
{
  gcc_obstack_init (&util_obstack);
  gcc_obstack_init (&util_obstack);
  util_firstobj = (char *) obstack_finish (&util_obstack);
  util_firstobj = (char *) obstack_finish (&util_obstack);
 
 
  errbuf = XNEWVEC (char, 1024 * 10);
  errbuf = XNEWVEC (char, 1024 * 10);
  hash_init ();
  hash_init ();
  synth_module_prologue ();
  synth_module_prologue ();
}
}


static void
static void
finish_objc (void)
finish_objc (void)
{
{
  struct imp_entry *impent;
  struct imp_entry *impent;
  tree chain;
  tree chain;
  /* The internally generated initializers appear to have missing braces.
  /* The internally generated initializers appear to have missing braces.
     Don't warn about this.  */
     Don't warn about this.  */
  int save_warn_missing_braces = warn_missing_braces;
  int save_warn_missing_braces = warn_missing_braces;
  warn_missing_braces = 0;
  warn_missing_braces = 0;
 
 
  /* A missing @end may not be detected by the parser.  */
  /* A missing @end may not be detected by the parser.  */
  if (objc_implementation_context)
  if (objc_implementation_context)
    {
    {
      warning (0, "%<@end%> missing in implementation context");
      warning (0, "%<@end%> missing in implementation context");
      finish_class (objc_implementation_context);
      finish_class (objc_implementation_context);
      objc_ivar_chain = NULL_TREE;
      objc_ivar_chain = NULL_TREE;
      objc_implementation_context = NULL_TREE;
      objc_implementation_context = NULL_TREE;
    }
    }
 
 
  /* Process the static instances here because initialization of objc_symtab
  /* Process the static instances here because initialization of objc_symtab
     depends on them.  */
     depends on them.  */
  if (objc_static_instances)
  if (objc_static_instances)
    generate_static_references ();
    generate_static_references ();
 
 
  if (imp_list || class_names_chain
  if (imp_list || class_names_chain
      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
    generate_objc_symtab_decl ();
    generate_objc_symtab_decl ();
 
 
  for (impent = imp_list; impent; impent = impent->next)
  for (impent = imp_list; impent; impent = impent->next)
    {
    {
      objc_implementation_context = impent->imp_context;
      objc_implementation_context = impent->imp_context;
      implementation_template = impent->imp_template;
      implementation_template = impent->imp_template;
 
 
      UOBJC_CLASS_decl = impent->class_decl;
      UOBJC_CLASS_decl = impent->class_decl;
      UOBJC_METACLASS_decl = impent->meta_decl;
      UOBJC_METACLASS_decl = impent->meta_decl;
 
 
      /* Dump the @interface of each class as we compile it, if the
      /* Dump the @interface of each class as we compile it, if the
         -gen-decls option is in use.  TODO: Dump the classes in the
         -gen-decls option is in use.  TODO: Dump the classes in the
         order they were found, rather than in reverse order as we
         order they were found, rather than in reverse order as we
         are doing now.  */
         are doing now.  */
      if (flag_gen_declaration)
      if (flag_gen_declaration)
        {
        {
          dump_interface (gen_declaration_file, objc_implementation_context);
          dump_interface (gen_declaration_file, objc_implementation_context);
        }
        }
 
 
      if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
      if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
        {
        {
          /* all of the following reference the string pool...  */
          /* all of the following reference the string pool...  */
          generate_ivar_lists ();
          generate_ivar_lists ();
          generate_dispatch_tables ();
          generate_dispatch_tables ();
          generate_shared_structures (impent->has_cxx_cdtors
          generate_shared_structures (impent->has_cxx_cdtors
                                      ? CLS_HAS_CXX_STRUCTORS
                                      ? CLS_HAS_CXX_STRUCTORS
                                      : 0);
                                      : 0);
        }
        }
      else
      else
        {
        {
          generate_dispatch_tables ();
          generate_dispatch_tables ();
          generate_category (objc_implementation_context);
          generate_category (objc_implementation_context);
        }
        }
    }
    }
 
 
  /* If we are using an array of selectors, we must always
  /* If we are using an array of selectors, we must always
     finish up the array decl even if no selectors were used.  */
     finish up the array decl even if no selectors were used.  */
  if (! flag_next_runtime || sel_ref_chain)
  if (! flag_next_runtime || sel_ref_chain)
    build_selector_translation_table ();
    build_selector_translation_table ();
 
 
  if (protocol_chain)
  if (protocol_chain)
    generate_protocols ();
    generate_protocols ();
 
 
  if ((flag_replace_objc_classes && imp_list) || flag_objc_gc)
  if ((flag_replace_objc_classes && imp_list) || flag_objc_gc)
    generate_objc_image_info ();
    generate_objc_image_info ();
 
 
  /* Arrange for ObjC data structures to be initialized at run time.  */
  /* Arrange for ObjC data structures to be initialized at run time.  */
  if (objc_implementation_context || class_names_chain || objc_static_instances
  if (objc_implementation_context || class_names_chain || objc_static_instances
      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
    {
    {
      build_module_descriptor ();
      build_module_descriptor ();
 
 
      if (!flag_next_runtime)
      if (!flag_next_runtime)
        build_module_initializer_routine ();
        build_module_initializer_routine ();
    }
    }
 
 
  /* Dump the class references.  This forces the appropriate classes
  /* Dump the class references.  This forces the appropriate classes
     to be linked into the executable image, preserving unix archive
     to be linked into the executable image, preserving unix archive
     semantics.  This can be removed when we move to a more dynamically
     semantics.  This can be removed when we move to a more dynamically
     linked environment.  */
     linked environment.  */
 
 
  for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
  for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
    {
    {
      handle_class_ref (chain);
      handle_class_ref (chain);
      if (TREE_PURPOSE (chain))
      if (TREE_PURPOSE (chain))
        generate_classref_translation_entry (chain);
        generate_classref_translation_entry (chain);
    }
    }
 
 
  for (impent = imp_list; impent; impent = impent->next)
  for (impent = imp_list; impent; impent = impent->next)
    handle_impent (impent);
    handle_impent (impent);
 
 
  if (warn_selector)
  if (warn_selector)
    {
    {
      int slot;
      int slot;
      hash hsh;
      hash hsh;
 
 
      /* Run through the selector hash tables and print a warning for any
      /* Run through the selector hash tables and print a warning for any
         selector which has multiple methods.  */
         selector which has multiple methods.  */
 
 
      for (slot = 0; slot < SIZEHASHTABLE; slot++)
      for (slot = 0; slot < SIZEHASHTABLE; slot++)
        {
        {
          for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
          for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
            check_duplicates (hsh, 0, 1);
            check_duplicates (hsh, 0, 1);
          for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
          for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
            check_duplicates (hsh, 0, 1);
            check_duplicates (hsh, 0, 1);
        }
        }
    }
    }
 
 
  warn_missing_braces = save_warn_missing_braces;
  warn_missing_braces = save_warn_missing_braces;
}
}


/* Subroutines of finish_objc.  */
/* Subroutines of finish_objc.  */
 
 
static void
static void
generate_classref_translation_entry (tree chain)
generate_classref_translation_entry (tree chain)
{
{
  tree expr, decl, type;
  tree expr, decl, type;
 
 
  decl = TREE_PURPOSE (chain);
  decl = TREE_PURPOSE (chain);
  type = TREE_TYPE (decl);
  type = TREE_TYPE (decl);
 
 
  expr = add_objc_string (TREE_VALUE (chain), class_names);
  expr = add_objc_string (TREE_VALUE (chain), class_names);
  expr = convert (type, expr); /* cast! */
  expr = convert (type, expr); /* cast! */
 
 
  /* The decl that is the one that we
  /* The decl that is the one that we
     forward declared in build_class_reference.  */
     forward declared in build_class_reference.  */
  finish_var_decl (decl, expr);
  finish_var_decl (decl, expr);
  return;
  return;
}
}
 
 
static void
static void
handle_class_ref (tree chain)
handle_class_ref (tree chain)
{
{
  const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain));
  const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain));
  char *string = (char *) alloca (strlen (name) + 30);
  char *string = (char *) alloca (strlen (name) + 30);
  tree decl;
  tree decl;
  tree exp;
  tree exp;
 
 
  sprintf (string, "%sobjc_class_name_%s",
  sprintf (string, "%sobjc_class_name_%s",
           (flag_next_runtime ? "." : "__"), name);
           (flag_next_runtime ? "." : "__"), name);
 
 
#ifdef ASM_DECLARE_UNRESOLVED_REFERENCE
#ifdef ASM_DECLARE_UNRESOLVED_REFERENCE
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      ASM_DECLARE_UNRESOLVED_REFERENCE (asm_out_file, string);
      ASM_DECLARE_UNRESOLVED_REFERENCE (asm_out_file, string);
      return;
      return;
    }
    }
#endif
#endif
 
 
  /* Make a decl for this name, so we can use its address in a tree.  */
  /* Make a decl for this name, so we can use its address in a tree.  */
  decl = build_decl (input_location,
  decl = build_decl (input_location,
                     VAR_DECL, get_identifier (string), char_type_node);
                     VAR_DECL, get_identifier (string), char_type_node);
  DECL_EXTERNAL (decl) = 1;
  DECL_EXTERNAL (decl) = 1;
  TREE_PUBLIC (decl) = 1;
  TREE_PUBLIC (decl) = 1;
 
 
  pushdecl (decl);
  pushdecl (decl);
  rest_of_decl_compilation (decl, 0, 0);
  rest_of_decl_compilation (decl, 0, 0);
 
 
  /* Make a decl for the address.  */
  /* Make a decl for the address.  */
  sprintf (string, "%sobjc_class_ref_%s",
  sprintf (string, "%sobjc_class_ref_%s",
           (flag_next_runtime ? "." : "__"), name);
           (flag_next_runtime ? "." : "__"), name);
  exp = build1 (ADDR_EXPR, string_type_node, decl);
  exp = build1 (ADDR_EXPR, string_type_node, decl);
  decl = build_decl (input_location,
  decl = build_decl (input_location,
                     VAR_DECL, get_identifier (string), string_type_node);
                     VAR_DECL, get_identifier (string), string_type_node);
  DECL_INITIAL (decl) = exp;
  DECL_INITIAL (decl) = exp;
  TREE_STATIC (decl) = 1;
  TREE_STATIC (decl) = 1;
  TREE_USED (decl) = 1;
  TREE_USED (decl) = 1;
  /* Force the output of the decl as this forces the reference of the class.  */
  /* Force the output of the decl as this forces the reference of the class.  */
  mark_decl_referenced (decl);
  mark_decl_referenced (decl);
 
 
  pushdecl (decl);
  pushdecl (decl);
  rest_of_decl_compilation (decl, 0, 0);
  rest_of_decl_compilation (decl, 0, 0);
}
}
 
 
static void
static void
handle_impent (struct imp_entry *impent)
handle_impent (struct imp_entry *impent)
{
{
  char *string;
  char *string;
 
 
  objc_implementation_context = impent->imp_context;
  objc_implementation_context = impent->imp_context;
  implementation_template = impent->imp_template;
  implementation_template = impent->imp_template;
 
 
  if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE)
  if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE)
    {
    {
      const char *const class_name =
      const char *const class_name =
        IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context));
        IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context));
 
 
      string = (char *) alloca (strlen (class_name) + 30);
      string = (char *) alloca (strlen (class_name) + 30);
 
 
      sprintf (string, "%sobjc_class_name_%s",
      sprintf (string, "%sobjc_class_name_%s",
               (flag_next_runtime ? "." : "__"), class_name);
               (flag_next_runtime ? "." : "__"), class_name);
    }
    }
  else if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
  else if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
    {
    {
      const char *const class_name =
      const char *const class_name =
        IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context));
        IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context));
      const char *const class_super_name =
      const char *const class_super_name =
        IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context));
        IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context));
 
 
      string = (char *) alloca (strlen (class_name)
      string = (char *) alloca (strlen (class_name)
                                + strlen (class_super_name) + 30);
                                + strlen (class_super_name) + 30);
 
 
      /* Do the same for categories.  Even though no references to
      /* Do the same for categories.  Even though no references to
         these symbols are generated automatically by the compiler, it
         these symbols are generated automatically by the compiler, it
         gives you a handle to pull them into an archive by hand.  */
         gives you a handle to pull them into an archive by hand.  */
      sprintf (string, "*%sobjc_category_name_%s_%s",
      sprintf (string, "*%sobjc_category_name_%s_%s",
               (flag_next_runtime ? "." : "__"), class_name, class_super_name);
               (flag_next_runtime ? "." : "__"), class_name, class_super_name);
    }
    }
  else
  else
    return;
    return;
 
 
#ifdef ASM_DECLARE_CLASS_REFERENCE
#ifdef ASM_DECLARE_CLASS_REFERENCE
  if (flag_next_runtime)
  if (flag_next_runtime)
    {
    {
      ASM_DECLARE_CLASS_REFERENCE (asm_out_file, string);
      ASM_DECLARE_CLASS_REFERENCE (asm_out_file, string);
      return;
      return;
    }
    }
  else
  else
#endif
#endif
    {
    {
      tree decl, init;
      tree decl, init;
 
 
      init = build_int_cst (c_common_type_for_size (BITS_PER_WORD, 1), 0);
      init = build_int_cst (c_common_type_for_size (BITS_PER_WORD, 1), 0);
      decl = build_decl (input_location,
      decl = build_decl (input_location,
                         VAR_DECL, get_identifier (string), TREE_TYPE (init));
                         VAR_DECL, get_identifier (string), TREE_TYPE (init));
      TREE_PUBLIC (decl) = 1;
      TREE_PUBLIC (decl) = 1;
      TREE_READONLY (decl) = 1;
      TREE_READONLY (decl) = 1;
      TREE_USED (decl) = 1;
      TREE_USED (decl) = 1;
      TREE_CONSTANT (decl) = 1;
      TREE_CONSTANT (decl) = 1;
      DECL_CONTEXT (decl) = 0;
      DECL_CONTEXT (decl) = 0;
      DECL_ARTIFICIAL (decl) = 1;
      DECL_ARTIFICIAL (decl) = 1;
      DECL_INITIAL (decl) = init;
      DECL_INITIAL (decl) = init;
      assemble_variable (decl, 1, 0, 0);
      assemble_variable (decl, 1, 0, 0);
    }
    }
}
}


/* The Fix-and-Continue functionality available in Mac OS X 10.3 and
/* The Fix-and-Continue functionality available in Mac OS X 10.3 and
   later requires that ObjC translation units participating in F&C be
   later requires that ObjC translation units participating in F&C be
   specially marked.  The following routine accomplishes this.  */
   specially marked.  The following routine accomplishes this.  */
 
 
/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */
/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */
 
 
static void
static void
generate_objc_image_info (void)
generate_objc_image_info (void)
{
{
  tree decl, initlist;
  tree decl, initlist;
  int flags
  int flags
    = ((flag_replace_objc_classes && imp_list ? 1 : 0)
    = ((flag_replace_objc_classes && imp_list ? 1 : 0)
       | (flag_objc_gc ? 2 : 0));
       | (flag_objc_gc ? 2 : 0));
 
 
  decl = start_var_decl (build_array_type
  decl = start_var_decl (build_array_type
                         (integer_type_node,
                         (integer_type_node,
                          build_index_type (build_int_cst (NULL_TREE, 2 - 1))),
                          build_index_type (build_int_cst (NULL_TREE, 2 - 1))),
                         "_OBJC_IMAGE_INFO");
                         "_OBJC_IMAGE_INFO");
 
 
  initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
  initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, flags), initlist);
  initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, flags), initlist);
  initlist = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist));
  initlist = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist));
 
 
  finish_var_decl (decl, initlist);
  finish_var_decl (decl, initlist);
}
}
 
 
/* Look up ID as an instance variable.  OTHER contains the result of
/* Look up ID as an instance variable.  OTHER contains the result of
   the C or C++ lookup, which we may want to use instead.  */
   the C or C++ lookup, which we may want to use instead.  */
 
 
tree
tree
objc_lookup_ivar (tree other, tree id)
objc_lookup_ivar (tree other, tree id)
{
{
  tree ivar;
  tree ivar;
 
 
  /* If we are not inside of an ObjC method, ivar lookup makes no sense.  */
  /* If we are not inside of an ObjC method, ivar lookup makes no sense.  */
  if (!objc_method_context)
  if (!objc_method_context)
    return other;
    return other;
 
 
  if (!strcmp (IDENTIFIER_POINTER (id), "super"))
  if (!strcmp (IDENTIFIER_POINTER (id), "super"))
    /* We have a message to super.  */
    /* We have a message to super.  */
    return get_super_receiver ();
    return get_super_receiver ();
 
 
  /* In a class method, look up an instance variable only as a last
  /* In a class method, look up an instance variable only as a last
     resort.  */
     resort.  */
  if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL
  if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL
      && other && other != error_mark_node)
      && other && other != error_mark_node)
    return other;
    return other;
 
 
  /* Look up the ivar, but do not use it if it is not accessible.  */
  /* Look up the ivar, but do not use it if it is not accessible.  */
  ivar = is_ivar (objc_ivar_chain, id);
  ivar = is_ivar (objc_ivar_chain, id);
 
 
  if (!ivar || is_private (ivar))
  if (!ivar || is_private (ivar))
    return other;
    return other;
 
 
  /* In an instance method, a local variable (or parameter) may hide the
  /* In an instance method, a local variable (or parameter) may hide the
     instance variable.  */
     instance variable.  */
  if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL
  if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL
      && other && other != error_mark_node
      && other && other != error_mark_node
#ifdef OBJCPLUS
#ifdef OBJCPLUS
      && CP_DECL_CONTEXT (other) != global_namespace)
      && CP_DECL_CONTEXT (other) != global_namespace)
#else
#else
      && !DECL_FILE_SCOPE_P (other))
      && !DECL_FILE_SCOPE_P (other))
#endif
#endif
    {
    {
      warning (0, "local declaration of %qE hides instance variable",
      warning (0, "local declaration of %qE hides instance variable",
               id);
               id);
 
 
      return other;
      return other;
    }
    }
 
 
  /* At this point, we are either in an instance method with no obscuring
  /* At this point, we are either in an instance method with no obscuring
     local definitions, or in a class method with no alternate definitions
     local definitions, or in a class method with no alternate definitions
     at all.  */
     at all.  */
  return build_ivar_reference (id);
  return build_ivar_reference (id);
}
}
 
 
/* Possibly rewrite a function CALL into an OBJ_TYPE_REF expression.  This
/* Possibly rewrite a function CALL into an OBJ_TYPE_REF expression.  This
   needs to be done if we are calling a function through a cast.  */
   needs to be done if we are calling a function through a cast.  */
 
 
tree
tree
objc_rewrite_function_call (tree function, tree first_param)
objc_rewrite_function_call (tree function, tree first_param)
{
{
  if (TREE_CODE (function) == NOP_EXPR
  if (TREE_CODE (function) == NOP_EXPR
      && TREE_CODE (TREE_OPERAND (function, 0)) == ADDR_EXPR
      && TREE_CODE (TREE_OPERAND (function, 0)) == ADDR_EXPR
      && TREE_CODE (TREE_OPERAND (TREE_OPERAND (function, 0), 0))
      && TREE_CODE (TREE_OPERAND (TREE_OPERAND (function, 0), 0))
         == FUNCTION_DECL)
         == FUNCTION_DECL)
    {
    {
      function = build3 (OBJ_TYPE_REF, TREE_TYPE (function),
      function = build3 (OBJ_TYPE_REF, TREE_TYPE (function),
                         TREE_OPERAND (function, 0),
                         TREE_OPERAND (function, 0),
                         first_param, size_zero_node);
                         first_param, size_zero_node);
    }
    }
 
 
  return function;
  return function;
}
}
 
 
/* Look for the special case of OBJC_TYPE_REF with the address of
/* Look for the special case of OBJC_TYPE_REF with the address of
   a function in OBJ_TYPE_REF_EXPR (presumably objc_msgSend or one
   a function in OBJ_TYPE_REF_EXPR (presumably objc_msgSend or one
   of its cousins).  */
   of its cousins).  */
 
 
int
int
objc_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
objc_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
{
{
  enum gimplify_status r0, r1;
  enum gimplify_status r0, r1;
  if (TREE_CODE (*expr_p) == OBJ_TYPE_REF
  if (TREE_CODE (*expr_p) == OBJ_TYPE_REF
      && TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR
      && TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR
      && TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0))
      && TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0))
         == FUNCTION_DECL)
         == FUNCTION_DECL)
    {
    {
      /* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the
      /* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the
         value of the OBJ_TYPE_REF, so force them to be emitted
         value of the OBJ_TYPE_REF, so force them to be emitted
         during subexpression evaluation rather than after the
         during subexpression evaluation rather than after the
         OBJ_TYPE_REF. This permits objc_msgSend calls in Objective
         OBJ_TYPE_REF. This permits objc_msgSend calls in Objective
         C to use direct rather than indirect calls when the
         C to use direct rather than indirect calls when the
         object expression has a postincrement.  */
         object expression has a postincrement.  */
      r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL,
      r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL,
                          is_gimple_val, fb_rvalue);
                          is_gimple_val, fb_rvalue);
      r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
      r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
                          is_gimple_val, fb_rvalue);
                          is_gimple_val, fb_rvalue);
 
 
      return MIN (r0, r1);
      return MIN (r0, r1);
    }
    }
 
 
#ifdef OBJCPLUS
#ifdef OBJCPLUS
  return (enum gimplify_status) cp_gimplify_expr (expr_p, pre_p, post_p);
  return (enum gimplify_status) cp_gimplify_expr (expr_p, pre_p, post_p);
#else
#else
  return (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p);
  return (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p);
#endif
#endif
}
}
 
 
#include "gt-objc-objc-act.h"
#include "gt-objc-objc-act.h"
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.