X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fobjc%2Fobjc-act.c;h=d4624bb5439d2635aa38c9b3d868ac081c08fbae;hb=f352a3fbf2100b1b9954e0132b6e5b9644956c56;hp=408f25709a41827fd8bd7d3918e0644cbe0255c8;hpb=02fc645a90d105c647fa1c0a854b4a453fac45b3;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 408f25709a4..d4624bb5439 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1,13 +1,13 @@ /* Implement classes and message passing for Objective C. - Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Steve Naroff. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, @@ -16,9 +16,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ + /* Purpose: This module implements the Objective-C 4.0 language. @@ -55,6 +55,7 @@ Boston, MA 02111-1307, USA. */ #endif #include "c-common.h" +#include "c-pragma.h" #include "flags.h" #include "langhooks.h" #include "objc-act.h" @@ -68,13 +69,22 @@ Boston, MA 02111-1307, USA. */ #include "debug.h" #include "target.h" #include "diagnostic.h" +#include "intl.h" #include "cgraph.h" #include "tree-iterator.h" #include "libfuncs.h" #include "hashtab.h" +#include "langhooks-def.h" #define OBJC_VOID_AT_END void_list_node +static unsigned int should_call_super_dealloc = 0; + +/* When building Objective-C++, we need in_late_binary_op. */ +#ifdef OBJCPLUS +bool in_late_binary_op = false; +#endif /* OBJCPLUS */ + /* 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. */ #ifdef OBJCPLUS @@ -124,7 +134,7 @@ char *util_firstobj; the module (file) was compiled for, and is recorded in the module descriptor. */ -#define OBJC_VERSION (flag_next_runtime ? 5 : 8) +#define OBJC_VERSION (flag_next_runtime ? 6 : 8) #define PROTOCOL_VERSION 2 /* (Decide if these can ever be validly changed.) */ @@ -140,15 +150,9 @@ static void finish_objc (void); /* Code generation. */ -static void synth_module_prologue (void); static tree objc_build_constructor (tree, tree); -static void build_module_descriptor (void); -static void build_module_initializer_routine (void); -static tree init_module_descriptor (tree); static tree build_objc_method_call (int, tree, tree, tree, tree); -static void generate_strings (void); static tree get_proto_encoding (tree); -static void build_selector_translation_table (void); static tree lookup_interface (tree); static tree objc_add_static_instance (tree, tree); @@ -162,60 +166,46 @@ static void objc_start_function (tree, tree, tree, tree); static void objc_start_function (tree, tree, tree, struct c_arg_info *); #endif static tree start_protocol (enum tree_code, tree, tree); -static tree build_method_decl (enum tree_code, tree, tree, tree); +static tree build_method_decl (enum tree_code, tree, tree, tree, bool); static tree objc_add_method (tree, tree, int); static tree add_instance_variable (tree, int, tree); static tree build_ivar_reference (tree); static tree is_ivar (tree, tree); -static int is_private (tree); -static tree get_super_receiver (void); static void build_objc_exception_stuff (void); static void build_next_objc_exception_stuff (void); -static tree build_ivar_template (void); -static tree build_method_template (void); -static tree build_private_template (tree); +/* We only need the following for ObjC; ObjC++ will use C++'s definition + of DERIVED_FROM_P. */ +#ifndef OBJCPLUS +static bool objc_derived_from_p (tree, tree); +#define DERIVED_FROM_P(PARENT, CHILD) objc_derived_from_p (PARENT, CHILD) +#endif +static void objc_xref_basetypes (tree, tree); + static void build_class_template (void); static void build_selector_template (void); static void build_category_template (void); -static tree lookup_method_in_hash_lists (tree, int); static void build_super_template (void); -static tree build_category_initializer (tree, tree, tree, tree, tree, tree); static tree build_protocol_initializer (tree, tree, tree, tree, tree); -static void synth_forward_declarations (void); -static int ivar_list_length (tree); -static tree get_class_ivars (tree); -static void generate_ivar_lists (void); -static void generate_dispatch_tables (void); -static void generate_shared_structures (void); +static tree get_class_ivars (tree, bool); static tree generate_protocol_list (tree); static void build_protocol_reference (tree); -static tree build_keyword_selector (tree); -static const char *synth_id_with_class_suffix (const char *, tree); +#ifdef OBJCPLUS +static void objc_generate_cxx_cdtors (void); +#endif -static void generate_static_references (void); -static int check_methods_accessible (tree, tree, int); -static void encode_aggregate_within (tree, int, int, int, int); -static const char *objc_demangle (const char *); +static const char *synth_id_with_class_suffix (const char *, tree); /* Hash tables to manage the global pool of method prototypes. */ hash *nst_method_hash_list = 0; hash *cls_method_hash_list = 0; -static size_t hash_func (tree); -static void hash_init (void); -static void hash_enter (hash *, tree); static hash hash_lookup (hash *, tree); -static void hash_add_attr (hash, tree); static tree lookup_method (tree, tree); static tree lookup_method_static (tree, tree, int); -static void add_method_to_hash_list (hash *, tree); -static tree add_class (tree); -static void add_category (tree, tree); -static inline tree lookup_category (tree, tree); enum string_section { @@ -225,26 +215,17 @@ enum string_section }; static tree add_objc_string (tree, enum string_section); -static tree get_objc_string_decl (tree, enum string_section); static tree build_objc_string_decl (enum string_section); -static tree build_selector_reference_decl (void); static void build_selector_table_decl (void); /* Protocol additions. */ -static tree add_protocol (tree); static tree lookup_protocol (tree); -static void check_protocol_recursively (tree, tree); static tree lookup_and_install_protocols (tree); /* Type encoding. */ static void encode_type_qualifiers (tree); -static void encode_pointer (tree, int, int); -static void encode_array (tree, int, int); -static void encode_aggregate (tree, int, int); -static void encode_next_bitfield (int); -static void encode_gnu_bitfield (int, tree, int); static void encode_type (tree, int, int); static void encode_field_decl (tree, int, int); @@ -253,76 +234,27 @@ static void really_start_method (tree, tree); #else static void really_start_method (tree, struct c_arg_info *); #endif -static int objc_types_are_equivalent (tree, tree); -static int comp_proto_with_proto (tree, tree); -static tree get_arg_type_list (tree, int, int); +static int comp_proto_with_proto (tree, tree, int); static void objc_push_parm (tree); #ifdef OBJCPLUS static tree objc_get_parm_info (int); #else static struct c_arg_info *objc_get_parm_info (int); #endif -static void synth_self_and_ucmd_args (void); /* Utilities for debugging and error diagnostics. */ -static void warn_with_method (const char *, int, tree); -static void error_with_ivar (const char *, tree); static char *gen_type_name (tree); static char *gen_type_name_0 (tree); static char *gen_method_decl (tree); static char *gen_declaration (tree); -static void dump_interface (FILE *, tree); /* Everything else. */ -static tree lookup_method_in_protocol_list (tree, tree, int); -static tree lookup_protocol_in_reflist (tree, tree); -static tree start_var_decl (tree, const char *); -static void finish_var_decl (tree, tree); static tree create_field_decl (tree, const char *); -static tree setup_string_decl (void); -static int check_string_class_template (void); -static tree my_build_string (int, const char *); -static void build_objc_symtab_template (void); -static tree init_def_list (tree); -static tree init_objc_symtab (tree); -static tree build_metadata_decl (const char *, tree); -static void forward_declare_categories (void); -static void generate_objc_symtab_decl (void); -static tree build_selector (tree); -static tree build_typed_selector_reference (tree, tree); -static tree build_selector_reference (tree); -static tree build_class_reference_decl (void); static void add_class_reference (tree); static void build_protocol_template (void); -static tree build_descriptor_table_initializer (tree, tree); -static tree build_method_prototype_list_template (tree, int); -static tree build_method_prototype_template (void); -static tree objc_method_parm_type (tree); -static int objc_encoded_type_size (tree); static tree encode_method_prototype (tree); -static tree generate_descriptor_table (tree, const char *, int, tree, tree); -static void generate_method_descriptors (tree); -static void generate_protocol_references (tree); -static void generate_protocols (void); -static void check_ivars (tree, tree); -static tree build_ivar_list_template (tree, int); -static tree build_method_list_template (tree, int); -static tree build_ivar_list_initializer (tree, tree); -static tree generate_ivars_list (tree, const char *, int, tree); -static tree build_dispatch_table_initializer (tree, tree); -static tree generate_dispatch_table (tree, const char *, int, tree); -static tree build_shared_structure_initializer (tree, tree, tree, tree, - tree, int, tree, tree, tree); -static void generate_category (tree); -static tree adjust_type_for_id_default (tree); -static tree check_duplicates (hash, int, int); -static tree receiver_is_class_object (tree, int, int); -static int check_methods (tree, tree, int); -static int conforms_to_protocol (tree, tree); -static void check_protocol (tree, const char *, const char *); -static void check_protocols (tree, const char *, const char *); static void generate_classref_translation_entry (tree); static void handle_class_ref (tree); static void generate_struct_by_value_array (void) @@ -376,6 +308,7 @@ static const char *default_constant_string_class_name; /* Runtime metadata flags. */ #define CLS_FACTORY 0x0001L #define CLS_META 0x0002L +#define CLS_HAS_CXX_STRUCTORS 0x2000L #define OBJC_MODIFIER_STATIC 0x00000001 #define OBJC_MODIFIER_FINAL 0x00000002 @@ -403,11 +336,28 @@ static const char *default_constant_string_class_name; #define TAG_SETJMP "_setjmp" #define UTAG_EXCDATA "_objc_exception_data" +#define TAG_ASSIGNIVAR "objc_assign_ivar" +#define TAG_ASSIGNGLOBAL "objc_assign_global" +#define TAG_ASSIGNSTRONGCAST "objc_assign_strongCast" + +/* Branch entry points. All that matters here are the addresses; + functions with these names do not really exist in libobjc. */ + +#define TAG_MSGSEND_FAST "objc_msgSend_Fast" +#define TAG_ASSIGNIVAR_FAST "objc_assign_ivar_Fast" + +#define TAG_CXX_CONSTRUCT ".cxx_construct" +#define TAG_CXX_DESTRUCT ".cxx_destruct" + /* GNU-specific tags. */ #define TAG_EXECCLASS "__objc_exec_class" #define TAG_GNUINIT "__objc_gnu_init" +/* Flags for lookup_method_static(). */ +#define OBJC_LOOKUP_CLASS 1 /* Look for class methods. */ +#define OBJC_LOOKUP_NO_SUPER 2 /* Do not examine superclasses. */ + /* The OCTI_... enumeration itself is in objc/objc-act.h. */ tree objc_global_trees[OCTI_MAX]; @@ -440,8 +390,7 @@ static int flag_typed_selectors; /* Store all constructed constant strings in a hash table so that they get uniqued properly. */ -struct string_descriptor GTY(()) -{ +struct GTY(()) string_descriptor { /* The literal argument . */ tree literal; @@ -451,8 +400,12 @@ struct string_descriptor GTY(()) static GTY((param_is (struct string_descriptor))) htab_t string_htab; -static hashval_t string_hash (const void *); -static int string_eq (const void *, const void *); +/* Store the EH-volatilized types in a hash table, for easy retrieval. */ +struct GTY(()) volatilized_type { + tree type; +}; + +static GTY((param_is (struct volatilized_type))) htab_t volatilized_htab; FILE *gen_declaration_file; @@ -463,6 +416,35 @@ FILE *gen_declaration_file; static int generating_instance_variables = 0; +/* For building an objc struct. These may not be used when this file + is compiled as part of obj-c++. */ + +static bool objc_building_struct; +static bool objc_in_struct ATTRIBUTE_UNUSED; +static VEC(tree,heap) *objc_struct_types ATTRIBUTE_UNUSED; + +/* Start building a struct for objc. */ + +static tree +objc_start_struct (tree name) +{ + gcc_assert (!objc_building_struct); + objc_building_struct = true; + return start_struct (RECORD_TYPE, name, &objc_in_struct, &objc_struct_types, + UNKNOWN_LOCATION); +} + +/* Finish building a struct for objc. */ + +static tree +objc_finish_struct (tree type, tree fieldlist) +{ + gcc_assert (objc_building_struct); + objc_building_struct = false; + return finish_struct (type, fieldlist, NULL_TREE, objc_in_struct, + objc_struct_types); +} + /* Some platforms pass small structures through registers versus through an invisible pointer. Determine at what size structure is the transition point between the two possibilities. */ @@ -482,7 +464,7 @@ generate_struct_by_value_array (void) char buffer[5]; /* Create an unnamed struct that has `i' character components */ - type = start_struct (RECORD_TYPE, NULL_TREE); + type = objc_start_struct (NULL_TREE); strcpy (buffer, "c1"); field_decl = create_field_decl (char_type_node, @@ -496,7 +478,7 @@ generate_struct_by_value_array (void) buffer); chainon (field_decl_chain, field_decl); } - finish_struct (type, field_decl_chain, NULL_TREE); + objc_finish_struct (type, field_decl_chain); aggregate_in_mem[i] = aggregate_value_p (type, 0); if (!aggregate_in_mem[i]) @@ -534,13 +516,6 @@ objc_init (void) #endif return false; -#ifndef USE_MAPPED_LOCATION - /* Force the line number back to 0; check_newline will have - raised it to 1, which will make the builtin functions appear - not to be built in. */ - input_line = 0; -#endif - /* If gen_declaration desired, open the output file. */ if (flag_gen_declaration) { @@ -589,20 +564,17 @@ objc_finish_file (void) #ifdef OBJCPLUS /* We need to instantiate templates _before_ we emit ObjC metadata; if we do not, some metadata (such as selectors) may go missing. */ + at_eof = 1; instantiate_pending_templates (0); #endif /* Finalize Objective-C runtime data. No need to generate tables - and code if only checking syntax. */ - if (!flag_syntax_only) + and code if only checking syntax, or if generating a PCH file. */ + if (!flag_syntax_only && !pch_file) finish_objc (); if (gen_declaration_file) fclose (gen_declaration_file); - -#ifdef OBJCPLUS - cp_finish_file (); -#endif } /* Return the first occurrence of a method declaration corresponding @@ -677,19 +649,19 @@ lookup_protocol_in_reflist (tree rproto_list, tree lproto) } void -objc_start_class_interface (tree class, tree super_class, tree protos) +objc_start_class_interface (tree klass, tree super_class, tree protos) { objc_interface_context = objc_ivar_context - = start_class (CLASS_INTERFACE_TYPE, class, super_class, protos); + = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos); objc_public_flag = 0; } void -objc_start_category_interface (tree class, tree categ, tree protos) +objc_start_category_interface (tree klass, tree categ, tree protos) { objc_interface_context - = start_class (CATEGORY_INTERFACE_TYPE, class, categ, protos); + = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos); objc_ivar_chain = continue_class (objc_interface_context); } @@ -716,19 +688,19 @@ objc_finish_interface (void) } void -objc_start_class_implementation (tree class, tree super_class) +objc_start_class_implementation (tree klass, tree super_class) { objc_implementation_context = objc_ivar_context - = start_class (CLASS_IMPLEMENTATION_TYPE, class, super_class, NULL_TREE); + = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE); objc_public_flag = 0; } void -objc_start_category_implementation (tree class, tree categ) +objc_start_category_implementation (tree klass, tree categ) { objc_implementation_context - = start_class (CATEGORY_IMPLEMENTATION_TYPE, class, categ, NULL_TREE); + = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE); objc_ivar_chain = continue_class (objc_implementation_context); } @@ -743,6 +715,11 @@ objc_continue_implementation (void) void objc_finish_implementation (void) { +#ifdef OBJCPLUS + if (flag_objc_call_cxx_cdtors) + objc_generate_cxx_cdtors (); +#endif + if (objc_implementation_context) { finish_class (objc_implementation_context); @@ -750,7 +727,7 @@ objc_finish_implementation (void) objc_implementation_context = NULL_TREE; } else - warning ("%<@end%> must appear in an @implementation context"); + warning (0, "%<@end%> must appear in an @implementation context"); } void @@ -768,9 +745,11 @@ objc_set_method_type (enum tree_code type) } tree -objc_build_method_signature (tree rettype, tree selector, tree optparms) +objc_build_method_signature (tree rettype, tree selector, + tree optparms, bool ellipsis) { - return build_method_decl (objc_inherit_code, rettype, selector, optparms); + return build_method_decl (objc_inherit_code, rettype, selector, + optparms, ellipsis); } void @@ -813,12 +792,9 @@ objc_is_reserved_word (tree ident) unsigned char code = C_RID_CODE (ident); return (OBJC_IS_AT_KEYWORD (code) -#ifdef OBJCPLUS || code == RID_CLASS || code == RID_PUBLIC || code == RID_PROTECTED || code == RID_PRIVATE - || code == RID_TRY || code == RID_THROW || code == RID_CATCH -#endif - ); + || code == RID_TRY || code == RID_THROW || code == RID_CATCH); } /* Return true if TYPE is 'id'. */ @@ -835,330 +811,551 @@ objc_is_class_id (tree type) return OBJC_TYPE_NAME (type) == objc_class_id; } -/* Return 1 if LHS and RHS are compatible types for assignment or - various other operations. Return 0 if they are incompatible, and - return -1 if we choose to not decide (because the types are really - just C types, not ObjC specific ones). When the operation is - REFLEXIVE (typically comparisons), check for compatibility in - either direction; when it's not (typically assignments), don't. +/* Construct a C struct with same name as KLASS, a base struct with tag + SUPER_NAME (if any), and FIELDS indicated. */ + +static tree +objc_build_struct (tree klass, tree fields, tree super_name) +{ + tree name = CLASS_NAME (klass); + tree s = objc_start_struct (name); + tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE); + tree t, objc_info = NULL_TREE; + + if (super) + { + /* Prepend a packed variant of the base class into the layout. This + is necessary to preserve ObjC ABI compatibility. */ + tree base = build_decl (FIELD_DECL, NULL_TREE, super); + tree field = TYPE_FIELDS (super); + + while (field && TREE_CHAIN (field) + && TREE_CODE (TREE_CHAIN (field)) == FIELD_DECL) + field = TREE_CHAIN (field); + + /* 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 + in the class. */ + DECL_SIZE (base) + = (field && TREE_CODE (field) == FIELD_DECL + ? size_binop (PLUS_EXPR, + size_binop (PLUS_EXPR, + size_binop + (MULT_EXPR, + convert (bitsizetype, + DECL_FIELD_OFFSET (field)), + bitsize_int (BITS_PER_UNIT)), + DECL_FIELD_BIT_OFFSET (field)), + DECL_SIZE (field)) + : bitsize_zero_node); + DECL_SIZE_UNIT (base) + = size_binop (FLOOR_DIV_EXPR, convert (sizetype, DECL_SIZE (base)), + size_int (BITS_PER_UNIT)); + DECL_ARTIFICIAL (base) = 1; + DECL_ALIGN (base) = 1; + DECL_FIELD_CONTEXT (base) = s; +#ifdef OBJCPLUS + DECL_FIELD_IS_BASE (base) = 1; + + if (fields) + TREE_NO_WARNING (fields) = 1; /* Suppress C++ ABI warnings -- we */ +#endif /* are following the ObjC ABI here. */ + TREE_CHAIN (base) = fields; + fields = base; + } - This function is called in two cases: when both lhs and rhs are - pointers to records (in which case we check protocols too), and - when both lhs and rhs are records (in which case we check class - inheritance only). + /* 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 + that we store protocol conformance info (e.g., 'NSObject '). + Hence, we must squirrel away the ObjC-specific information before calling + finish_struct(), and then reinstate it afterwards. */ - Warnings about classes/protocols not implementing a protocol are - emitted here (multiple of those warnings might be emitted for a - single line!); generic warnings about incompatible assignments and - lacks of casts in comparisons are/must be emitted by the caller if - we return 0. -*/ + for (t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t)) + objc_info + = chainon (objc_info, + build_tree_list (NULL_TREE, TYPE_OBJC_INFO (t))); -int -objc_comptypes (tree lhs, tree rhs, int reflexive) -{ - /* New clause for protocols. */ + /* Point the struct at its related Objective-C class. */ + INIT_TYPE_OBJC_INFO (s); + TYPE_OBJC_INTERFACE (s) = klass; - /* Here we manage the case of a POINTER_TYPE = POINTER_TYPE. We only - manage the ObjC ones, and leave the rest to the C code. */ - if (TREE_CODE (lhs) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE - && TREE_CODE (rhs) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE) + s = objc_finish_struct (s, fields); + + for (t = TYPE_NEXT_VARIANT (s); t; + t = TYPE_NEXT_VARIANT (t), objc_info = TREE_CHAIN (objc_info)) { - int lhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (lhs); - int rhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (rhs); + TYPE_OBJC_INFO (t) = TREE_VALUE (objc_info); + /* Replace the IDENTIFIER_NODE with an actual @interface. */ + TYPE_OBJC_INTERFACE (t) = klass; + } - if (lhs_is_proto) - { - tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs); - tree rproto, rproto_list; - tree p; + /* Use TYPE_BINFO structures to point at the super class, if any. */ + objc_xref_basetypes (s, super); - /* = */ - if (rhs_is_proto) - { - /* Class != id ; - id != Class */ - if (IS_ID (lhs) != IS_ID (rhs)) - return 0; + /* Mark this struct as a class template. */ + CLASS_STATIC_TEMPLATE (klass) = s; - rproto_list = TYPE_PROTOCOL_LIST (rhs); + return s; +} - if (!reflexive) - { - /* An assignment between objects of type 'id - '; make sure the protocol on the lhs is - supported by the object on the rhs. */ - for (lproto = lproto_list; lproto; - lproto = TREE_CHAIN (lproto)) - { - p = TREE_VALUE (lproto); - rproto = lookup_protocol_in_reflist (rproto_list, p); +/* 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 + process. */ +static tree +objc_build_volatilized_type (tree type) +{ + tree t; - if (!rproto) - warning - ("object does not conform to the %qs protocol", - IDENTIFIER_POINTER (PROTOCOL_NAME (p))); - } - return 1; - } - else - { - /* Obscure case - a comparison between two objects - of type 'id '. Check that either the - protocol on the lhs is supported by the object on - the rhs, or viceversa. */ - - /* Check if the protocol on the lhs is supported by the - object on the rhs. */ - for (lproto = lproto_list; lproto; - lproto = TREE_CHAIN (lproto)) - { - p = TREE_VALUE (lproto); - rproto = lookup_protocol_in_reflist (rproto_list, p); - - if (!rproto) - { - /* Check failed - check if the protocol on the rhs - is supported by the object on the lhs. */ - for (rproto = rproto_list; rproto; - rproto = TREE_CHAIN (rproto)) - { - p = TREE_VALUE (rproto); - lproto = lookup_protocol_in_reflist (lproto_list, - p); - - if (!lproto) - { - /* This check failed too: incompatible */ - return 0; - } - } - return 1; - } - } - return 1; - } - } - /* = * */ - else if (TYPED_OBJECT (TREE_TYPE (rhs))) - { - tree rname = OBJC_TYPE_NAME (TREE_TYPE (rhs)); - tree rinter; + /* Check if we have not constructed the desired variant already. */ + for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) + { + /* The type qualifiers must (obviously) match up. */ + if (!TYPE_VOLATILE (t) + || (TYPE_READONLY (t) != TYPE_READONLY (type)) + || (TYPE_RESTRICT (t) != TYPE_RESTRICT (type))) + continue; - /* Class != * */ - if (IS_CLASS (lhs)) - return 0; + /* For pointer types, the pointees (and hence their TYPE_LANG_SPECIFIC + info, if any) must match up. */ + if (POINTER_TYPE_P (t) + && (TREE_TYPE (t) != TREE_TYPE (type))) + continue; - /* Make sure the protocol is supported by the object on - the rhs. */ - for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto)) - { - p = TREE_VALUE (lproto); - rproto = 0; - rinter = lookup_interface (rname); + /* Everything matches up! */ + return t; + } - while (rinter && !rproto) - { - tree cat; - - rproto_list = CLASS_PROTOCOL_LIST (rinter); - rproto = lookup_protocol_in_reflist (rproto_list, p); - /* If the underlying ObjC class does not have - the protocol we're looking for, check for "one-off" - protocols (e.g., `NSObject *foo;') attached - to the rhs. */ - if (!rproto) - { - rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs)); - rproto = lookup_protocol_in_reflist (rproto_list, p); - } - - /* Check for protocols adopted by categories. */ - cat = CLASS_CATEGORY_LIST (rinter); - while (cat && !rproto) - { - rproto_list = CLASS_PROTOCOL_LIST (cat); - rproto = lookup_protocol_in_reflist (rproto_list, p); - cat = CLASS_CATEGORY_LIST (cat); - } - - rinter = lookup_interface (CLASS_SUPER_NAME (rinter)); - } + /* Ok, we could not re-use any of the pre-existing variants. Create + a new one. */ + t = build_variant_type_copy (type); + TYPE_VOLATILE (t) = 1; - if (!rproto) - warning ("class %qs does not implement the %qs protocol", - IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (rhs))), - IDENTIFIER_POINTER (PROTOCOL_NAME (p))); - } - return 1; - } - /* id = id; Class = id */ - else if (objc_is_object_id (TREE_TYPE (rhs))) - { - return 1; - } - /* id != Class; Class = Class */ - else if (objc_is_class_id (TREE_TYPE (rhs))) - { - return IS_CLASS (lhs); - } - /* = ?? : let comptypes decide. */ - return -1; - } - else if (rhs_is_proto) + /* Set up the canonical type information. */ + if (TYPE_STRUCTURAL_EQUALITY_P (type)) + SET_TYPE_STRUCTURAL_EQUALITY (t); + else if (TYPE_CANONICAL (type) != type) + TYPE_CANONICAL (t) = objc_build_volatilized_type (TYPE_CANONICAL (type)); + else + TYPE_CANONICAL (t) = t; + + return t; +} + +/* Mark DECL as being 'volatile' for purposes of Darwin + _setjmp()/_longjmp() exception handling. Called from + objc_mark_locals_volatile(). */ +void +objc_volatilize_decl (tree decl) +{ + /* Do not mess with variables that are 'static' or (already) + 'volatile'. */ + if (!TREE_THIS_VOLATILE (decl) && !TREE_STATIC (decl) + && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL)) + { + tree t = TREE_TYPE (decl); + struct volatilized_type key; + void **loc; + + t = objc_build_volatilized_type (t); + key.type = t; + loc = htab_find_slot (volatilized_htab, &key, INSERT); + + if (!*loc) { - /* * = */ - if (TYPED_OBJECT (TREE_TYPE (lhs))) - { - /* * != Class */ - if (IS_CLASS (rhs)) - return 0; + *loc = ggc_alloc (sizeof (key)); + ((struct volatilized_type *) *loc)->type = t; + } - if (reflexive) - { - tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs)); - tree rinter; - tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs); - - /* Make sure the protocol is supported by the object on - the lhs. */ - for (rproto = rproto_list; rproto; - rproto = TREE_CHAIN (rproto)) - { - tree p = TREE_VALUE (rproto); - tree lproto = 0; - rinter = lookup_interface (rname); - - while (rinter && !lproto) - { - tree cat; - - tree lproto_list = CLASS_PROTOCOL_LIST (rinter); - lproto = lookup_protocol_in_reflist (lproto_list, p); - /* If the underlying ObjC class does not - have the protocol we're looking for, - check for "one-off" protocols (e.g., - `NSObject *foo;') attached to the - lhs. */ - if (!lproto) - { - lproto_list = TYPE_PROTOCOL_LIST - (TREE_TYPE (lhs)); - lproto = lookup_protocol_in_reflist - (lproto_list, p); - } - - /* Check for protocols adopted by categories. */ - cat = CLASS_CATEGORY_LIST (rinter); - while (cat && !lproto) - { - lproto_list = CLASS_PROTOCOL_LIST (cat); - lproto = lookup_protocol_in_reflist (lproto_list, - p); - cat = CLASS_CATEGORY_LIST (cat); - } - - rinter = lookup_interface (CLASS_SUPER_NAME - (rinter)); - } - - if (!lproto) - warning ("class %qs does not implement the %qs protocol", - IDENTIFIER_POINTER (OBJC_TYPE_NAME - (TREE_TYPE (lhs))), - IDENTIFIER_POINTER (PROTOCOL_NAME (p))); - } - return 1; - } - else - return 0; - } - /* id = id ; id = Class */ - else if (objc_is_object_id (TREE_TYPE (lhs))) - { - return 1; - } - /* Class != id ; Class = Class */ - else if (objc_is_class_id (TREE_TYPE (lhs))) - { - return IS_CLASS (rhs); - } - /* ??? = : let comptypes decide */ - else - { - return -1; - } + TREE_TYPE (decl) = t; + TREE_THIS_VOLATILE (decl) = 1; + TREE_SIDE_EFFECTS (decl) = 1; + DECL_REGISTER (decl) = 0; +#ifndef OBJCPLUS + C_DECL_REGISTER (decl) = 0; +#endif + } +} + +/* Check if protocol PROTO is adopted (directly or indirectly) by class CLS + (including its categories and superclasses) or by object type TYP. + Issue a warning if PROTO is not adopted anywhere and WARN is set. */ + +static bool +objc_lookup_protocol (tree proto, tree cls, tree typ, bool warn) +{ + bool class_type = (cls != NULL_TREE); + + while (cls) + { + tree c; + + /* Check protocols adopted by the class and its categories. */ + for (c = cls; c; c = CLASS_CATEGORY_LIST (c)) + { + if (lookup_protocol_in_reflist (CLASS_PROTOCOL_LIST (c), proto)) + return true; } + + /* Repeat for superclasses. */ + cls = lookup_interface (CLASS_SUPER_NAME (cls)); + } + + /* Check for any protocols attached directly to the object type. */ + if (TYPE_HAS_OBJC_INFO (typ)) + { + if (lookup_protocol_in_reflist (TYPE_OBJC_PROTOCOL_LIST (typ), proto)) + return true; + } + + if (warn) + { + *errbuf = 0; + gen_type_name_0 (class_type ? typ : TYPE_POINTER_TO (typ)); + /* NB: Types 'id' and 'Class' cannot reasonably be described as + "implementing" a given protocol, since they do not have an + implementation. */ + if (class_type) + warning (0, "class %qs does not implement the %qE protocol", + identifier_to_locale (errbuf), PROTOCOL_NAME (proto)); else + warning (0, "type %qs does not conform to the %qE protocol", + identifier_to_locale (errbuf), PROTOCOL_NAME (proto)); + } + + return false; +} + +/* Check if class RCLS and instance struct type RTYP conform to at least the + same protocols that LCLS and LTYP conform to. */ + +static bool +objc_compare_protocols (tree lcls, tree ltyp, tree rcls, tree rtyp, bool warn) +{ + tree p; + bool have_lproto = false; + + while (lcls) + { + /* 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 + that RCLS/RTYP must implement any of their protocols. */ + for (p = CLASS_PROTOCOL_LIST (lcls); p; p = TREE_CHAIN (p)) { - /* Attention: we shouldn't defer to comptypes here. One bad - side effect would be that we might loose the REFLEXIVE - information. - */ - lhs = TREE_TYPE (lhs); - rhs = TREE_TYPE (rhs); + have_lproto = true; + + if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn)) + return warn; } + + /* Repeat for superclasses. */ + lcls = lookup_interface (CLASS_SUPER_NAME (lcls)); } - if (TREE_CODE (lhs) != RECORD_TYPE || TREE_CODE (rhs) != RECORD_TYPE) + /* Check for any protocols attached directly to the object type. */ + if (TYPE_HAS_OBJC_INFO (ltyp)) { - /* Nothing to do with ObjC - let immediately comptypes take - responsibility for checking. */ - return -1; + for (p = TYPE_OBJC_PROTOCOL_LIST (ltyp); p; p = TREE_CHAIN (p)) + { + have_lproto = true; + + if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn)) + return warn; + } } - /* `id' = ` *' ` *' = `id': always allow it. - Please note that - 'Object *o = [[Object alloc] init]; falls - in the case * = `id'. - */ - if ((objc_is_object_id (lhs) && TYPED_OBJECT (rhs)) - || (objc_is_object_id (rhs) && TYPED_OBJECT (lhs))) - return 1; + /* NB: If LTYP and LCLS have no protocols to search for, return 'true' + vacuously, _unless_ RTYP is a protocol-qualified 'id'. We can get + away with simply checking for 'id' or 'Class' (!RCLS), since this + routine will not get called in other cases. */ + return have_lproto || (rcls != NULL_TREE); +} - /* `id' = `Class', `Class' = `id' */ +/* 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 + (if ARGNO is equal to -3), per ObjC type system rules. Before + returning 'true', this routine may issue warnings related to, e.g., + protocol conformance. When returning 'false', the routine must + 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, + the routine must return 'false'. - else if ((objc_is_object_id (lhs) && objc_is_class_id (rhs)) - || (objc_is_class_id (lhs) && objc_is_object_id (rhs))) - return 1; + The ARGNO parameter is encoded as follows: + >= 1 Parameter number (CALLEE contains function being called); + 0 Return value; + -1 Assignment; + -2 Initialization; + -3 Comparison (LTYP and RTYP may match in either direction). */ - /* `Class' != ` *' && ` *' != `Class'! */ - else if ((OBJC_TYPE_NAME (lhs) == objc_class_id && TYPED_OBJECT (rhs)) - || (OBJC_TYPE_NAME (rhs) == objc_class_id && TYPED_OBJECT (lhs))) - return 0; +bool +objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) +{ + tree lcls, rcls, lproto, rproto; + bool pointers_compatible; - /* ` *' = ` *' */ + /* We must be dealing with pointer types */ + if (!POINTER_TYPE_P (ltyp) || !POINTER_TYPE_P (rtyp)) + return false; - else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs)) + do { - tree lname = OBJC_TYPE_NAME (lhs); - tree rname = OBJC_TYPE_NAME (rhs); - tree inter; + ltyp = TREE_TYPE (ltyp); /* Remove indirections. */ + rtyp = TREE_TYPE (rtyp); + } + while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp)); - if (lname == rname) - return 1; + /* Past this point, we are only interested in ObjC class instances, + or 'id' or 'Class'. */ + if (TREE_CODE (ltyp) != RECORD_TYPE || TREE_CODE (rtyp) != RECORD_TYPE) + return false; + + if (!objc_is_object_id (ltyp) && !objc_is_class_id (ltyp) + && !TYPE_HAS_OBJC_INFO (ltyp)) + return false; - /* If the left hand side is a super class of the right hand side, - allow it. */ - for (inter = lookup_interface (rname); inter; - inter = lookup_interface (CLASS_SUPER_NAME (inter))) - if (lname == CLASS_SUPER_NAME (inter)) - return 1; + if (!objc_is_object_id (rtyp) && !objc_is_class_id (rtyp) + && !TYPE_HAS_OBJC_INFO (rtyp)) + return false; - /* Allow the reverse when reflexive. */ - if (reflexive) - for (inter = lookup_interface (lname); inter; - inter = lookup_interface (CLASS_SUPER_NAME (inter))) - if (rname == CLASS_SUPER_NAME (inter)) - return 1; + /* Past this point, we are committed to returning 'true' to the caller. + However, we can still warn about type and/or protocol mismatches. */ - return 0; + if (TYPE_HAS_OBJC_INFO (ltyp)) + { + lcls = TYPE_OBJC_INTERFACE (ltyp); + lproto = TYPE_OBJC_PROTOCOL_LIST (ltyp); } else - /* Not an ObjC type - let comptypes do the check. */ - return -1; + lcls = lproto = NULL_TREE; + + if (TYPE_HAS_OBJC_INFO (rtyp)) + { + rcls = TYPE_OBJC_INTERFACE (rtyp); + rproto = TYPE_OBJC_PROTOCOL_LIST (rtyp); + } + else + rcls = rproto = NULL_TREE; + + /* If we could not find an @interface declaration, we must have + only seen a @class declaration; for purposes of type comparison, + treat it as a stand-alone (root) class. */ + + if (lcls && TREE_CODE (lcls) == IDENTIFIER_NODE) + lcls = NULL_TREE; + + if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE) + rcls = NULL_TREE; + + /* If either type is an unqualified 'id', we're done. */ + if ((!lproto && objc_is_object_id (ltyp)) + || (!rproto && objc_is_object_id (rtyp))) + return true; + + pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp)); + + /* 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. */ + if (pointers_compatible && (!lproto || !rproto)) + return true; + + /* If exactly one of the types is 'Class', issue a diagnostic; any + exceptions of this rule have already been handled. */ + if (objc_is_class_id (ltyp) ^ objc_is_class_id (rtyp)) + pointers_compatible = false; + /* Otherwise, check for inheritance relations. */ + else + { + if (!pointers_compatible) + pointers_compatible + = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp)); + + if (!pointers_compatible) + pointers_compatible = DERIVED_FROM_P (ltyp, rtyp); + + if (!pointers_compatible && argno == -3) + pointers_compatible = DERIVED_FROM_P (rtyp, ltyp); + } + + /* If the pointers match modulo protocols, check for protocol conformance + mismatches. */ + if (pointers_compatible) + { + pointers_compatible = objc_compare_protocols (lcls, ltyp, rcls, rtyp, + argno != -3); + + if (!pointers_compatible && argno == -3) + pointers_compatible = objc_compare_protocols (rcls, rtyp, lcls, ltyp, + argno != -3); + } + + if (!pointers_compatible) + { + /* 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 + ObjC-specific. */ + switch (argno) + { + case -3: + warning (0, "comparison of distinct Objective-C types lacks a cast"); + break; + + case -2: + warning (0, "initialization from distinct Objective-C type"); + break; + + case -1: + warning (0, "assignment from distinct Objective-C type"); + break; + + case 0: + warning (0, "distinct Objective-C type in return"); + break; + + default: + warning (0, "passing argument %d of %qE from distinct " + "Objective-C type", argno, callee); + break; + } + } + + return true; +} + +/* Check if LTYP and RTYP have the same type qualifiers. If either type + lives in the volatilized hash table, ignore the 'volatile' bit when + making the comparison. */ + +bool +objc_type_quals_match (tree ltyp, tree rtyp) +{ + int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp); + struct volatilized_type key; + + key.type = ltyp; + + if (htab_find_slot (volatilized_htab, &key, NO_INSERT)) + lquals &= ~TYPE_QUAL_VOLATILE; + + key.type = rtyp; + + if (htab_find_slot (volatilized_htab, &key, NO_INSERT)) + rquals &= ~TYPE_QUAL_VOLATILE; + + return (lquals == rquals); +} + +#ifndef OBJCPLUS +/* Determine if CHILD is derived from PARENT. The routine assumes that + both parameters are RECORD_TYPEs, and is non-reflexive. */ + +static bool +objc_derived_from_p (tree parent, tree child) +{ + parent = TYPE_MAIN_VARIANT (parent); + + for (child = TYPE_MAIN_VARIANT (child); + TYPE_BINFO (child) && BINFO_N_BASE_BINFOS (TYPE_BINFO (child));) + { + child = TYPE_MAIN_VARIANT (BINFO_TYPE (BINFO_BASE_BINFO + (TYPE_BINFO (child), + 0))); + + if (child == parent) + return true; + } + + return false; +} +#endif + +static tree +objc_build_component_ref (tree datum, tree component) +{ + /* If COMPONENT is NULL, the caller is referring to the anonymous + base class field. */ + if (!component) + { + tree base = TYPE_FIELDS (TREE_TYPE (datum)); + + return build3 (COMPONENT_REF, TREE_TYPE (base), datum, base, NULL_TREE); + } + + /* The 'build_component_ref' routine has been removed from the C++ + front-end, but 'finish_class_member_access_expr' seems to be + a worthy substitute. */ +#ifdef OBJCPLUS + return finish_class_member_access_expr (datum, component, false, + tf_warning_or_error); +#else + return build_component_ref (datum, component); +#endif +} + +/* Recursively copy inheritance information rooted at BINFO. To do this, + we emulate the song and dance performed by cp/tree.c:copy_binfo(). */ + +static tree +objc_copy_binfo (tree binfo) +{ + tree btype = BINFO_TYPE (binfo); + tree binfo2 = make_tree_binfo (BINFO_N_BASE_BINFOS (binfo)); + tree base_binfo; + int ix; + + BINFO_TYPE (binfo2) = btype; + BINFO_OFFSET (binfo2) = BINFO_OFFSET (binfo); + BINFO_BASE_ACCESSES (binfo2) = BINFO_BASE_ACCESSES (binfo); + + /* Recursively copy base binfos of BINFO. */ + for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++) + { + tree base_binfo2 = objc_copy_binfo (base_binfo); + + BINFO_INHERITANCE_CHAIN (base_binfo2) = binfo2; + BINFO_BASE_APPEND (binfo2, base_binfo2); + } + + return binfo2; +} + +/* Record superclass information provided in BASETYPE for ObjC class REF. + This is loosely based on cp/decl.c:xref_basetypes(). */ + +static void +objc_xref_basetypes (tree ref, tree basetype) +{ + tree binfo = make_tree_binfo (basetype ? 1 : 0); + + TYPE_BINFO (ref) = binfo; + BINFO_OFFSET (binfo) = size_zero_node; + BINFO_TYPE (binfo) = ref; + + if (basetype) + { + tree base_binfo = objc_copy_binfo (TYPE_BINFO (basetype)); + + BINFO_INHERITANCE_CHAIN (base_binfo) = binfo; + BINFO_BASE_ACCESSES (binfo) = VEC_alloc (tree, gc, 1); + BINFO_BASE_APPEND (binfo, base_binfo); + BINFO_BASE_ACCESS_APPEND (binfo, access_public_node); + } +} + +static hashval_t +volatilized_hash (const void *ptr) +{ + const_tree const typ = ((const struct volatilized_type *)ptr)->type; + + return htab_hash_pointer(typ); +} + +static int +volatilized_eq (const void *ptr1, const void *ptr2) +{ + const_tree const typ1 = ((const struct volatilized_type *)ptr1)->type; + const_tree const typ2 = ((const struct volatilized_type *)ptr2)->type; + + return typ1 == typ2; } /* Called from finish_decl. */ @@ -1171,8 +1368,8 @@ objc_check_decl (tree decl) if (TREE_CODE (type) != RECORD_TYPE) return; if (OBJC_TYPE_NAME (type) && (type = objc_is_class_name (OBJC_TYPE_NAME (type)))) - error ("statically allocated instance of Objective-C class %qs", - IDENTIFIER_POINTER (type)); + error ("statically allocated instance of Objective-C class %qE", + type); } /* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may @@ -1182,11 +1379,11 @@ objc_check_decl (tree decl) tree objc_get_protocol_qualified_type (tree interface, tree protocols) { - tree type; + /* If INTERFACE is not provided, default to 'id'. */ + tree type = (interface ? objc_is_id (interface) : objc_object_type); + bool is_ptr = (type != NULL_TREE); - if (!interface) - type = objc_object_type; - else if (!(type = objc_is_id (interface))) + if (!is_ptr) { type = objc_is_class_name (interface); @@ -1199,13 +1396,33 @@ objc_get_protocol_qualified_type (tree interface, tree protocols) if (protocols) { type = build_variant_type_copy (type); - /* Look up protocols and install in lang specific list. Note - that the protocol list can have a different lifetime than T! */ - SET_TYPE_PROTOCOL_LIST (type, lookup_and_install_protocols (protocols)); - /* Establish the ObjC-ness of this record. */ - if (TREE_CODE (type) == RECORD_TYPE) - TREE_STATIC_TEMPLATE (type) = 1; + /* For pointers (i.e., 'id' or 'Class'), attach the protocol(s) + to the pointee. */ + if (is_ptr) + { + tree orig_pointee_type = TREE_TYPE (type); + TREE_TYPE (type) = build_variant_type_copy (orig_pointee_type); + + /* Set up the canonical type information. */ + TYPE_CANONICAL (type) + = TYPE_CANONICAL (TYPE_POINTER_TO (orig_pointee_type)); + + TYPE_POINTER_TO (TREE_TYPE (type)) = type; + type = TREE_TYPE (type); + } + + /* Look up protocols and install in lang specific list. */ + DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type)); + TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols (protocols); + + /* For RECORD_TYPEs, point to the @interface; for 'id' and 'Class', + return the pointer to the new pointee variant. */ + if (is_ptr) + type = TYPE_POINTER_TO (type); + else + TYPE_OBJC_INTERFACE (type) + = TYPE_OBJC_INTERFACE (TYPE_MAIN_VARIANT (type)); } return type; @@ -1228,8 +1445,8 @@ check_protocol_recursively (tree proto, tree list) pp = lookup_protocol (pp); if (pp == proto) - fatal_error ("protocol %qs has circular dependency", - IDENTIFIER_POINTER (PROTOCOL_NAME (pp))); + fatal_error ("protocol %qE has circular dependency", + PROTOCOL_NAME (pp)); if (pp) check_protocol_recursively (proto, PROTOCOL_LIST (pp)); } @@ -1249,12 +1466,12 @@ lookup_and_install_protocols (tree protocols) tree ident = TREE_VALUE (proto); tree p = lookup_protocol (ident); - if (!p) - error ("cannot find protocol declaration for %qs", - IDENTIFIER_POINTER (ident)); - else + if (p) return_value = chainon (return_value, build_tree_list (NULL_TREE, p)); + else if (ident != error_mark_node) + error ("cannot find protocol declaration for %qE", + ident); } return return_value; @@ -1293,7 +1510,7 @@ start_var_decl (tree type, const char *name) static void finish_var_decl (tree var, tree initializer) { - finish_decl (var, initializer, NULL_TREE); + finish_decl (var, initializer, NULL_TREE, NULL_TREE); /* Ensure that the variable actually gets output. */ mark_decl_referenced (var); /* Mark the decl to avoid "defined but not used" warning. */ @@ -1312,7 +1529,7 @@ setup_string_decl (void) /* %s in format will provide room for terminating null */ length = strlen (STRING_OBJECT_GLOBAL_FORMAT) + strlen (constant_string_class_name); - name = xmalloc (length); + name = XNEWVEC (char, length); sprintf (name, STRING_OBJECT_GLOBAL_FORMAT, constant_string_class_name); constant_string_global_id = get_identifier (name); @@ -1340,7 +1557,7 @@ synth_module_prologue (void) const struct gcc_debug_hooks *const save_hooks = debug_hooks; /* Suppress outputting debug symbols, because - dbxout_init hasn'r been called yet. */ + dbxout_init hasn't been called yet. */ write_symbols = NO_DEBUG; debug_hooks = &do_nothing_debug_hooks; @@ -1355,7 +1572,7 @@ synth_module_prologue (void) objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id); objc_class_reference = xref_tag (RECORD_TYPE, objc_class_id); - + objc_object_type = build_pointer_type (objc_object_reference); objc_class_type = build_pointer_type (objc_class_reference); @@ -1367,11 +1584,11 @@ synth_module_prologue (void) type = lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, objc_object_name, objc_object_type)); - DECL_IN_SYSTEM_HEADER (type) = 1; + TREE_NO_WARNING (type) = 1; type = lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, objc_class_name, objc_class_type)); - DECL_IN_SYSTEM_HEADER (type) = 1; + TREE_NO_WARNING (type) = 1; /* Forward-declare '@interface Protocol'. */ @@ -1401,6 +1618,21 @@ synth_module_prologue (void) objc_super_type = build_pointer_type (xref_tag (RECORD_TYPE, get_identifier (TAG_SUPER))); + /* Declare pointers to method and ivar lists. */ + objc_method_list_ptr = build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_METHOD_LIST))); + objc_method_proto_list_ptr + = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); + objc_ivar_list_ptr = build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_IVAR_LIST))); + + /* TREE_NOTHROW is cleared for the message-sending functions, + because the function that gets called can throw in Obj-C++, or + could itself call something that can throw even in Obj-C. */ + if (flag_next_runtime) { /* NB: In order to call one of the ..._stret (struct-returning) @@ -1417,18 +1649,42 @@ synth_module_prologue (void) tree_cons (NULL_TREE, objc_object_type, tree_cons (NULL_TREE, objc_selector_type, NULL_TREE))); - umsg_decl = builtin_function (TAG_MSGSEND, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_nonnil_decl = builtin_function (TAG_MSGSEND_NONNIL, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_stret_decl = builtin_function (TAG_MSGSEND_STRET, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_nonnil_stret_decl = builtin_function (TAG_MSGSEND_NONNIL_STRET, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + umsg_decl = add_builtin_function (TAG_MSGSEND, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_nonnil_decl = add_builtin_function (TAG_MSGSEND_NONNIL, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_stret_decl = add_builtin_function (TAG_MSGSEND_STRET, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_nonnil_stret_decl = add_builtin_function (TAG_MSGSEND_NONNIL_STRET, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* 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. */ + TREE_NOTHROW (umsg_decl) = 0; + TREE_NOTHROW (umsg_nonnil_decl) = 0; + TREE_NOTHROW (umsg_stret_decl) = 0; + TREE_NOTHROW (umsg_nonnil_stret_decl) = 0; + + /* id objc_msgSend_Fast (id, SEL, ...) + __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */ +#ifdef OFFS_MSGSEND_FAST + umsg_fast_decl = add_builtin_function (TAG_MSGSEND_FAST, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_fast_decl) = 0; + DECL_ATTRIBUTES (umsg_fast_decl) + = tree_cons (get_identifier ("hard_coded_address"), + build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST), + NULL_TREE); +#else + /* No direct dispatch available. */ + umsg_fast_decl = umsg_decl; +#endif /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */ @@ -1437,12 +1693,14 @@ synth_module_prologue (void) tree_cons (NULL_TREE, objc_super_type, tree_cons (NULL_TREE, objc_selector_type, NULL_TREE))); - umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_super_stret_decl = builtin_function (TAG_MSGSENDSUPER_STRET, - type, 0, NOT_BUILT_IN, 0, - NULL_TREE); + umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_super_stret_decl = add_builtin_function (TAG_MSGSENDSUPER_STRET, + type, 0, NOT_BUILT_IN, 0, + NULL_TREE); + TREE_NOTHROW (umsg_super_decl) = 0; + TREE_NOTHROW (umsg_super_stret_decl) = 0; } else { @@ -1451,10 +1709,10 @@ synth_module_prologue (void) /* typedef id (*IMP)(id, SEL, ...); */ tree IMP_type = build_pointer_type - (build_function_type (objc_object_type, - tree_cons (NULL_TREE, objc_object_type, - tree_cons (NULL_TREE, objc_selector_type, - NULL_TREE)))); + (build_function_type (objc_object_type, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, objc_selector_type, + NULL_TREE)))); /* IMP objc_msg_lookup (id, SEL); */ type @@ -1462,9 +1720,10 @@ synth_module_prologue (void) tree_cons (NULL_TREE, objc_object_type, tree_cons (NULL_TREE, objc_selector_type, OBJC_VOID_AT_END))); - umsg_decl = builtin_function (TAG_MSGSEND, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + umsg_decl = add_builtin_function (TAG_MSGSEND, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_decl) = 0; /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */ type @@ -1472,9 +1731,10 @@ synth_module_prologue (void) tree_cons (NULL_TREE, objc_super_type, tree_cons (NULL_TREE, objc_selector_type, OBJC_VOID_AT_END))); - umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_super_decl) = 0; /* The following GNU runtime entry point is called to initialize each module: @@ -1484,9 +1744,9 @@ synth_module_prologue (void) = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, OBJC_VOID_AT_END)); - execclass_decl = builtin_function (TAG_EXECCLASS, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + execclass_decl = add_builtin_function (TAG_EXECCLASS, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); } /* id objc_getClass (const char *); */ @@ -1497,13 +1757,13 @@ synth_module_prologue (void) OBJC_VOID_AT_END)); objc_get_class_decl - = builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); /* id objc_getMetaClass (const char *); */ objc_get_meta_class_decl - = 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_super_template (); @@ -1529,10 +1789,6 @@ synth_module_prologue (void) /* Pre-build the following entities - for speed/convenience. */ self_id = get_identifier ("self"); ucmd_id = get_identifier ("_cmd"); -#ifndef OBJCPLUS - /* The C++ front-end does not appear to grok __attribute__((__unused__)). */ - unused_list = build_tree_list (get_identifier ("__unused__"), NULL_TREE); -#endif #ifdef OBJCPLUS pop_lang_context (); @@ -1557,11 +1813,11 @@ synth_module_prologue (void) static int check_string_class_template (void) { - tree field_decl = TYPE_FIELDS (constant_string_type); + tree field_decl = objc_get_class_ivars (constant_string_id); #define AT_LEAST_AS_LARGE_AS(F, T) \ (F && TREE_CODE (F) == FIELD_DECL \ - && (TREE_INT_CST_LOW (DECL_SIZE (F)) \ + && (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (F))) \ >= TREE_INT_CST_LOW (TYPE_SIZE (T)))) if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) @@ -1580,6 +1836,27 @@ check_string_class_template (void) /* Avoid calling `check_string_class_template ()' more than once. */ static GTY(()) int string_layout_checked; +/* Construct an internal string layout to be used as a template for + creating NSConstantString/NXConstantString instances. */ + +static tree +objc_build_internal_const_str_type (void) +{ + tree type = (*lang_hooks.types.make_type) (RECORD_TYPE); + tree fields = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node); + tree field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node); + + TREE_CHAIN (field) = fields; fields = field; + field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); + TREE_CHAIN (field) = fields; fields = field; + /* NB: The finish_builtin_struct() routine expects FIELD_DECLs in + reverse order! */ + finish_builtin_struct (type, "__builtin_ObjCString", + fields, NULL_TREE); + + return type; +} + /* Custom build_string which sets TREE_TYPE! */ static tree @@ -1588,11 +1865,21 @@ my_build_string (int len, const char *str) return fix_string_type (build_string (len, str)); } +/* Build a string with contents STR and length LEN and convert it to a + pointer. */ + +static tree +my_build_string_pointer (int len, const char *str) +{ + tree string = my_build_string (len, str); + tree ptrtype = build_pointer_type (TREE_TYPE (TREE_TYPE (string))); + return build1 (ADDR_EXPR, ptrtype, string); +} static hashval_t string_hash (const void *ptr) { - tree str = ((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); int i, len = TREE_STRING_LENGTH (str); hashval_t h = len; @@ -1606,8 +1893,8 @@ string_hash (const void *ptr) static int string_eq (const void *ptr1, const void *ptr2) { - tree str1 = ((struct string_descriptor *)ptr1)->literal; - tree str2 = ((struct string_descriptor *)ptr2)->literal; + const_tree const str1 = ((const struct string_descriptor *)ptr1)->literal; + const_tree const str2 = ((const struct string_descriptor *)ptr2)->literal; int len1 = TREE_STRING_LENGTH (str1); return (len1 == TREE_STRING_LENGTH (str2) @@ -1642,21 +1929,22 @@ objc_build_string_object (tree string) { string_layout_checked = -1; constant_string_class = lookup_interface (constant_string_id); + internal_const_str_type = objc_build_internal_const_str_type (); if (!constant_string_class || !(constant_string_type = CLASS_STATIC_TEMPLATE (constant_string_class))) - error ("cannot find interface declaration for %qs", - IDENTIFIER_POINTER (constant_string_id)); + error ("cannot find interface declaration for %qE", + constant_string_id); /* The NSConstantString/NXConstantString ivar layout is now known. */ else if (!check_string_class_template ()) - error ("interface %qs does not have valid constant string layout", - IDENTIFIER_POINTER (constant_string_id)); + error ("interface %qE does not have valid constant string layout", + constant_string_id); /* For the NeXT runtime, we can generate a literal reference to the string class, don't need to run a constructor. */ else if (flag_next_runtime && !setup_string_decl ()) - error ("cannot find reference tag for class %qs", - IDENTIFIER_POINTER (constant_string_id)); + error ("cannot find reference tag for class %qE", + constant_string_id); else { string_layout_checked = 1; /* Success! */ @@ -1670,31 +1958,32 @@ objc_build_string_object (tree string) /* Perhaps we already constructed a constant string just like this one? */ key.literal = string; loc = htab_find_slot (string_htab, &key, INSERT); - desc = *loc; + desc = (struct string_descriptor *) *loc; if (!desc) { tree var; - *loc = desc = ggc_alloc (sizeof (*desc)); + *loc = desc = GGC_NEW (struct string_descriptor); desc->literal = string; - /* GNU: & ((NXConstantString) { NULL, string, length }) */ - /* NeXT: & ((NSConstantString) { isa, string, length }) */ - fields = TYPE_FIELDS (constant_string_type); + /* GNU: (NXConstantString *) & ((__builtin_ObjCString) { NULL, string, length }) */ + /* NeXT: (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length }) */ + fields = TYPE_FIELDS (internal_const_str_type); initlist = build_tree_list (fields, flag_next_runtime - ? build_unary_op (ADDR_EXPR, string_class_decl, 0) + ? build_unary_op (input_location, + ADDR_EXPR, string_class_decl, 0) : build_int_cst (NULL_TREE, 0)); fields = TREE_CHAIN (fields); - initlist = tree_cons (fields, build_unary_op (ADDR_EXPR, string, 1), + initlist = tree_cons (fields, build_unary_op (input_location, + ADDR_EXPR, string, 1), initlist); fields = TREE_CHAIN (fields); initlist = tree_cons (fields, build_int_cst (NULL_TREE, length), initlist); - constructor = objc_build_constructor (constant_string_type, + constructor = objc_build_constructor (internal_const_str_type, nreverse (initlist)); - TREE_INVARIANT (constructor) = true; if (!flag_next_runtime) constructor @@ -1710,7 +1999,9 @@ objc_build_string_object (tree string) desc->constructor = constructor; } - addr = build_unary_op (ADDR_EXPR, desc->constructor, 1); + addr = convert (build_pointer_type (constant_string_type), + build_unary_op (input_location, + ADDR_EXPR, desc->constructor, 1)); return addr; } @@ -1741,6 +2032,7 @@ objc_add_static_instance (tree constructor, tree class_decl) DECL_COMMON (decl) = 1; TREE_STATIC (decl) = 1; DECL_ARTIFICIAL (decl) = 1; + TREE_USED (decl) = 1; DECL_INITIAL (decl) = constructor; /* We may be writing something else just now. @@ -1761,7 +2053,7 @@ objc_add_static_instance (tree constructor, tree class_decl) static tree objc_build_constructor (tree type, tree elts) { - tree constructor = build_constructor (type, elts); + tree constructor = build_constructor_from_list (type, elts); TREE_CONSTANT (constructor) = 1; TREE_STATIC (constructor) = 1; @@ -1771,8 +2063,7 @@ objc_build_constructor (tree type, tree elts) /* Adjust for impedance mismatch. We should figure out how to build CONSTRUCTORs that consistently please both the C and C++ gods. */ if (!TREE_PURPOSE (elts)) - TREE_TYPE (constructor) = NULL_TREE; - TREE_HAS_CONSTRUCTOR (constructor) = 1; + TREE_TYPE (constructor) = init_list_type_node; #endif return constructor; @@ -1796,8 +2087,7 @@ build_objc_symtab_template (void) { tree field_decl, field_decl_chain; - objc_symtab_template - = start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB)); + objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB)); /* long sel_ref_cnt; */ field_decl = create_field_decl (long_integer_type_node, "sel_ref_cnt"); @@ -1831,7 +2121,7 @@ build_objc_symtab_template (void) chainon (field_decl_chain, field_decl); } - finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_symtab_template, field_decl_chain); } /* Create the initial value for the `defs' field of _objc_symtab. @@ -1848,7 +2138,8 @@ init_def_list (tree type) { if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) { - expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0); + expr = build_unary_op (input_location, + ADDR_EXPR, impent->class_decl, 0); initlist = tree_cons (NULL_TREE, expr, initlist); } } @@ -1858,7 +2149,8 @@ init_def_list (tree type) { if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) { - expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0); + expr = build_unary_op (input_location, + ADDR_EXPR, impent->class_decl, 0); initlist = tree_cons (NULL_TREE, expr, initlist); } } @@ -1869,7 +2161,8 @@ init_def_list (tree type) tree expr; if (static_instances_decl) - expr = build_unary_op (ADDR_EXPR, static_instances_decl, 0); + expr = build_unary_op (input_location, + ADDR_EXPR, static_instances_decl, 0); else expr = build_int_cst (NULL_TREE, 0); @@ -1899,7 +2192,7 @@ init_objc_symtab (tree type) initlist = tree_cons (NULL_TREE, convert (build_pointer_type (objc_selector_type), - build_unary_op (ADDR_EXPR, + build_unary_op (input_location, ADDR_EXPR, UOBJC_SELECTOR_TABLE_decl, 1)), initlist); @@ -1997,15 +2290,17 @@ init_module_descriptor (tree type) size_in_bytes (objc_module_template)); initlist = tree_cons (NULL_TREE, expr, initlist); - /* name = { ..., "foo.m", ... } */ + /* Don't provide any file name for security reasons. */ + /* name = { ..., "", ... } */ - expr = add_objc_string (get_identifier (input_filename), class_names); + expr = add_objc_string (get_identifier (""), class_names); initlist = tree_cons (NULL_TREE, expr, initlist); /* symtab = { ..., _OBJC_SYMBOLS, ... } */ if (UOBJC_SYMBOLS_decl) - expr = build_unary_op (ADDR_EXPR, UOBJC_SYMBOLS_decl, 0); + expr = build_unary_op (input_location, + ADDR_EXPR, UOBJC_SYMBOLS_decl, 0); else expr = build_int_cst (NULL_TREE, 0); initlist = tree_cons (NULL_TREE, expr, initlist); @@ -2026,8 +2321,7 @@ build_module_descriptor (void) push_lang_context (lang_name_c); /* extern "C" */ #endif - objc_module_template - = start_struct (RECORD_TYPE, get_identifier (UTAG_MODULE)); + objc_module_template = objc_start_struct (get_identifier (UTAG_MODULE)); /* long version; */ field_decl = create_field_decl (long_integer_type_node, "version"); @@ -2049,7 +2343,7 @@ build_module_descriptor (void) "symtab"); chainon (field_decl_chain, field_decl); - finish_struct (objc_module_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_module_template, field_decl_chain); /* Create an instance of "_objc_module". */ UOBJC_MODULES_decl = start_var_decl (objc_module_template, "_OBJC_MODULES"); @@ -2066,7 +2360,7 @@ build_module_descriptor (void) static void __objc_gnu_init (void) { __objc_exec_class (&L_OBJC_MODULES); - } */ + } */ static void build_module_initializer_routine (void) @@ -2075,7 +2369,7 @@ build_module_initializer_routine (void) #ifdef OBJCPLUS push_lang_context (lang_name_c); /* extern "C" */ -#endif +#endif objc_push_parm (build_decl (PARM_DECL, NULL_TREE, void_type_node)); objc_start_function (get_identifier (TAG_GNUINIT), @@ -2088,7 +2382,7 @@ build_module_initializer_routine (void) (execclass_decl, build_tree_list (NULL_TREE, - build_unary_op (ADDR_EXPR, + build_unary_op (input_location, ADDR_EXPR, UOBJC_MODULES_decl, 0)))); add_stmt (c_end_compound_stmt (body, true)); @@ -2161,7 +2455,7 @@ static void generate_static_references (void) { tree decls = NULL_TREE, expr = NULL_TREE; - tree class_name, class, decl, initlist; + tree class_name, klass, decl, initlist; tree cl_chain, in_chain, type = build_array_type (build_pointer_type (void_type_node), NULL_TREE); int num_inst, num_class; @@ -2180,16 +2474,18 @@ generate_static_references (void) decl = start_var_decl (type, buf); /* Output {class_name, ...}. */ - class = TREE_VALUE (cl_chain); - class_name = get_objc_string_decl (OBJC_TYPE_NAME (class), class_names); + klass = TREE_VALUE (cl_chain); + class_name = get_objc_string_decl (OBJC_TYPE_NAME (klass), class_names); initlist = build_tree_list (NULL_TREE, - build_unary_op (ADDR_EXPR, class_name, 1)); + build_unary_op (input_location, + ADDR_EXPR, class_name, 1)); /* Output {..., instance, ...}. */ for (in_chain = TREE_PURPOSE (cl_chain); in_chain; in_chain = TREE_CHAIN (in_chain)) { - expr = build_unary_op (ADDR_EXPR, TREE_VALUE (in_chain), 1); + expr = build_unary_op (input_location, + ADDR_EXPR, TREE_VALUE (in_chain), 1); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -2199,7 +2495,8 @@ generate_static_references (void) expr = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist)); finish_var_decl (decl, expr); decls - = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, decl, 1), decls); + = tree_cons (NULL_TREE, build_unary_op (input_location, + ADDR_EXPR, decl, 1), decls); } decls = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), decls); @@ -2208,60 +2505,6 @@ generate_static_references (void) finish_var_decl (static_instances_decl, expr); } -/* Output all strings. */ - -static void -generate_strings (void) -{ - tree chain, string_expr; - tree string, decl, type; - - for (chain = class_names_chain; chain; chain = TREE_CHAIN (chain)) - { - string = TREE_VALUE (chain); - decl = TREE_PURPOSE (chain); - type = build_array_type - (char_type_node, - build_index_type - (build_int_cst (NULL_TREE, - IDENTIFIER_LENGTH (string)))); - decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl))); - string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, - IDENTIFIER_POINTER (string)); - finish_var_decl (decl, string_expr); - } - - for (chain = meth_var_names_chain; chain; chain = TREE_CHAIN (chain)) - { - string = TREE_VALUE (chain); - decl = TREE_PURPOSE (chain); - type = build_array_type - (char_type_node, - build_index_type - (build_int_cst (NULL_TREE, - IDENTIFIER_LENGTH (string)))); - decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl))); - string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, - IDENTIFIER_POINTER (string)); - finish_var_decl (decl, string_expr); - } - - for (chain = meth_var_types_chain; chain; chain = TREE_CHAIN (chain)) - { - string = TREE_VALUE (chain); - decl = TREE_PURPOSE (chain); - type = build_array_type - (char_type_node, - build_index_type - (build_int_cst (NULL_TREE, - IDENTIFIER_LENGTH (string)))); - decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl))); - string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, - IDENTIFIER_POINTER (string)); - finish_var_decl (decl, string_expr); - } -} - static GTY(()) int selector_reference_idx; static tree @@ -2327,8 +2570,15 @@ build_selector_translation_table (void) } } if (!found) - warning ("%Jcreating selector for nonexistent method %qE", - TREE_PURPOSE (chain), TREE_VALUE (chain)); + { + location_t *loc; + if (flag_next_runtime && TREE_PURPOSE (chain)) + loc = &DECL_SOURCE_LOCATION (TREE_PURPOSE (chain)); + else + loc = &input_location; + warning (0, "%Hcreating selector for nonexistent method %qE", + loc, TREE_VALUE (chain)); + } } expr = build_selector (TREE_VALUE (chain)); @@ -2367,7 +2617,7 @@ build_selector_translation_table (void) tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), tree_cons (NULL_TREE, - build_int_cst (NULL_TREE, 0), + build_int_cst (NULL_TREE, 0), NULL_TREE))) : build_int_cst (NULL_TREE, 0), initlist); initlist = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl), @@ -2418,9 +2668,10 @@ build_typed_selector_reference (tree ident, tree prototype) *chain = tree_cons (prototype, ident, NULL_TREE); return_at_index: - expr = build_unary_op (ADDR_EXPR, + expr = build_unary_op (input_location, ADDR_EXPR, build_array_ref (UOBJC_SELECTOR_TABLE_decl, - build_int_cst (NULL_TREE, index)), + build_int_cst (NULL_TREE, index), + input_location), 1); return convert (objc_selector_type, expr); } @@ -2438,7 +2689,8 @@ build_selector_reference (tree ident) return (flag_next_runtime ? TREE_PURPOSE (*chain) : build_array_ref (UOBJC_SELECTOR_TABLE_decl, - build_int_cst (NULL_TREE, index))); + build_int_cst (NULL_TREE, index), + input_location)); index++; chain = &TREE_CHAIN (*chain); @@ -2451,7 +2703,8 @@ build_selector_reference (tree ident) return (flag_next_runtime ? expr : build_array_ref (UOBJC_SELECTOR_TABLE_decl, - build_int_cst (NULL_TREE, index))); + build_int_cst (NULL_TREE, index), + input_location)); } static GTY(()) int class_reference_idx; @@ -2502,21 +2755,34 @@ add_class_reference (tree ident) tree objc_get_class_reference (tree ident) { - tree orig_ident; + tree orig_ident = (DECL_P (ident) + ? DECL_NAME (ident) + : TYPE_P (ident) + ? OBJC_TYPE_NAME (ident) + : ident); + bool local_scope = false; #ifdef OBJCPLUS if (processing_template_decl) /* Must wait until template instantiation time. */ return build_min_nt (CLASS_REFERENCE_EXPR, ident); +#endif + if (TREE_CODE (ident) == TYPE_DECL) - ident = DECL_NAME (ident); + ident = (DECL_ORIGINAL_TYPE (ident) + ? DECL_ORIGINAL_TYPE (ident) + : TREE_TYPE (ident)); + +#ifdef OBJCPLUS + if (TYPE_P (ident) && TYPE_CONTEXT (ident) + && TYPE_CONTEXT (ident) != global_namespace) + local_scope = true; #endif - orig_ident = ident; - if (!(ident = objc_is_class_name (ident))) + if (local_scope || !(ident = objc_is_class_name (ident))) { - error ("%qs is not an Objective-C class name or alias", - IDENTIFIER_POINTER (orig_ident)); + error ("%qE is not an Objective-C class name or alias", + orig_ident); return error_mark_node; } @@ -2545,8 +2811,9 @@ objc_get_class_reference (tree ident) add_class_reference (ident); params = build_tree_list (NULL_TREE, - my_build_string (IDENTIFIER_LENGTH (ident) + 1, - IDENTIFIER_POINTER (ident))); + my_build_string_pointer + (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident))); assemble_external (objc_get_class_decl); return build_function_call (objc_get_class_decl, params); @@ -2559,7 +2826,7 @@ objc_get_class_reference (tree ident) static tree add_objc_string (tree ident, enum string_section section) { - tree *chain, decl; + tree *chain, decl, type, string_expr; if (section == class_names) chain = &class_names_chain; @@ -2574,16 +2841,28 @@ add_objc_string (tree ident, enum string_section section) { if (TREE_VALUE (*chain) == ident) return convert (string_type_node, - build_unary_op (ADDR_EXPR, TREE_PURPOSE (*chain), 1)); + build_unary_op (input_location, + ADDR_EXPR, TREE_PURPOSE (*chain), 1)); chain = &TREE_CHAIN (*chain); } decl = build_objc_string_decl (section); + type = build_array_type + (char_type_node, + build_index_type + (build_int_cst (NULL_TREE, + IDENTIFIER_LENGTH (ident)))); + decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl))); + string_expr = my_build_string (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident)); + finish_var_decl (decl, string_expr); + *chain = tree_cons (decl, ident, NULL_TREE); - return convert (string_type_node, build_unary_op (ADDR_EXPR, decl, 1)); + return convert (string_type_node, build_unary_op (input_location, + ADDR_EXPR, decl, 1)); } static GTY(()) int class_names_idx; @@ -2614,7 +2893,7 @@ build_objc_string_decl (enum string_section section) DECL_ARTIFICIAL (decl) = 1; #ifdef OBJCPLUS DECL_THIS_STATIC (decl) = 1; /* squash redeclaration errors */ -#endif +#endif make_decl_rtl (decl); pushdecl_top_level (decl); @@ -2635,11 +2914,24 @@ objc_declare_alias (tree alias_ident, tree class_ident) #endif /* OBJCPLUS */ if (!(underlying_class = objc_is_class_name (class_ident))) - warning ("cannot find class %qs", IDENTIFIER_POINTER (class_ident)); + warning (0, "cannot find class %qE", class_ident); else if (objc_is_class_name (alias_ident)) - warning ("class %qs already exists", IDENTIFIER_POINTER (alias_ident)); + warning (0, "class %qE already exists", alias_ident); else - alias_chain = tree_cons (underlying_class, alias_ident, alias_chain); + { + /* Implement @compatibility_alias as a typedef. */ +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + lang_hooks.decls.pushdecl (build_decl + (TYPE_DECL, + alias_ident, + xref_tag (RECORD_TYPE, underlying_class))); +#ifdef OBJCPLUS + pop_lang_context (); +#endif + alias_chain = tree_cons (underlying_class, alias_ident, alias_chain); + } } void @@ -2658,18 +2950,26 @@ objc_declare_class (tree ident_list) if (! objc_is_class_name (ident)) { - tree record = lookup_name (ident); - - if (record && ! TREE_STATIC_TEMPLATE (record)) + tree record = lookup_name (ident), type = record; + + if (record) { - error ("%qs redeclared as different kind of symbol", - IDENTIFIER_POINTER (ident)); - error ("%Jprevious declaration of '%D'", - record, record); + if (TREE_CODE (record) == TYPE_DECL) + type = DECL_ORIGINAL_TYPE (record); + + if (!TYPE_HAS_OBJC_INFO (type) + || !TYPE_OBJC_INTERFACE (type)) + { + error ("%qE redeclared as different kind of symbol", + ident); + error ("previous declaration of %q+D", + record); + } } record = xref_tag (RECORD_TYPE, ident); - TREE_STATIC_TEMPLATE (record) = 1; + INIT_TYPE_OBJC_INFO (record); + TYPE_OBJC_INTERFACE (record) = ident; class_chain = tree_cons (NULL_TREE, ident, class_chain); } } @@ -2730,7 +3030,7 @@ objc_is_id (tree type) return (objc_object_type && type && (IS_ID (type) || IS_CLASS (type) || IS_SUPER (type)) ? type - : NULL_TREE); + : NULL_TREE); } /* Check whether TYPE is either 'id', 'Class', or a pointer to an ObjC @@ -2753,21 +3053,323 @@ objc_is_object_ptr (tree type) return ret; } +static int +objc_is_gcable_type (tree type, int or_strong_p) +{ + tree name; + + if (!TYPE_P (type)) + return 0; + if (objc_is_id (TYPE_MAIN_VARIANT (type))) + return 1; + if (or_strong_p && lookup_attribute ("objc_gc", TYPE_ATTRIBUTES (type))) + return 1; + if (TREE_CODE (type) != POINTER_TYPE && TREE_CODE (type) != INDIRECT_REF) + return 0; + type = TREE_TYPE (type); + if (TREE_CODE (type) != RECORD_TYPE) + return 0; + name = TYPE_NAME (type); + return (objc_is_class_name (name) != NULL_TREE); +} + static tree -lookup_interface (tree ident) +objc_substitute_decl (tree expr, tree oldexpr, tree newexpr) +{ + if (expr == oldexpr) + return newexpr; + + switch (TREE_CODE (expr)) + { + case COMPONENT_REF: + return objc_build_component_ref + (objc_substitute_decl (TREE_OPERAND (expr, 0), + oldexpr, + newexpr), + DECL_NAME (TREE_OPERAND (expr, 1))); + case ARRAY_REF: + return build_array_ref (objc_substitute_decl (TREE_OPERAND (expr, 0), + oldexpr, + newexpr), + TREE_OPERAND (expr, 1), + input_location); + case INDIRECT_REF: + return build_indirect_ref (input_location, + objc_substitute_decl (TREE_OPERAND (expr, 0), + oldexpr, + newexpr), "->"); + default: + return expr; + } +} + +static tree +objc_build_ivar_assignment (tree outervar, tree lhs, tree rhs) { - tree chain; + tree func_params; + /* The LHS parameter contains the expression 'outervar->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]'). + */ + tree offs + = objc_substitute_decl + (lhs, outervar, convert (TREE_TYPE (outervar), integer_zero_node)); + tree func + = (flag_objc_direct_dispatch + ? objc_assign_ivar_fast_decl + : objc_assign_ivar_decl); + + offs = convert (integer_type_node, build_unary_op (input_location, + ADDR_EXPR, offs, 0)); + offs = fold (offs); + func_params = tree_cons (NULL_TREE, + convert (objc_object_type, rhs), + tree_cons (NULL_TREE, convert (objc_object_type, outervar), + tree_cons (NULL_TREE, offs, + NULL_TREE))); + + assemble_external (func); + return build_function_call (func, func_params); +} + +static tree +objc_build_global_assignment (tree lhs, tree rhs) +{ + tree func_params = tree_cons (NULL_TREE, + convert (objc_object_type, rhs), + tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type), + build_unary_op (input_location, ADDR_EXPR, lhs, 0)), + NULL_TREE)); + + assemble_external (objc_assign_global_decl); + return build_function_call (objc_assign_global_decl, func_params); +} + +static tree +objc_build_strong_cast_assignment (tree lhs, tree rhs) +{ + tree func_params = tree_cons (NULL_TREE, + convert (objc_object_type, rhs), + tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type), + build_unary_op (input_location, ADDR_EXPR, lhs, 0)), + NULL_TREE)); + + assemble_external (objc_assign_strong_cast_decl); + return build_function_call (objc_assign_strong_cast_decl, func_params); +} + +static int +objc_is_gcable_p (tree expr) +{ + return (TREE_CODE (expr) == COMPONENT_REF + ? objc_is_gcable_p (TREE_OPERAND (expr, 1)) + : TREE_CODE (expr) == ARRAY_REF + ? (objc_is_gcable_p (TREE_TYPE (expr)) + || objc_is_gcable_p (TREE_OPERAND (expr, 0))) + : TREE_CODE (expr) == ARRAY_TYPE + ? objc_is_gcable_p (TREE_TYPE (expr)) + : TYPE_P (expr) + ? objc_is_gcable_type (expr, 1) + : (objc_is_gcable_p (TREE_TYPE (expr)) + || (DECL_P (expr) + && lookup_attribute ("objc_gc", DECL_ATTRIBUTES (expr))))); +} + +static int +objc_is_ivar_reference_p (tree expr) +{ + return (TREE_CODE (expr) == ARRAY_REF + ? objc_is_ivar_reference_p (TREE_OPERAND (expr, 0)) + : TREE_CODE (expr) == COMPONENT_REF + ? TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL + : 0); +} + +static int +objc_is_global_reference_p (tree expr) +{ + return (TREE_CODE (expr) == INDIRECT_REF || TREE_CODE (expr) == PLUS_EXPR + ? objc_is_global_reference_p (TREE_OPERAND (expr, 0)) + : DECL_P (expr) + ? (!DECL_CONTEXT (expr) || TREE_STATIC (expr)) + : 0); +} + +tree +objc_generate_write_barrier (tree lhs, enum tree_code modifycode, tree rhs) +{ + tree result = NULL_TREE, outer; + 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 + will have been transformed to the form '*(type *)&expr'. */ + if (TREE_CODE (lhs) == INDIRECT_REF) + { + outer = TREE_OPERAND (lhs, 0); + + while (!strong_cast_p + && (CONVERT_EXPR_P (outer) + || TREE_CODE (outer) == NON_LVALUE_EXPR)) + { + tree lhstype = TREE_TYPE (outer); + + /* Descend down the cast chain, and record the first objc_gc + attribute found. */ + if (POINTER_TYPE_P (lhstype)) + { + tree attr + = lookup_attribute ("objc_gc", + TYPE_ATTRIBUTES (TREE_TYPE (lhstype))); + + if (attr) + strong_cast_p = 1; + } + + outer = TREE_OPERAND (outer, 0); + } + } + + /* If we have a __strong cast, it trumps all else. */ + if (strong_cast_p) + { + if (modifycode != NOP_EXPR) + goto invalid_pointer_arithmetic; + + if (warn_assign_intercept) + warning (0, "strong-cast assignment has been intercepted"); + + result = objc_build_strong_cast_assignment (lhs, rhs); + + goto exit_point; + } + + /* the lhs must be of a suitable type, regardless of its underlying + structure. */ + if (!objc_is_gcable_p (lhs)) + goto exit_point; + + outer = lhs; + + while (outer + && (TREE_CODE (outer) == COMPONENT_REF + || TREE_CODE (outer) == ARRAY_REF)) + outer = TREE_OPERAND (outer, 0); + + if (TREE_CODE (outer) == INDIRECT_REF) + { + outer = TREE_OPERAND (outer, 0); + indirect_p = 1; + } + + outer_gc_p = objc_is_gcable_p (outer); + + /* Handle ivar assignments. */ + if (objc_is_ivar_reference_p (lhs)) + { + /* 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. */ + if (!objc_is_gcable_type (TREE_TYPE (outer), 0)) + { + /* We may still be able to use the global write barrier... */ + if (!indirect_p && objc_is_global_reference_p (outer)) + goto global_reference; + suggest_cast: + if (modifycode == NOP_EXPR) + { + if (warn_assign_intercept) + warning (0, "strong-cast may possibly be needed"); + } + + goto exit_point; + } + + if (modifycode != NOP_EXPR) + goto invalid_pointer_arithmetic; + + if (warn_assign_intercept) + warning (0, "instance variable assignment has been intercepted"); + + result = objc_build_ivar_assignment (outer, lhs, rhs); + + goto exit_point; + } + + /* Likewise, intercept assignment to global/static variables if their type is + GC-marked. */ + if (objc_is_global_reference_p (outer)) + { + if (indirect_p) + goto suggest_cast; + + global_reference: + if (modifycode != NOP_EXPR) + { + invalid_pointer_arithmetic: + if (outer_gc_p) + warning (0, "pointer arithmetic for garbage-collected objects not allowed"); + + goto exit_point; + } + + if (warn_assign_intercept) + warning (0, "global/static variable assignment has been intercepted"); + + result = objc_build_global_assignment (lhs, rhs); + } + + /* In all other cases, fall back to the normal mechanism. */ + exit_point: + return result; +} + +struct GTY(()) interface_tuple { + tree id; + tree class_name; +}; + +static GTY ((param_is (struct interface_tuple))) htab_t interface_htab; + +static hashval_t +hash_interface (const void *p) +{ + const struct interface_tuple *d = (const struct interface_tuple *) p; + return IDENTIFIER_HASH_VALUE (d->id); +} + +static int +eq_interface (const void *p1, const void *p2) +{ + const struct interface_tuple *d = (const struct interface_tuple *) p1; + return d->id == p2; +} + +static tree +lookup_interface (tree ident) +{ #ifdef OBJCPLUS if (ident && TREE_CODE (ident) == TYPE_DECL) ident = DECL_NAME (ident); #endif - for (chain = interface_chain; chain; chain = TREE_CHAIN (chain)) - { - if (ident == CLASS_NAME (chain)) - return chain; - } - return NULL_TREE; + + if (ident == NULL_TREE || TREE_CODE (ident) != IDENTIFIER_NODE) + return NULL_TREE; + + { + struct interface_tuple **slot; + tree i = NULL_TREE; + + if (interface_htab) + { + slot = (struct interface_tuple **) + htab_find_slot_with_hash (interface_htab, ident, + IDENTIFIER_HASH_VALUE (ident), + NO_INSERT); + if (slot && *slot) + i = (*slot)->class_name; + } + return i; + } } /* Implement @defs () within struct bodies. */ @@ -2778,10 +3380,10 @@ objc_get_class_ivars (tree class_name) tree interface = lookup_interface (class_name); if (interface) - return get_class_ivars (interface); + return get_class_ivars (interface, true); - error ("cannot find interface declaration for %qs", - IDENTIFIER_POINTER (class_name)); + error ("cannot find interface declaration for %qE", + class_name); return error_mark_node; } @@ -2790,7 +3392,7 @@ objc_get_class_ivars (tree class_name) and for @defs constructs. */ static tree -get_class_ivars (tree interface) +get_class_ivars (tree interface, bool inherited) { tree ivar_chain = copy_list (CLASS_RAW_IVARS (interface)); @@ -2801,6 +3403,9 @@ get_class_ivars (tree interface) if (!CLASS_IVARS (interface)) CLASS_IVARS (interface) = ivar_chain; + if (!inherited) + return ivar_chain; + while (CLASS_SUPER_NAME (interface)) { /* Prepend super-class ivars. */ @@ -2816,7 +3421,7 @@ static tree objc_create_temporary_var (tree type) { tree decl; - + decl = build_decl (VAR_DECL, NULL_TREE, type); TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; @@ -2890,7 +3495,7 @@ objc_init_exceptions (void) /* On Darwin, ObjC exceptions require a sufficiently recent version of the runtime, so the user must ask for them explicitly. */ if (!flag_objc_exceptions) - warning ("use %<-fobjc-exceptions%> to enable Objective-C " + warning (0, "use %<-fobjc-exceptions%> to enable Objective-C " "exception syntax"); } #ifndef OBJCPLUS @@ -2901,6 +3506,7 @@ objc_init_exceptions (void) = init_one_libfunc (USING_SJLJ_EXCEPTIONS ? "__gnu_objc_personality_sj0" : "__gnu_objc_personality_v0"); + default_init_unwind_resume_libfunc (); using_eh_for_cleanups (); lang_eh_runtime_type = objc_eh_runtime_type; } @@ -2925,7 +3531,7 @@ objc_build_exc_ptr (void) return var; } else - return build (EXC_PTR_EXPR, objc_object_type); + return build0 (EXC_PTR_EXPR, objc_object_type); } /* Build "objc_exception_try_exit(&_stack)". */ @@ -2958,23 +3564,31 @@ next_sjlj_build_enter_and_setjmp (void) t = tree_cons (NULL, t, NULL); enter = build_function_call (objc_exception_try_enter_decl, t); - t = build_component_ref (cur_try_context->stack_decl, - get_identifier ("buf")); + t = objc_build_component_ref (cur_try_context->stack_decl, + get_identifier ("buf")); t = build_fold_addr_expr (t); +#ifdef OBJCPLUS + /* Convert _setjmp argument to type that is expected. */ + if (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))) + t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t); + else + t = convert (ptr_type_node, t); +#else t = convert (ptr_type_node, t); +#endif t = tree_cons (NULL, t, NULL); sj = build_function_call (objc_setjmp_decl, t); - cond = build (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj); - cond = lang_hooks.truthvalue_conversion (cond); + cond = build2 (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj); + cond = c_common_truthvalue_conversion (input_location, cond); - return build (COND_EXPR, void_type_node, cond, NULL, NULL); + return build3 (COND_EXPR, void_type_node, cond, NULL, NULL); } -/* Build - DECL = objc_exception_extract(&_stack); -*/ - +/* Build: + + DECL = objc_exception_extract(&_stack); */ + static tree next_sjlj_build_exc_extract (tree decl) { @@ -2984,7 +3598,7 @@ next_sjlj_build_exc_extract (tree decl) t = tree_cons (NULL, t, NULL); t = build_function_call (objc_exception_extract_decl, t); t = convert (TREE_TYPE (decl), t); - t = build (MODIFY_EXPR, void_type_node, decl, t); + t = build2 (MODIFY_EXPR, void_type_node, decl, t); return t; } @@ -3033,9 +3647,9 @@ next_sjlj_build_catch_list (void) t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type))); args = tree_cons (NULL, t, args); t = build_function_call (objc_exception_match_decl, args); - cond = lang_hooks.truthvalue_conversion (t); + cond = c_common_truthvalue_conversion (input_location, t); } - t = build (COND_EXPR, void_type_node, cond, body, NULL); + t = build3 (COND_EXPR, void_type_node, cond, body, NULL); SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); *last = t; @@ -3045,8 +3659,8 @@ next_sjlj_build_catch_list (void) if (!saw_id) { - t = build (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl, - cur_try_context->caught_decl); + t = build2 (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl, + cur_try_context->caught_decl); SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus); append_to_statement_list (t, last); @@ -3063,7 +3677,7 @@ next_sjlj_build_catch_list (void) { struct _objc_exception_data _stack; - id volatile _rethrow = 0; + id _rethrow = 0; try { objc_exception_try_enter (&_stack); @@ -3107,22 +3721,21 @@ next_sjlj_build_try_catch_finally (void) rethrow_decl = objc_create_temporary_var (objc_object_type); cur_try_context->rethrow_decl = rethrow_decl; - TREE_THIS_VOLATILE (rethrow_decl) = 1; TREE_CHAIN (rethrow_decl) = stack_decl; /* Build the outermost variable binding level. */ - bind = build (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); TREE_SIDE_EFFECTS (bind) = 1; /* Initialize rethrow_decl. */ - t = build (MODIFY_EXPR, void_type_node, rethrow_decl, - convert (objc_object_type, null_pointer_node)); + t = build2 (MODIFY_EXPR, void_type_node, rethrow_decl, + convert (objc_object_type, null_pointer_node)); SET_EXPR_LOCATION (t, cur_try_context->try_locus); append_to_statement_list (t, &BIND_EXPR_BODY (bind)); /* Build the outermost TRY_FINALLY_EXPR. */ - try_fin = build (TRY_FINALLY_EXPR, void_type_node, NULL, NULL); + try_fin = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL); SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus); TREE_SIDE_EFFECTS (try_fin) = 1; append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind)); @@ -3132,6 +3745,7 @@ next_sjlj_build_try_catch_finally (void) { tree caught_decl = objc_build_exc_ptr (); catch_seq = build_stmt (BIND_EXPR, caught_decl, NULL, NULL); + TREE_SIDE_EFFECTS (catch_seq) = 1; t = next_sjlj_build_exc_extract (caught_decl); append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); @@ -3155,7 +3769,8 @@ next_sjlj_build_try_catch_finally (void) /* Build the complete FINALLY statement list. */ t = next_sjlj_build_try_exit (); t = build_stmt (COND_EXPR, - lang_hooks.truthvalue_conversion (rethrow_decl), + c_common_truthvalue_conversion + (input_location, rethrow_decl), NULL, t); SET_EXPR_LOCATION (t, cur_try_context->finally_locus); append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); @@ -3166,7 +3781,8 @@ next_sjlj_build_try_catch_finally (void) t = tree_cons (NULL, rethrow_decl, NULL); t = build_function_call (objc_exception_throw_decl, t); t = build_stmt (COND_EXPR, - lang_hooks.truthvalue_conversion (rethrow_decl), + c_common_truthvalue_conversion (input_location, + rethrow_decl), t, NULL); SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus); append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); @@ -3180,7 +3796,7 @@ next_sjlj_build_try_catch_finally (void) void objc_begin_try_stmt (location_t try_locus, tree body) { - struct objc_try_context *c = xcalloc (1, sizeof (*c)); + struct objc_try_context *c = XCNEW (struct objc_try_context); c->outer = cur_try_context; c->try_body = body; c->try_locus = try_locus; @@ -3188,12 +3804,15 @@ objc_begin_try_stmt (location_t try_locus, tree body) cur_try_context = c; objc_init_exceptions (); + + if (flag_objc_sjlj_exceptions) + 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 binding level open while the body of the compound statement is parsed. */ - + void objc_begin_catch_clause (tree decl) { @@ -3233,11 +3852,11 @@ objc_begin_catch_clause (tree decl) t = CATCH_TYPES (stmt); if (t == error_mark_node) continue; - if (!t || objc_comptypes (TREE_TYPE (t), TREE_TYPE (type), 0) == 1) + if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type))) { - warning ("exception of type %<%T%> will be caught", + warning (0, "exception of type %<%T%> will be caught", TREE_TYPE (type)); - warning ("%H by earlier handler for %<%T%>", + warning (0, "%H by earlier handler for %<%T%>", EXPR_LOCUS (stmt), TREE_TYPE (t ? t : objc_object_type)); break; } @@ -3252,7 +3871,7 @@ objc_begin_catch_clause (tree decl) /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ t = objc_build_exc_ptr (); t = convert (TREE_TYPE (decl), t); - t = build (MODIFY_EXPR, void_type_node, decl, t); + t = build2 (MODIFY_EXPR, void_type_node, decl, t); add_stmt (t); } @@ -3283,7 +3902,7 @@ objc_build_finally_clause (location_t finally_locus, tree body) /* Called to finalize a @try construct. */ -void +tree objc_finish_try_stmt (void) { struct objc_try_context *c = cur_try_context; @@ -3295,12 +3914,15 @@ objc_finish_try_stmt (void) /* If we're doing Darwin setjmp exceptions, build the big nasty. */ if (flag_objc_sjlj_exceptions) { + bool save = in_late_binary_op; + in_late_binary_op = true; if (!cur_try_context->finally_body) { cur_try_context->finally_locus = input_location; cur_try_context->end_finally_locus = input_location; } stmt = next_sjlj_build_try_catch_finally (); + in_late_binary_op = save; } else { @@ -3321,6 +3943,7 @@ objc_finish_try_stmt (void) cur_try_context = c->outer; free (c); + return stmt; } tree @@ -3352,7 +3975,7 @@ objc_build_throw_stmt (tree throw_expr) return add_stmt (build_function_call (objc_exception_throw_decl, args)); } -void +tree objc_build_synchronized (location_t start_locus, tree mutex, tree body) { tree args, call; @@ -3372,7 +3995,7 @@ objc_build_synchronized (location_t start_locus, tree mutex, tree body) /* Put the that and the body in a TRY_FINALLY. */ objc_begin_try_stmt (start_locus, body); objc_build_finally_clause (input_location, call); - objc_finish_try_stmt (); + return objc_finish_try_stmt (); } @@ -3380,19 +4003,16 @@ objc_build_synchronized (location_t start_locus, tree mutex, tree body) struct _objc_exception_data { - int buf[_JBLEN]; + int buf[OBJC_JBLEN]; void *pointers[4]; }; */ /* The following yuckiness should prevent users from having to #include in their code... */ -#ifdef TARGET_POWERPC -/* snarfed from /usr/include/ppc/setjmp.h */ -#define _JBLEN (26 + 36 + 129 + 1) -#else -/* snarfed from /usr/include/i386/{setjmp,signal}.h */ -#define _JBLEN 18 +/* Define to a harmless positive value so the below code doesn't die. */ +#ifndef OBJC_JBLEN +#define OBJC_JBLEN 18 #endif static void @@ -3401,11 +4021,11 @@ build_next_objc_exception_stuff (void) tree field_decl, field_decl_chain, index, temp_type; objc_exception_data_template - = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); + = objc_start_struct (get_identifier (UTAG_EXCDATA)); - /* int buf[_JBLEN]; */ + /* int buf[OBJC_JBLEN]; */ - index = build_index_type (build_int_cst (NULL_TREE, _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), "buf"); field_decl_chain = field_decl; @@ -3417,14 +4037,14 @@ build_next_objc_exception_stuff (void) "pointers"); chainon (field_decl_chain, field_decl); - finish_struct (objc_exception_data_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_exception_data_template, field_decl_chain); /* int _setjmp(...); */ /* If the user includes , this shall be superseded by 'int _setjmp(jmp_buf);' */ temp_type = build_function_type (integer_type_node, NULL_TREE); objc_setjmp_decl - = builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + = add_builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); /* id objc_exception_extract(struct _objc_exception_data *); */ temp_type @@ -3433,7 +4053,8 @@ build_next_objc_exception_stuff (void) build_pointer_type (objc_exception_data_template), OBJC_VOID_AT_END)); objc_exception_extract_decl - = builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + = add_builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); /* void objc_exception_try_enter(struct _objc_exception_data *); */ /* void objc_exception_try_exit(struct _objc_exception_data *); */ temp_type @@ -3442,18 +4063,61 @@ build_next_objc_exception_stuff (void) build_pointer_type (objc_exception_data_template), OBJC_VOID_AT_END)); objc_exception_try_enter_decl - = builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + = add_builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); objc_exception_try_exit_decl - = builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + = add_builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); /* int objc_exception_match(id, id); */ - temp_type + temp_type = build_function_type (integer_type_node, tree_cons (NULL_TREE, objc_object_type, tree_cons (NULL_TREE, objc_object_type, OBJC_VOID_AT_END))); objc_exception_match_decl - = builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + = add_builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); + + /* id objc_assign_ivar (id, id, unsigned int); */ + /* id objc_assign_ivar_Fast (id, id, unsigned int) + __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */ + 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, + unsigned_type_node, + OBJC_VOID_AT_END)))); + objc_assign_ivar_decl + = add_builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); +#ifdef OFFS_ASSIGNIVAR_FAST + objc_assign_ivar_fast_decl + = add_builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0, + NOT_BUILT_IN, NULL, NULL_TREE); + DECL_ATTRIBUTES (objc_assign_ivar_fast_decl) + = tree_cons (get_identifier ("hard_coded_address"), + build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST), + NULL_TREE); +#else + /* Default to slower ivar method. */ + objc_assign_ivar_fast_decl = objc_assign_ivar_decl; +#endif + + /* id objc_assign_global (id, id *); */ + /* id objc_assign_strongCast (id, id *); */ + temp_type = build_function_type (objc_object_type, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, build_pointer_type (objc_object_type), + OBJC_VOID_AT_END))); + objc_assign_global_decl + = add_builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); + objc_assign_strong_cast_decl + = add_builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); } static void @@ -3471,48 +4135,38 @@ build_objc_exception_stuff (void) tree_cons (NULL_TREE, objc_object_type, OBJC_VOID_AT_END)); objc_exception_throw_decl - = builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, - noreturn_list); + = add_builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, + noreturn_list); objc_sync_enter_decl - = builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, - NULL, nothrow_list); + = add_builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, + NULL, nothrow_list); objc_sync_exit_decl - = builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, - NULL, nothrow_list); + = add_builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, + NULL, nothrow_list); } +/* Construct a C struct corresponding to ObjC class CLASS, with the same + name as the class: -/* struct { + struct { struct _objc_class *isa; ... }; */ -static tree -build_private_template (tree class) +static void +build_private_template (tree klass) { - tree ivar_context; - - if (CLASS_STATIC_TEMPLATE (class)) - { - uprivate_record = CLASS_STATIC_TEMPLATE (class); - ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class)); - } - else + if (!CLASS_STATIC_TEMPLATE (klass)) { - uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class)); - ivar_context = get_class_ivars (class); - - finish_struct (uprivate_record, ivar_context, NULL_TREE); - - CLASS_STATIC_TEMPLATE (class) = uprivate_record; + tree record = objc_build_struct (klass, + get_class_ivars (klass, false), + CLASS_SUPER_NAME (klass)); - /* mark this record as class template - for class type checking */ - TREE_STATIC_TEMPLATE (uprivate_record) = 1; + /* Set the TREE_USED bit for this struct, so that stab generator + can emit stabs for this struct type. */ + if (flag_debug_only_used_symbols && TYPE_STUB_DECL (record)) + TREE_USED (TYPE_STUB_DECL (record)) = 1; } - - objc_instance_type = build_pointer_type (uprivate_record); - - return ivar_context; } /* Begin code generation for protocols... */ @@ -3530,8 +4184,7 @@ build_protocol_template (void) { tree field_decl, field_decl_chain; - objc_protocol_template = start_struct (RECORD_TYPE, - get_identifier (UTAG_PROTOCOL)); + objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL)); /* struct _objc_class *isa; */ field_decl = create_field_decl (build_pointer_type @@ -3549,25 +4202,19 @@ build_protocol_template (void) (build_pointer_type (objc_protocol_template)), "protocol_list"); - chainon (field_decl_chain, field_decl); - - /* struct objc_method_list *instance_methods; */ - field_decl = create_field_decl (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier - (UTAG_METHOD_PROTOTYPE_LIST))), + chainon (field_decl_chain, field_decl); + + /* struct _objc__method_prototype_list *instance_methods; */ + field_decl = create_field_decl (objc_method_proto_list_ptr, "instance_methods"); chainon (field_decl_chain, field_decl); - /* struct objc_method_list *class_methods; */ - field_decl = create_field_decl (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier - (UTAG_METHOD_PROTOTYPE_LIST))), + /* struct _objc__method_prototype_list *class_methods; */ + field_decl = create_field_decl (objc_method_proto_list_ptr, "class_methods"); chainon (field_decl_chain, field_decl); - finish_struct (objc_protocol_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_protocol_template, field_decl_chain); } static tree @@ -3617,7 +4264,7 @@ build_method_prototype_list_template (tree list_type, int size) /* Generate an unnamed struct definition. */ - objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); + objc_ivar_list_record = objc_start_struct (NULL_TREE); /* int method_count; */ field_decl = create_field_decl (integer_type_node, "method_count"); @@ -3631,7 +4278,7 @@ build_method_prototype_list_template (tree list_type, int size) "method_list"); chainon (field_decl_chain, field_decl); - finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_ivar_list_record, field_decl_chain); return objc_ivar_list_record; } @@ -3642,8 +4289,7 @@ build_method_prototype_template (void) tree proto_record; tree field_decl, field_decl_chain; - proto_record - = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE)); + proto_record = objc_start_struct (get_identifier (UTAG_METHOD_PROTOTYPE)); /* SEL _cmd; */ field_decl = create_field_decl (objc_selector_type, "_cmd"); @@ -3653,7 +4299,7 @@ build_method_prototype_template (void) field_decl = create_field_decl (string_type_node, "method_types"); chainon (field_decl_chain, field_decl); - finish_struct (proto_record, field_decl_chain, NULL_TREE); + objc_finish_struct (proto_record, field_decl_chain); return proto_record; } @@ -3664,7 +4310,7 @@ objc_method_parm_type (tree type) type = TREE_VALUE (TREE_TYPE (type)); if (TREE_CODE (type) == TYPE_DECL) type = TREE_TYPE (type); - return TYPE_MAIN_VARIANT (type); + return type; } static int @@ -3713,8 +4359,8 @@ encode_method_prototype (tree method_decl) /* If a type size is not known, bail out. */ if (sz < 0) { - error ("%Jtype '%D' does not have a known size", - type, type); + error ("type %q+D does not have a known size", + type); /* Pretend that the encoding succeeded; the compilation will fail nevertheless. */ goto finish_encoding; @@ -3748,7 +4394,7 @@ encode_method_prototype (tree method_decl) finish_encoding: obstack_1grow (&util_obstack, '\0'); - result = get_identifier (obstack_finish (&util_obstack)); + result = get_identifier (XOBFINISH (&util_obstack, char *)); obstack_free (&util_obstack, util_firstobj); return result; } @@ -3842,6 +4488,136 @@ generate_protocol_references (tree plist) } } +/* Generate either '- .cxx_construct' or '- .cxx_destruct' for the + current class. */ +#ifdef OBJCPLUS +static void +objc_generate_cxx_ctor_or_dtor (bool dtor) +{ + tree fn, body, compound_stmt, ivar; + + /* - (id) .cxx_construct { ... return self; } */ + /* - (void) .cxx_construct { ... } */ + + objc_set_method_type (MINUS_EXPR); + objc_start_method_definition + (objc_build_method_signature (build_tree_list (NULL_TREE, + dtor + ? void_type_node + : objc_object_type), + get_identifier (dtor + ? TAG_CXX_DESTRUCT + : TAG_CXX_CONSTRUCT), + make_node (TREE_LIST), + false)); + body = begin_function_body (); + compound_stmt = begin_compound_stmt (0); + + ivar = CLASS_IVARS (implementation_template); + /* Destroy ivars in reverse order. */ + if (dtor) + ivar = nreverse (copy_list (ivar)); + + for (; ivar; ivar = TREE_CHAIN (ivar)) + { + if (TREE_CODE (ivar) == FIELD_DECL) + { + tree type = TREE_TYPE (ivar); + + /* Call the ivar's default constructor or destructor. Do not + call the destructor unless a corresponding constructor call + has also been made (or is not needed). */ + if (MAYBE_CLASS_TYPE_P (type) + && (dtor + ? (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + && (!TYPE_NEEDS_CONSTRUCTING (type) + || TYPE_HAS_DEFAULT_CONSTRUCTOR (type))) + : (TYPE_NEEDS_CONSTRUCTING (type) + && TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))) + finish_expr_stmt + (build_special_member_call + (build_ivar_reference (DECL_NAME (ivar)), + dtor ? complete_dtor_identifier : complete_ctor_identifier, + NULL, type, LOOKUP_NORMAL, tf_warning_or_error)); + } + } + + /* The constructor returns 'self'. */ + if (!dtor) + finish_return_stmt (self_decl); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + fn = current_function_decl; + finish_function (); + objc_finish_method_definition (fn); +} + +/* The following routine will examine the current @interface for any + non-POD C++ ivars requiring non-trivial construction and/or + destruction, and then synthesize special '- .cxx_construct' and/or + '- .cxx_destruct' methods which will run the appropriate + construction or destruction code. Note that ivars inherited from + super-classes are _not_ considered. */ +static void +objc_generate_cxx_cdtors (void) +{ + bool need_ctor = false, need_dtor = false; + tree ivar; + + /* We do not want to do this for categories, since they do not have + their own ivars. */ + + if (TREE_CODE (objc_implementation_context) != CLASS_IMPLEMENTATION_TYPE) + return; + + /* First, determine if we even need a constructor and/or destructor. */ + + for (ivar = CLASS_IVARS (implementation_template); ivar; + ivar = TREE_CHAIN (ivar)) + { + if (TREE_CODE (ivar) == FIELD_DECL) + { + tree type = TREE_TYPE (ivar); + + if (MAYBE_CLASS_TYPE_P (type)) + { + if (TYPE_NEEDS_CONSTRUCTING (type) + && TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) + /* NB: If a default constructor is not available, we will not + be able to initialize this ivar; the add_instance_variable() + routine will already have warned about this. */ + need_ctor = true; + + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + && (!TYPE_NEEDS_CONSTRUCTING (type) + || TYPE_HAS_DEFAULT_CONSTRUCTOR (type))) + /* NB: If a default constructor is not available, we will not + call the destructor either, for symmetry. */ + need_dtor = true; + } + } + } + + /* Generate '- .cxx_construct' if needed. */ + + if (need_ctor) + objc_generate_cxx_ctor_or_dtor (false); + + /* Generate '- .cxx_destruct' if needed. */ + + if (need_dtor) + objc_generate_cxx_ctor_or_dtor (true); + + /* The 'imp_list' variable points at an imp_entry record for the current + @implementation. Record the existence of '- .cxx_construct' and/or + '- .cxx_destruct' methods therein; it will be included in the + metadata for the class. */ + if (flag_next_runtime) + imp_list->has_cxx_cdtors = (need_ctor || need_dtor); +} +#endif + /* For each protocol which was referenced either from a @protocol() expression, or because a class/category implements it (then a pointer to the protocol is stored in the struct describing the @@ -3939,7 +4715,8 @@ generate_protocols (void) if (refs_decl) refs_expr = convert (build_pointer_type (build_pointer_type (objc_protocol_template)), - build_unary_op (ADDR_EXPR, refs_decl, 0)); + build_unary_op (input_location, + ADDR_EXPR, refs_decl, 0)); else refs_expr = build_int_cst (NULL_TREE, 0); @@ -3975,7 +4752,9 @@ build_protocol_initializer (tree type, tree protocol_name, initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); else { - expr = build_unary_op (ADDR_EXPR, instance_methods, 0); + expr = convert (objc_method_proto_list_ptr, + build_unary_op (input_location, + ADDR_EXPR, instance_methods, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -3983,7 +4762,9 @@ build_protocol_initializer (tree type, tree protocol_name, initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); else { - expr = build_unary_op (ADDR_EXPR, class_methods, 0); + expr = convert (objc_method_proto_list_ptr, + build_unary_op (input_location, + ADDR_EXPR, class_methods, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -4003,8 +4784,7 @@ build_category_template (void) { tree field_decl, field_decl_chain; - objc_category_template = start_struct (RECORD_TYPE, - get_identifier (UTAG_CATEGORY)); + objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY)); /* char *category_name; */ field_decl = create_field_decl (string_type_node, "category_name"); @@ -4015,18 +4795,12 @@ build_category_template (void) chainon (field_decl_chain, field_decl); /* struct _objc_method_list *instance_methods; */ - field_decl = create_field_decl (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier - (UTAG_METHOD_LIST))), + field_decl = create_field_decl (objc_method_list_ptr, "instance_methods"); chainon (field_decl_chain, field_decl); /* struct _objc_method_list *class_methods; */ - field_decl = create_field_decl (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier - (UTAG_METHOD_LIST))), + field_decl = create_field_decl (objc_method_list_ptr, "class_methods"); chainon (field_decl_chain, field_decl); @@ -4037,7 +4811,7 @@ build_category_template (void) "protocol_list"); chainon (field_decl_chain, field_decl); - finish_struct (objc_category_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_category_template, field_decl_chain); } /* struct _objc_selector { @@ -4048,11 +4822,9 @@ build_category_template (void) static void build_selector_template (void) { - tree field_decl, field_decl_chain; - objc_selector_template - = start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR)); + objc_selector_template = objc_start_struct (get_identifier (UTAG_SELECTOR)); /* SEL sel_id; */ field_decl = create_field_decl (objc_selector_type, "sel_id"); @@ -4062,7 +4834,7 @@ build_selector_template (void) field_decl = create_field_decl (string_type_node, "sel_type"); chainon (field_decl_chain, field_decl); - finish_struct (objc_selector_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_selector_template, field_decl_chain); } /* struct _objc_class { @@ -4098,8 +4870,7 @@ build_class_template (void) { tree field_decl, field_decl_chain; - objc_class_template - = start_struct (RECORD_TYPE, get_identifier (UTAG_CLASS)); + objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS)); /* struct _objc_class *isa; */ field_decl = create_field_decl (build_pointer_type (objc_class_template), @@ -4128,18 +4899,12 @@ build_class_template (void) chainon (field_decl_chain, field_decl); /* struct _objc_ivar_list *ivars; */ - field_decl = create_field_decl (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier - (UTAG_IVAR_LIST))), + field_decl = create_field_decl (objc_ivar_list_ptr, "ivars"); chainon (field_decl_chain, field_decl); /* struct _objc_method_list *methods; */ - field_decl = create_field_decl (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier - (UTAG_METHOD_LIST))), + field_decl = create_field_decl (objc_method_list_ptr, "methods"); chainon (field_decl_chain, field_decl); @@ -4198,7 +4963,7 @@ build_class_template (void) "gc_object_type"); chainon (field_decl_chain, field_decl); - finish_struct (objc_class_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_class_template, field_decl_chain); } /* Generate appropriate forward declarations for an implementation. */ @@ -4219,15 +4984,15 @@ synth_forward_declarations (void) /* Pre-build the following entities - for speed/convenience. */ an_id = get_identifier ("super_class"); - ucls_super_ref = build_component_ref (UOBJC_CLASS_decl, an_id); - uucls_super_ref = build_component_ref (UOBJC_METACLASS_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); } static void error_with_ivar (const char *message, tree decl) { error ("%J%s %qs", decl, - message, gen_declaration (decl)); + message, identifier_to_locale (gen_declaration (decl))); } @@ -4299,7 +5064,7 @@ build_super_template (void) { tree field_decl, field_decl_chain; - objc_super_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); + objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER)); /* struct _objc_object *self; */ field_decl = create_field_decl (objc_object_type, "self"); @@ -4310,7 +5075,7 @@ build_super_template (void) "super_class"); chainon (field_decl_chain, field_decl); - finish_struct (objc_super_template, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_super_template, field_decl_chain); } /* struct _objc_ivar { @@ -4326,7 +5091,7 @@ build_ivar_template (void) tree field_decl, field_decl_chain; objc_ivar_id = get_identifier (UTAG_IVAR); - objc_ivar_record = start_struct (RECORD_TYPE, objc_ivar_id); + objc_ivar_record = objc_start_struct (objc_ivar_id); /* char *ivar_name; */ field_decl = create_field_decl (string_type_node, "ivar_name"); @@ -4340,7 +5105,7 @@ build_ivar_template (void) field_decl = create_field_decl (integer_type_node, "ivar_offset"); chainon (field_decl_chain, field_decl); - finish_struct (objc_ivar_record, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_ivar_record, field_decl_chain); return objc_ivar_record; } @@ -4356,7 +5121,7 @@ build_ivar_list_template (tree list_type, int size) tree objc_ivar_list_record; tree field_decl, field_decl_chain; - objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); + objc_ivar_list_record = objc_start_struct (NULL_TREE); /* int ivar_count; */ field_decl = create_field_decl (integer_type_node, "ivar_count"); @@ -4370,7 +5135,7 @@ build_ivar_list_template (tree list_type, int size) "ivar_list"); chainon (field_decl_chain, field_decl); - finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_ivar_list_record, field_decl_chain); return objc_ivar_list_record; } @@ -4387,13 +5152,10 @@ build_method_list_template (tree list_type, int size) tree objc_ivar_list_record; tree field_decl, field_decl_chain; - objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); + objc_ivar_list_record = objc_start_struct (NULL_TREE); /* struct _objc__method_prototype_list *method_next; */ - field_decl = create_field_decl (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier - (UTAG_METHOD_PROTOTYPE_LIST))), + field_decl = create_field_decl (objc_method_proto_list_ptr, "method_next"); field_decl_chain = field_decl; @@ -4409,7 +5171,7 @@ build_method_list_template (tree list_type, int size) "method_list"); chainon (field_decl_chain, field_decl); - finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); + objc_finish_struct (objc_ivar_list_record, field_decl_chain); return objc_ivar_list_record; } @@ -4443,7 +5205,7 @@ build_ivar_list_initializer (tree type, tree field_decl) ivar = tree_cons (NULL_TREE, - add_objc_string (get_identifier (obstack_finish (&util_obstack)), + add_objc_string (get_identifier (XOBFINISH (&util_obstack, char *)), meth_var_types), ivar); obstack_free (&util_obstack, util_firstobj); @@ -4482,6 +5244,7 @@ generate_ivars_list (tree type, const char *name, int size, tree list) } /* Count only the fields occurring in T. */ + static int ivar_list_length (tree t) { @@ -4565,8 +5328,8 @@ build_dispatch_table_initializer (tree type, tree entries) elemlist = tree_cons (NULL_TREE, - convert (ptr_type_node, - build_unary_op (ADDR_EXPR, + convert (ptr_type_node, + build_unary_op (input_location, ADDR_EXPR, METHOD_DEFINITION (entries), 1)), elemlist); @@ -4596,7 +5359,7 @@ build_method_template (void) tree _SLT_record; tree field_decl, field_decl_chain; - _SLT_record = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD)); + _SLT_record = objc_start_struct (get_identifier (UTAG_METHOD)); /* SEL _cmd; */ field_decl = create_field_decl (objc_selector_type, "_cmd"); @@ -4611,7 +5374,7 @@ build_method_template (void) "_imp"); chainon (field_decl_chain, field_decl); - finish_struct (_SLT_record, field_decl_chain, NULL_TREE); + objc_finish_struct (_SLT_record, field_decl_chain); return _SLT_record; } @@ -4750,7 +5513,8 @@ generate_protocol_list (tree i_or_p) if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE && PROTOCOL_FORWARD_DECL (pval)) { - e = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (pval), 0); + e = build_unary_op (input_location, ADDR_EXPR, + PROTOCOL_FORWARD_DECL (pval), 0); initlist = tree_cons (NULL_TREE, e, initlist); } } @@ -4792,14 +5556,18 @@ build_category_initializer (tree type, tree cat_name, tree class_name, initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); else { - expr = build_unary_op (ADDR_EXPR, instance_methods, 0); + expr = convert (objc_method_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + instance_methods, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } if (!class_methods) initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); else { - expr = build_unary_op (ADDR_EXPR, class_methods, 0); + expr = convert (objc_method_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + class_methods, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -4809,9 +5577,10 @@ build_category_initializer (tree type, tree cat_name, tree class_name, else { expr = convert (build_pointer_type - (build_pointer_type + (build_pointer_type (objc_protocol_template)), - build_unary_op (ADDR_EXPR, protocol_list, 0)); + build_unary_op (input_location, ADDR_EXPR, + protocol_list, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -4875,7 +5644,9 @@ build_shared_structure_initializer (tree type, tree isa, tree super, initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); else { - expr = build_unary_op (ADDR_EXPR, ivar_list, 0); + expr = convert (objc_ivar_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + ivar_list, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -4884,7 +5655,9 @@ build_shared_structure_initializer (tree type, tree isa, tree super, initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); else { - expr = build_unary_op (ADDR_EXPR, dispatch_table, 0); + expr = convert (objc_method_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + dispatch_table, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -4909,9 +5682,10 @@ build_shared_structure_initializer (tree type, tree isa, tree super, else { expr = convert (build_pointer_type - (build_pointer_type + (build_pointer_type (objc_protocol_template)), - build_unary_op (ADDR_EXPR, protocol_list, 0)); + build_unary_op (input_location, ADDR_EXPR, + protocol_list, 0)); initlist = tree_cons (NULL_TREE, expr, initlist); } @@ -4928,9 +5702,9 @@ build_shared_structure_initializer (tree type, tree isa, tree super, /* Retrieve category interface CAT_NAME (if any) associated with CLASS. */ static inline tree -lookup_category (tree class, tree cat_name) +lookup_category (tree klass, tree cat_name) { - tree category = CLASS_CATEGORY_LIST (class); + tree category = CLASS_CATEGORY_LIST (klass); while (category && CLASS_SUPER_NAME (category) != cat_name) category = CLASS_CATEGORY_LIST (category); @@ -4979,7 +5753,7 @@ generate_category (tree cat) static struct objc_class _OBJC_CLASS_Foo={ ... }; */ static void -generate_shared_structures (void) +generate_shared_structures (int cls_flags) { tree sc_spec, decl_specs, decl; tree name_expr, super_expr, root_expr; @@ -5065,12 +5839,12 @@ generate_shared_structures (void) initlist = build_shared_structure_initializer (TREE_TYPE (decl), - build_unary_op (ADDR_EXPR, UOBJC_METACLASS_decl, 0), + build_unary_op (input_location, ADDR_EXPR, UOBJC_METACLASS_decl, 0), super_expr, name_expr, convert (integer_type_node, TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE (implementation_template))), - 1 /*CLS_FACTORY*/, + 1 /*CLS_FACTORY*/ | cls_flags, UOBJC_INSTANCE_METHODS_decl, UOBJC_INSTANCE_VARIABLES_decl, protocol_decl); @@ -5221,7 +5995,7 @@ build_keyword_selector (tree selector) static tree build_method_decl (enum tree_code code, tree ret_type, tree selector, - tree add_args) + tree add_args, bool ellipsis) { tree method_decl; @@ -5238,6 +6012,7 @@ build_method_decl (enum tree_code code, tree ret_type, tree selector, METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector); METHOD_SEL_ARGS (method_decl) = selector; METHOD_ADD_ARGS (method_decl) = add_args; + METHOD_ADD_ARGS_ELLIPSIS_P (method_decl) = ellipsis; } else { @@ -5286,6 +6061,12 @@ get_arg_type_list (tree meth, int context, int superflag) { tree arg_type = TREE_VALUE (TREE_TYPE (akey)); + /* Decay arrays and functions into pointers. */ + if (TREE_CODE (arg_type) == ARRAY_TYPE) + arg_type = build_pointer_type (TREE_TYPE (arg_type)); + else if (TREE_CODE (arg_type) == FUNCTION_TYPE) + arg_type = build_pointer_type (arg_type); + chainon (arglist, build_tree_list (NULL_TREE, arg_type)); } @@ -5299,7 +6080,7 @@ get_arg_type_list (tree meth, int context, int superflag) chainon (arglist, build_tree_list (NULL_TREE, arg_type)); } - if (!TREE_OVERFLOW (METHOD_ADD_ARGS (meth))) + if (!METHOD_ADD_ARGS_ELLIPSIS_P (meth)) goto lack_of_ellipsis; } else @@ -5326,22 +6107,51 @@ check_duplicates (hash hsh, int methods, int is_class) different types. */ attr loop; - warning ("multiple %s named %<%c%s%> found", - methods ? "methods" : "selectors", - (is_class ? '+' : '-'), - IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); + /* But just how different are those types? If + -Wno-strict-selector-match is specified, we shall not + complain if the differences are solely among types with + identical size and alignment. */ + if (!warn_strict_selector_match) + { + for (loop = hsh->list; loop; loop = loop->next) + if (!comp_proto_with_proto (meth, loop->value, 0)) + goto issue_warning; + + return meth; + } + + issue_warning: + if (methods) + { + bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL; + + warning (0, "multiple methods named %<%c%E%> found", + (is_class ? '+' : '-'), + METHOD_SEL_NAME (meth)); + inform (0, "%Jusing %<%c%s%>", meth, + (type ? '-' : '+'), + identifier_to_locale (gen_method_decl (meth))); + } + else + { + bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL; + + warning (0, "multiple selectors named %<%c%E%> found", + (is_class ? '+' : '-'), + METHOD_SEL_NAME (meth)); + inform (0, "%Jfound %<%c%s%>", meth, + (type ? '-' : '+'), + identifier_to_locale (gen_method_decl (meth))); + } - warn_with_method (methods ? "using" : "found", - ((TREE_CODE (meth) == INSTANCE_METHOD_DECL) - ? '-' - : '+'), - meth); for (loop = hsh->list; loop; loop = loop->next) - warn_with_method ("also found", - ((TREE_CODE (loop->value) == INSTANCE_METHOD_DECL) - ? '-' - : '+'), - loop->value); + { + bool type = TREE_CODE (loop->value) == INSTANCE_METHOD_DECL; + + inform (0, "%Jalso found %<%c%s%>", loop->value, + (type ? '-' : '+'), + identifier_to_locale (gen_method_decl (loop->value))); + } } } return meth; @@ -5379,7 +6189,7 @@ receiver_is_class_object (tree receiver, int self, int super) /* The receiver is a function call that returns an id. Check if it is a call to objc_getClass, if so, pick up the class name. */ if (TREE_CODE (receiver) == CALL_EXPR - && (exp = TREE_OPERAND (receiver, 0)) + && (exp = CALL_EXPR_FN (receiver)) && TREE_CODE (exp) == ADDR_EXPR && (exp = TREE_OPERAND (exp, 0)) && TREE_CODE (exp) == FUNCTION_DECL @@ -5389,9 +6199,7 @@ receiver_is_class_object (tree receiver, int self, int super) && TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl) && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS) /* We have a call to objc_get_class/objc_getClass! */ - && (arg = TREE_OPERAND (receiver, 1)) - && TREE_CODE (arg) == TREE_LIST - && (arg = TREE_VALUE (arg))) + && (arg = CALL_EXPR_ARG (receiver, 0))) { STRIP_NOPS (arg); if (TREE_CODE (arg) == ADDR_EXPR @@ -5496,7 +6304,7 @@ lookup_method_in_hash_lists (tree sel_name, int is_class) if (!is_class) method_prototype = hash_lookup (nst_method_hash_list, sel_name); - + if (!method_prototype) { method_prototype = hash_lookup (cls_method_hash_list, @@ -5525,8 +6333,7 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) rtype = receiver; while (TREE_CODE (rtype) == COMPOUND_EXPR || TREE_CODE (rtype) == MODIFY_EXPR - || TREE_CODE (rtype) == NOP_EXPR - || TREE_CODE (rtype) == CONVERT_EXPR + || CONVERT_EXPR_P (rtype) || TREE_CODE (rtype) == COMPONENT_REF) rtype = TREE_OPERAND (rtype, 0); self = (rtype == self_decl); @@ -5536,6 +6343,10 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) || (TREE_CODE (receiver) == COMPOUND_EXPR && !IS_SUPER (rtype))); + /* If we are calling [super dealloc], reset our warning flag. */ + if (super && !strcmp ("dealloc", IDENTIFIER_POINTER (sel_name))) + should_call_super_dealloc = 0; + /* If the receiver is a class object, retrieve the corresponding @interface, if one exists. */ class_tree = receiver_is_class_object (receiver, self, super); @@ -5551,8 +6362,8 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) { if (!CLASS_SUPER_NAME (implementation_template)) { - error ("no super class declared in @interface for %qs", - IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); + error ("no super class declared in @interface for %qE", + CLASS_NAME (implementation_template)); return error_mark_node; } rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template)); @@ -5564,16 +6375,13 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) /* If receiver is of type `id' or `Class' (or if the @interface for a class is not visible), we shall be satisfied with the existence of any instance or class method. */ - if (!rtype || objc_is_id (rtype)) + if (objc_is_id (rtype)) { - if (!rtype) - rtype = xref_tag (RECORD_TYPE, class_tree); - else - { - class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE); - rprotos = TYPE_PROTOCOL_LIST (rtype); - rtype = NULL_TREE; - } + class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE); + rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype)) + ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype)) + : NULL_TREE); + rtype = NULL_TREE; if (rprotos) { @@ -5592,13 +6400,12 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) = lookup_method_in_protocol_list (rprotos, sel_name, 0); if (method_prototype) - warning ("found %<-%s%> instead of %<+%s%> in protocol(s)", - IDENTIFIER_POINTER (sel_name), - IDENTIFIER_POINTER (sel_name)); + warning (0, "found %<-%E%> instead of %<+%E%> in protocol(s)", + sel_name, sel_name); } } } - else + else if (rtype) { tree orig_rtype = rtype, saved_rtype; @@ -5612,15 +6419,15 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) saved_rtype = rtype; if (TYPED_OBJECT (rtype)) { - rprotos = TYPE_PROTOCOL_LIST (rtype); - rtype = lookup_interface (OBJC_TYPE_NAME (rtype)); + rprotos = TYPE_OBJC_PROTOCOL_LIST (rtype); + rtype = TYPE_OBJC_INTERFACE (rtype); } /* If we could not find an @interface declaration, we must have only seen a @class declaration; so, we cannot say anything more intelligent about which methods the receiver will understand. */ - if (!rtype) - rtype = saved_rtype; + if (!rtype || TREE_CODE (rtype) == IDENTIFIER_NODE) + rtype = NULL_TREE; else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE) { @@ -5634,7 +6441,7 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) exist locally as part of the @implementation. */ if (!method_prototype && objc_implementation_context && CLASS_NAME (objc_implementation_context) - == OBJC_TYPE_NAME (rtype)) + == OBJC_TYPE_NAME (rtype)) method_prototype = lookup_method ((class_tree @@ -5651,13 +6458,13 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) } else { - warning ("invalid receiver type %qs", - gen_type_name (orig_rtype)); + warning (0, "invalid receiver type %qs", + identifier_to_locale (gen_type_name (orig_rtype))); /* After issuing the "invalid receiver" warning, perform method lookup as if we were messaging 'id'. */ rtype = rprotos = NULL_TREE; } - } + } /* For 'id' or 'Class' receivers, search in the global hash table @@ -5666,9 +6473,9 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) if (!method_prototype) { if (rprotos) - warning ("%<%c%s%> not found in protocol(s)", + warning (0, "%<%c%E%> not found in protocol(s)", (class_tree ? '+' : '-'), - IDENTIFIER_POINTER (sel_name)); + sel_name); if (!rtype) method_prototype @@ -5680,23 +6487,23 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) static bool warn_missing_methods = false; if (rtype) - warning ("%qs may not respond to %<%c%s%>", - IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)), + warning (0, "%qE may not respond to %<%c%E%>", + OBJC_TYPE_NAME (rtype), (class_tree ? '+' : '-'), - IDENTIFIER_POINTER (sel_name)); + sel_name); /* If we are messaging an 'id' or 'Class' object and made it here, then we have failed to find _any_ instance or class method, respectively. */ else - warning ("no %<%c%s%> method found", + warning (0, "no %<%c%E%> method found", (class_tree ? '+' : '-'), - IDENTIFIER_POINTER (sel_name)); + sel_name); if (!warn_missing_methods) { - warning ("(Messages without a matching method signature"); - warning ("will be assumed to return % and accept"); - warning ("%<...%> as arguments.)"); + warning (0, "(Messages without a matching method signature"); + warning (0, "will be assumed to return % and accept"); + warning (0, "%<...%> as arguments.)"); warn_missing_methods = true; } } @@ -5735,7 +6542,9 @@ build_objc_method_call (int super_flag, tree method_prototype, { tree sender = (super_flag ? umsg_super_decl : (!flag_next_runtime || flag_nil_receivers - ? umsg_decl + ? (flag_objc_direct_dispatch + ? umsg_fast_decl + : umsg_decl) : umsg_nonnil_decl)); tree rcv_p = (super_flag ? objc_super_type : objc_object_type); @@ -5755,7 +6564,7 @@ build_objc_method_call (int super_flag, tree method_prototype, tree method, t; lookup_object = build_c_cast (rcv_p, lookup_object); - + /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ lookup_object = save_expr (lookup_object); @@ -5785,7 +6594,7 @@ build_objc_method_call (int super_flag, tree method_prototype, /* First, call the lookup function to get a pointer to the method, then cast the pointer, then call it with the method arguments. */ - + object = (super_flag ? self_decl : lookup_object); t = tree_cons (NULL_TREE, selector, NULL_TREE); @@ -5800,7 +6609,7 @@ build_objc_method_call (int super_flag, tree method_prototype, /* ??? Selector is not at this point something we can use inside the compiler itself. Set it to garbage for the nonce. */ - t = build (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node); + t = build3 (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node); return build_function_call (t, method_params); } @@ -5828,15 +6637,16 @@ objc_build_protocol_expr (tree protoname) if (!p) { - error ("cannot find protocol declaration for %qs", - IDENTIFIER_POINTER (protoname)); + error ("cannot find protocol declaration for %qE", + protoname); return error_mark_node; } if (!PROTOCOL_FORWARD_DECL (p)) build_protocol_reference (p); - expr = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); + expr = build_unary_op (input_location, + ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); /* ??? Ideally we'd build the reference with objc_protocol_type directly, if we have it, rather than converting it here. */ @@ -5927,7 +6737,7 @@ objc_build_selector_expr (tree selnamelist) /* If still not found, print out a warning. */ if (!hsh) { - warning ("undeclared selector %qs", IDENTIFIER_POINTER (selname)); + warning (0, "undeclared selector %qE", selname); } } @@ -5947,7 +6757,7 @@ objc_build_encode_expr (tree type) encode_type (type, obstack_object_size (&util_obstack), OBJC_ENCODE_INLINE_DEFS); obstack_1grow (&util_obstack, 0); /* null terminate string */ - string = obstack_finish (&util_obstack); + string = XOBFINISH (&util_obstack, const char *); /* Synthesize a string that represents the encoded struct/union. */ result = my_build_string (strlen (string) + 1, string); @@ -5969,12 +6779,13 @@ build_ivar_reference (tree id) to an instance variable. It's better to catch the cases where this is done unknowingly than to support the above paradigm. */ - warning ("instance variable %qs accessed in class method", - IDENTIFIER_POINTER (id)); + warning (0, "instance variable %qE accessed in class method", + id); self_decl = convert (objc_instance_type, self_decl); /* cast */ } - return build_component_ref (build_indirect_ref (self_decl, "->"), id); + return objc_build_component_ref (build_indirect_ref (input_location, + self_decl, "->"), id); } /* Compute a hash value for a given method SEL_NAME. */ @@ -6002,6 +6813,10 @@ hash_init (void) /* Initialize the hash table used to hold the constant string objects. */ string_htab = htab_create_ggc (31, string_hash, string_eq, NULL); + + /* Initialize the hash table used to hold EH-volatilized types. */ + volatilized_htab = htab_create_ggc (31, volatilized_hash, + volatilized_eq, NULL); } /* WARNING!!!! hash_enter is called with a method, and will peek @@ -6072,11 +6887,23 @@ lookup_method (tree mchain, tree method) return NULL_TREE; } +/* 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. + 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 + 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_ + method of the same name in the root class as a last resort. + + If a suitable method cannot be found, return NULL_TREE. */ + static tree -lookup_method_static (tree interface, tree ident, int is_class) +lookup_method_static (tree interface, tree ident, int flags) { tree meth = NULL_TREE, root_inter = NULL_TREE; tree inter = interface; + int is_class = (flags & OBJC_LOOKUP_CLASS); + int no_superclasses = (flags & OBJC_LOOKUP_NO_SUPER); while (inter) { @@ -6113,6 +6940,10 @@ lookup_method_static (tree interface, tree ident, int is_class) return meth; } + /* If we were instructed not to look in superclasses, don't. */ + if (no_superclasses) + return NULL_TREE; + /* Failing that, climb up the inheritance hierarchy. */ root_inter = inter; inter = lookup_interface (CLASS_SUPER_NAME (inter)); @@ -6128,6 +6959,7 @@ lookup_method_static (tree interface, tree ident, int is_class) /* Add the method to the hash list if it doesn't contain an identical method already. */ + static void add_method_to_hash_list (hash *hash_list, tree method) { @@ -6142,33 +6974,33 @@ add_method_to_hash_list (hash *hash_list, tree method) { /* Check types against those; if different, add to a list. */ attr loop; - int already_there = comp_proto_with_proto (method, hsh->key); + int already_there = comp_proto_with_proto (method, hsh->key, 1); for (loop = hsh->list; !already_there && loop; loop = loop->next) - already_there |= comp_proto_with_proto (method, loop->value); + already_there |= comp_proto_with_proto (method, loop->value, 1); if (!already_there) hash_add_attr (hsh, method); } } static tree -objc_add_method (tree class, tree method, int is_class) +objc_add_method (tree klass, tree method, int is_class) { tree mth; if (!(mth = lookup_method (is_class - ? CLASS_CLS_METHODS (class) - : CLASS_NST_METHODS (class), method))) + ? CLASS_CLS_METHODS (klass) + : CLASS_NST_METHODS (klass), method))) { /* put method on list in reverse order */ if (is_class) { - TREE_CHAIN (method) = CLASS_CLS_METHODS (class); - CLASS_CLS_METHODS (class) = method; + TREE_CHAIN (method) = CLASS_CLS_METHODS (klass); + CLASS_CLS_METHODS (klass) = method; } else { - TREE_CHAIN (method) = CLASS_NST_METHODS (class); - CLASS_NST_METHODS (class) = method; + TREE_CHAIN (method) = CLASS_NST_METHODS (klass); + CLASS_NST_METHODS (klass) = method; } } else @@ -6178,12 +7010,12 @@ objc_add_method (tree class, tree method, int is_class) and/or return types. We do not do this for @implementations, because C/C++ will do it for us (i.e., there will be duplicate function definition errors). */ - if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE - || TREE_CODE (class) == CATEGORY_INTERFACE_TYPE) - && !comp_proto_with_proto (method, mth)) - error ("duplicate declaration of method %<%c%s%>", - is_class ? '+' : '-', - IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); + if ((TREE_CODE (klass) == CLASS_INTERFACE_TYPE + || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE) + && !comp_proto_with_proto (method, mth, 1)) + error ("duplicate declaration of method %<%c%E%>", + is_class ? '+' : '-', + METHOD_SEL_NAME (mth)); } if (is_class) @@ -6197,12 +7029,12 @@ objc_add_method (tree class, tree method, int is_class) instance methods listed in @protocol declarations to the class hash table, on the assumption that @protocols may be adopted by root classes or categories. */ - if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE - || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) - class = lookup_interface (CLASS_NAME (class)); + if (TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE + || TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE) + klass = lookup_interface (CLASS_NAME (klass)); - if (TREE_CODE (class) == PROTOCOL_INTERFACE_TYPE - || !CLASS_SUPER_NAME (class)) + if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE + || !CLASS_SUPER_NAME (klass)) add_method_to_hash_list (cls_method_hash_list, method); } @@ -6210,45 +7042,61 @@ objc_add_method (tree class, tree method, int is_class) } static tree -add_class (tree class) +add_class (tree class_name, tree name) { + struct interface_tuple **slot; + /* Put interfaces on list in reverse order. */ - TREE_CHAIN (class) = interface_chain; - interface_chain = class; + TREE_CHAIN (class_name) = interface_chain; + interface_chain = class_name; + + if (interface_htab == NULL) + interface_htab = htab_create_ggc (31, hash_interface, eq_interface, NULL); + slot = (struct interface_tuple **) + htab_find_slot_with_hash (interface_htab, name, + IDENTIFIER_HASH_VALUE (name), + INSERT); + if (!*slot) + { + *slot = (struct interface_tuple *) ggc_alloc_cleared (sizeof (struct interface_tuple)); + (*slot)->id = name; + } + (*slot)->class_name = class_name; + return interface_chain; } static void -add_category (tree class, tree category) +add_category (tree klass, tree category) { /* Put categories on list in reverse order. */ - tree cat = lookup_category (class, CLASS_SUPER_NAME (category)); + tree cat = lookup_category (klass, CLASS_SUPER_NAME (category)); if (cat) { - warning ("duplicate interface declaration for category %<%s(%s)%>", - IDENTIFIER_POINTER (CLASS_NAME (class)), - IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); + warning (0, "duplicate interface declaration for category %<%E(%E)%>", + CLASS_NAME (klass), + CLASS_SUPER_NAME (category)); } else { - CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); - CLASS_CATEGORY_LIST (class) = category; + CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (klass); + CLASS_CATEGORY_LIST (klass) = category; } } /* Called after parsing each instance variable declaration. Necessary to preserve typedefs and implement public/private... - PUBLIC 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 -add_instance_variable (tree class, int public, tree field_decl) +add_instance_variable (tree klass, int visibility, tree field_decl) { tree field_type = TREE_TYPE (field_decl); const char *ivar_name = DECL_NAME (field_decl) - ? IDENTIFIER_POINTER (DECL_NAME (field_decl)) - : ""; + ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (field_decl))) + : _(""); #ifdef OBJCPLUS if (TREE_CODE (field_type) == REFERENCE_TYPE) @@ -6256,7 +7104,7 @@ add_instance_variable (tree class, int public, tree field_decl) error ("illegal reference type specified for instance variable %qs", ivar_name); /* Return class as is without adding this ivar. */ - return class; + return klass; } #endif @@ -6266,36 +7114,74 @@ add_instance_variable (tree class, int public, tree field_decl) { error ("instance variable %qs has unknown size", ivar_name); /* Return class as is without adding this ivar. */ - return class; + return klass; } #ifdef OBJCPLUS - /* zlaski 2001-Apr-24: C++ classes with non-trivial constructors and/or destructors - cannot be ivars; ditto for classes with vtables. */ - if(IS_AGGR_TYPE (field_type) && (TYPE_NEEDS_CONSTRUCTING (field_type) - || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type) || TYPE_POLYMORPHIC_P (field_type))) - { - const char *type_name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (field_type)); - if(TYPE_POLYMORPHIC_P (field_type)) { - /* vtable pointers are Real Bad(tm), since Obj-C cannot initialize them */ - error ("type %qs has virtual member functions", type_name); - error ("illegal aggregate type %qs specified for instance variable %qs", - type_name, ivar_name); - /* Return class as is without adding this ivar. */ - return class; - } - /* user-defined constructors and destructors are not known to Obj-C and - hence will not be called. This may or may not be a problem. */ - if (TYPE_NEEDS_CONSTRUCTING (field_type)) - warning ("type %qs has a user-defined constructor", type_name); - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)) - warning ("type %qs has a user-defined destructor", type_name); - warning ("C++ constructors and destructors will not be invoked for Objective-C fields"); + /* 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 + constructor/destructor call from '- .cxx_construct' or '- .cxx_destruct' + methods (if '-fobjc-call-cxx-cdtors' was specified). */ + if (MAYBE_CLASS_TYPE_P (field_type) + && (TYPE_NEEDS_CONSTRUCTING (field_type) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type) + || TYPE_POLYMORPHIC_P (field_type))) + { + tree type_name = OBJC_TYPE_NAME (field_type); + + if (flag_objc_call_cxx_cdtors) + { + /* Since the ObjC runtime will be calling the constructors and + destructors for us, the only thing we can't handle is the lack + of a default constructor. */ + if (TYPE_NEEDS_CONSTRUCTING (field_type) + && !TYPE_HAS_DEFAULT_CONSTRUCTOR (field_type)) + { + warning (0, "type %qE has no default constructor to call", + type_name); + + /* If we cannot call a constructor, we should also avoid + calling the destructor, for symmetry. */ + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)) + warning (0, "destructor for %qE shall not be run either", + type_name); + } + } + else + { + static bool warn_cxx_ivars = false; + + if (TYPE_POLYMORPHIC_P (field_type)) + { + /* Vtable pointers are Real Bad(tm), since Obj-C cannot + initialize them. */ + error ("type %qE has virtual member functions", type_name); + error ("illegal aggregate type %qE specified " + "for instance variable %qs", + type_name, ivar_name); + /* Return class as is without adding this ivar. */ + return klass; + } + + /* User-defined constructors and destructors are not known to Obj-C + and hence will not be called. This may or may not be a problem. */ + if (TYPE_NEEDS_CONSTRUCTING (field_type)) + warning (0, "type %qE has a user-defined constructor", type_name); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)) + warning (0, "type %qE has a user-defined destructor", type_name); + + if (!warn_cxx_ivars) + { + warning (0, "C++ constructors and destructors will not " + "be invoked for Objective-C fields"); + warn_cxx_ivars = true; + } + } } #endif /* Overload the public attribute, it is not used for FIELD_DECLs. */ - switch (public) + switch (visibility) { case 0: TREE_PUBLIC (field_decl) = 0; @@ -6317,9 +7203,9 @@ add_instance_variable (tree class, int public, tree field_decl) } - CLASS_RAW_IVARS (class) = chainon (CLASS_RAW_IVARS (class), field_decl); + CLASS_RAW_IVARS (klass) = chainon (CLASS_RAW_IVARS (klass), field_decl); - return class; + return klass; } static tree @@ -6346,22 +7232,32 @@ is_private (tree decl) int objc_is_public (tree expr, tree identifier) { - tree basetype = TREE_TYPE (expr); - enum tree_code code = TREE_CODE (basetype); - tree decl; + tree basetype, decl; + +#ifdef OBJCPLUS + if (processing_template_decl) + return 1; +#endif - if (code == RECORD_TYPE) + if (TREE_TYPE (expr) == error_mark_node) + return 1; + + basetype = TYPE_MAIN_VARIANT (TREE_TYPE (expr)); + + if (basetype && TREE_CODE (basetype) == RECORD_TYPE) { - if (TREE_STATIC_TEMPLATE (basetype)) + if (TYPE_HAS_OBJC_INFO (basetype) && TYPE_OBJC_INTERFACE (basetype)) { - if (!lookup_interface (OBJC_TYPE_NAME (basetype))) + tree klass = lookup_interface (OBJC_TYPE_NAME (basetype)); + + if (!klass) { - error ("cannot find interface declaration for %qs", - IDENTIFIER_POINTER (OBJC_TYPE_NAME (basetype))); + error ("cannot find interface declaration for %qE", + OBJC_TYPE_NAME (basetype)); return 0; } - if ((decl = is_ivar (TYPE_FIELDS (basetype), identifier))) + if ((decl = is_ivar (get_class_ivars (klass, true), identifier))) { if (TREE_PUBLIC (decl)) return 1; @@ -6370,44 +7266,45 @@ objc_is_public (tree expr, tree identifier) all instance variables should be public within the context of the implementation. */ if (objc_implementation_context - && (((TREE_CODE (objc_implementation_context) - == CLASS_IMPLEMENTATION_TYPE) - || (TREE_CODE (objc_implementation_context) - == CATEGORY_IMPLEMENTATION_TYPE)) - && (CLASS_NAME (objc_implementation_context) - == OBJC_TYPE_NAME (basetype)))) + && ((TREE_CODE (objc_implementation_context) + == CLASS_IMPLEMENTATION_TYPE) + || (TREE_CODE (objc_implementation_context) + == CATEGORY_IMPLEMENTATION_TYPE))) { - int private = is_private (decl); + tree curtype = TYPE_MAIN_VARIANT + (CLASS_STATIC_TEMPLATE + (implementation_template)); - if (private) - error ("instance variable %qs is declared private", - IDENTIFIER_POINTER (DECL_NAME (decl))); - return !private; + if (basetype == curtype + || DERIVED_FROM_P (basetype, curtype)) + { + int priv = is_private (decl); + + if (priv) + error ("instance variable %qE is declared private", + DECL_NAME (decl)); + + return !priv; + } } /* The 2.95.2 compiler sometimes allowed C functions to access non-@public ivars. We will let this slide for now... */ if (!objc_method_context) { - warning ("instance variable %qs is %s; " + warning (0, "instance variable %qE is %s; " "this will be a hard error in the future", - IDENTIFIER_POINTER (identifier), + identifier, TREE_PRIVATE (decl) ? "@private" : "@protected"); return 1; } - - error ("instance variable %qs is declared %s", - IDENTIFIER_POINTER (identifier), + + error ("instance variable %qE is declared %s", + identifier, TREE_PRIVATE (decl) ? "private" : "protected"); return 0; } } - - else if (objc_implementation_context && (basetype == objc_object_reference)) - { - expr = convert (uprivate_record, expr); - warning ("static access to object of type %"); - } } return 1; @@ -6428,17 +7325,17 @@ check_methods (tree chain, tree list, int mtype) { if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) - warning ("incomplete implementation of class %qs", - IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context))); + warning (0, "incomplete implementation of class %qE", + CLASS_NAME (objc_implementation_context)); else if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE) - warning ("incomplete implementation of category %qs", - IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); + warning (0, "incomplete implementation of category %qE", + CLASS_SUPER_NAME (objc_implementation_context)); first = 0; } - warning ("method definition for %<%c%s%> not found", - mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain))); + warning (0, "method definition for %<%c%E%> not found", + mtype, METHOD_SEL_NAME (chain)); } chain = TREE_CHAIN (chain); @@ -6447,21 +7344,21 @@ check_methods (tree chain, tree list, int mtype) return first; } -/* Check if CLASS, or its superclasses, explicitly conforms to PROTOCOL. */ +/* Check if KLASS, or its superclasses, explicitly conforms to PROTOCOL. */ static int -conforms_to_protocol (tree class, tree protocol) +conforms_to_protocol (tree klass, tree protocol) { if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE) { - tree p = CLASS_PROTOCOL_LIST (class); + tree p = CLASS_PROTOCOL_LIST (klass); while (p && TREE_VALUE (p) != protocol) p = TREE_CHAIN (p); if (!p) { - tree super = (CLASS_SUPER_NAME (class) - ? lookup_interface (CLASS_SUPER_NAME (class)) + tree super = (CLASS_SUPER_NAME (klass) + ? lookup_interface (CLASS_SUPER_NAME (klass)) : NULL_TREE); int tmp = super ? conforms_to_protocol (super, protocol) : 0; if (!tmp) @@ -6516,18 +7413,16 @@ check_methods_accessible (tree chain, tree context, int mtype) { if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) - warning ("incomplete implementation of class %qs", - IDENTIFIER_POINTER - (CLASS_NAME (objc_implementation_context))); + warning (0, "incomplete implementation of class %qE", + CLASS_NAME (objc_implementation_context)); else if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE) - warning ("incomplete implementation of category %qs", - IDENTIFIER_POINTER - (CLASS_SUPER_NAME (objc_implementation_context))); + warning (0, "incomplete implementation of category %qE", + CLASS_SUPER_NAME (objc_implementation_context)); first = 0; } - warning ("method definition for %<%c%s%> not found", - mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain))); + warning (0, "method definition for %<%c%E%> not found", + mtype, METHOD_SEL_NAME (chain)); } chain = TREE_CHAIN (chain); /* next method... */ @@ -6540,7 +7435,7 @@ check_methods_accessible (tree chain, tree context, int mtype) with any protocols that P inherits. */ static void -check_protocol (tree p, const char *type, const char *name) +check_protocol (tree p, const char *type, tree name) { if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) { @@ -6567,8 +7462,8 @@ check_protocol (tree p, const char *type, const char *name) } if (!f1 || !f2) - warning ("%s %qs does not fully implement the %qs protocol", - type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + warning (0, "%s %qE does not fully implement the %qE protocol", + type, name, PROTOCOL_NAME (p)); } /* Check protocols recursively. */ @@ -6596,7 +7491,7 @@ check_protocol (tree p, const char *type, const char *name) in PROTO_LIST. */ static void -check_protocols (tree proto_list, const char *type, const char *name) +check_protocols (tree proto_list, const char *type, tree name) { for ( ; proto_list; proto_list = TREE_CHAIN (proto_list)) { @@ -6615,7 +7510,7 @@ static tree start_class (enum tree_code code, tree class_name, tree super_name, tree protocol_list) { - tree class, decl; + tree klass, decl; #ifdef OBJCPLUS if (current_namespace != global_namespace) { @@ -6625,36 +7520,45 @@ start_class (enum tree_code code, tree class_name, tree super_name, if (objc_implementation_context) { - warning ("%<@end%> missing in implementation context"); + warning (0, "%<@end%> missing in implementation context"); finish_class (objc_implementation_context); objc_ivar_chain = NULL_TREE; objc_implementation_context = NULL_TREE; } - class = make_node (code); - TYPE_LANG_SLOT_1 (class) = make_tree_vec (CLASS_LANG_SLOT_ELTS); + klass = make_node (code); + TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS); - /* Check for existence of the super class, if one was specified. */ + /* 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 + are looking at a @compatibility_alias, traverse it first. */ if ((code == CLASS_INTERFACE_TYPE || code == CLASS_IMPLEMENTATION_TYPE) - && super_name && !objc_is_class_name (super_name)) + && super_name) { - error ("cannot find interface declaration for %qs, superclass of %qs", - IDENTIFIER_POINTER (super_name), - IDENTIFIER_POINTER (class_name)); - super_name = NULL_TREE; + tree super = objc_is_class_name (super_name); + + if (!super || !lookup_interface (super)) + { + error ("cannot find interface declaration for %qE, superclass of %qE", + super ? super : super_name, + class_name); + super_name = NULL_TREE; + } + else + super_name = super; } - CLASS_NAME (class) = class_name; - CLASS_SUPER_NAME (class) = super_name; - CLASS_CLS_METHODS (class) = NULL_TREE; + CLASS_NAME (klass) = class_name; + CLASS_SUPER_NAME (klass) = super_name; + CLASS_CLS_METHODS (klass) = NULL_TREE; if (! objc_is_class_name (class_name) && (decl = lookup_name (class_name))) { - error ("%qs redeclared as different kind of symbol", - IDENTIFIER_POINTER (class_name)); - error ("%Jprevious declaration of '%D'", - decl, decl); + error ("%qE redeclared as different kind of symbol", + class_name); + error ("previous declaration of %q+D", + decl); } if (code == CLASS_IMPLEMENTATION_TYPE) @@ -6665,8 +7569,8 @@ start_class (enum tree_code code, tree class_name, tree super_name, for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain)) if (TREE_VALUE (chain) == class_name) { - error ("reimplementation of class %qs", - IDENTIFIER_POINTER (class_name)); + error ("reimplementation of class %qE", + class_name); return error_mark_node; } implemented_classes = tree_cons (NULL_TREE, class_name, @@ -6676,15 +7580,16 @@ start_class (enum tree_code code, tree class_name, tree super_name, /* Reset for multiple classes per file. */ method_slot = 0; - objc_implementation_context = class; + objc_implementation_context = klass; /* Lookup the interface for this implementation. */ if (!(implementation_template = lookup_interface (class_name))) { - warning ("cannot find interface declaration for %qs", - IDENTIFIER_POINTER (class_name)); - add_class (implementation_template = objc_implementation_context); + warning (0, "cannot find interface declaration for %qE", + class_name); + add_class (implementation_template = objc_implementation_context, + class_name); } /* If a super class has been specified in the implementation, @@ -6694,11 +7599,12 @@ start_class (enum tree_code code, tree class_name, tree super_name, && (super_name != CLASS_SUPER_NAME (implementation_template))) { tree previous_name = CLASS_SUPER_NAME (implementation_template); - const char *const name = - previous_name ? IDENTIFIER_POINTER (previous_name) : ""; - error ("conflicting super class name %qs", - IDENTIFIER_POINTER (super_name)); - error ("previous declaration of %qs", name); + error ("conflicting super class name %qE", + super_name); + if (previous_name) + error ("previous declaration of %qE", previous_name); + else + error ("previous declaration"); } else if (! super_name) @@ -6712,16 +7618,16 @@ start_class (enum tree_code code, tree class_name, tree super_name, { if (lookup_interface (class_name)) #ifdef OBJCPLUS - error ("duplicate interface declaration for class %qs", + error ("duplicate interface declaration for class %qE", #else - warning ("duplicate interface declaration for class %qs", -#endif - IDENTIFIER_POINTER (class_name)); + warning (0, "duplicate interface declaration for class %qE", +#endif + class_name); else - add_class (class); + add_class (klass, class_name); if (protocol_list) - CLASS_PROTOCOL_LIST (class) + CLASS_PROTOCOL_LIST (klass) = lookup_and_install_protocols (protocol_list); } @@ -6735,15 +7641,15 @@ start_class (enum tree_code code, tree class_name, tree super_name, if (!(class_category_is_assoc_with = lookup_interface (class_name))) { - error ("cannot find interface declaration for %qs", - IDENTIFIER_POINTER (class_name)); + error ("cannot find interface declaration for %qE", + class_name); exit (FATAL_EXIT_CODE); } else - add_category (class_category_is_assoc_with, class); + add_category (class_category_is_assoc_with, klass); if (protocol_list) - CLASS_PROTOCOL_LIST (class) + CLASS_PROTOCOL_LIST (klass) = lookup_and_install_protocols (protocol_list); } @@ -6752,7 +7658,7 @@ start_class (enum tree_code code, tree class_name, tree super_name, /* Reset for multiple classes per file. */ method_slot = 0; - objc_implementation_context = class; + objc_implementation_context = klass; /* For a category, class_name is really the name of the class that the following set of methods will be associated with. We must @@ -6760,27 +7666,26 @@ start_class (enum tree_code code, tree class_name, tree super_name, if (!(implementation_template = lookup_interface (class_name))) { - error ("cannot find interface declaration for %qs", - IDENTIFIER_POINTER (class_name)); + error ("cannot find interface declaration for %qE", + class_name); exit (FATAL_EXIT_CODE); } } - return class; + return klass; } static tree -continue_class (tree class) +continue_class (tree klass) { - if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE - || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) + if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE + || TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE) { struct imp_entry *imp_entry; - tree ivar_context; /* Check consistency of the instance variables. */ - if (CLASS_RAW_IVARS (class)) - check_ivars (implementation_template, class); + if (CLASS_RAW_IVARS (klass)) + check_ivars (implementation_template, klass); /* code generation */ @@ -6788,21 +7693,24 @@ continue_class (tree class) push_lang_context (lang_name_c); #endif - ivar_context = build_private_template (implementation_template); + build_private_template (implementation_template); + uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template); + objc_instance_type = build_pointer_type (uprivate_record); imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry)); imp_entry->next = imp_list; - imp_entry->imp_context = class; + imp_entry->imp_context = klass; imp_entry->imp_template = implementation_template; synth_forward_declarations (); imp_entry->class_decl = UOBJC_CLASS_decl; imp_entry->meta_decl = UOBJC_METACLASS_decl; + imp_entry->has_cxx_cdtors = 0; /* Append to front and increment count. */ imp_list = imp_entry; - if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) + if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE) imp_count++; else cat_count++; @@ -6811,24 +7719,16 @@ continue_class (tree class) pop_lang_context (); #endif /* OBJCPLUS */ - return ivar_context; + return get_class_ivars (implementation_template, true); } - else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE) + else if (TREE_CODE (klass) == CLASS_INTERFACE_TYPE) { #ifdef OBJCPLUS push_lang_context (lang_name_c); #endif /* OBJCPLUS */ - if (!CLASS_STATIC_TEMPLATE (class)) - { - tree record = start_struct (RECORD_TYPE, CLASS_NAME (class)); - finish_struct (record, get_class_ivars (class), NULL_TREE); - CLASS_STATIC_TEMPLATE (class) = record; - - /* Mark this record as a class template for static typing. */ - TREE_STATIC_TEMPLATE (record) = 1; - } + build_private_template (klass); #ifdef OBJCPLUS pop_lang_context (); @@ -6844,9 +7744,9 @@ continue_class (tree class) /* This is called once we see the "@end" in an interface/implementation. */ static void -finish_class (tree class) +finish_class (tree klass) { - if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) + if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE) { /* All code generation is done in finish_objc. */ @@ -6861,13 +7761,13 @@ finish_class (tree class) if (CLASS_PROTOCOL_LIST (implementation_template)) check_protocols (CLASS_PROTOCOL_LIST (implementation_template), "class", - IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context))); + CLASS_NAME (objc_implementation_context)); } } - else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) + else if (TREE_CODE (klass) == CATEGORY_IMPLEMENTATION_TYPE) { - tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class)); + tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (klass)); if (category) { @@ -6880,7 +7780,7 @@ finish_class (tree class) if (CLASS_PROTOCOL_LIST (category)) check_protocols (CLASS_PROTOCOL_LIST (category), "category", - IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); + CLASS_SUPER_NAME (objc_implementation_context)); } } } @@ -6974,8 +7874,8 @@ start_protocol (enum tree_code code, tree name, tree list) } else { - warning ("duplicate declaration for protocol %qs", - IDENTIFIER_POINTER (name)); + warning (0, "duplicate declaration for protocol %qE", + name); } return protocol; } @@ -7025,7 +7925,8 @@ encode_pointer (tree type, int curtype, int format) obstack_1grow (&util_obstack, '@'); return; } - else if (TREE_STATIC_TEMPLATE (pointer_to)) + else if (TYPE_HAS_OBJC_INFO (pointer_to) + && TYPE_OBJC_INTERFACE (pointer_to)) { if (generating_instance_variables) { @@ -7093,9 +7994,12 @@ encode_array (tree type, int curtype, int format) return; } - sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, - (TREE_INT_CST_LOW (an_int_cst) - / TREE_INT_CST_LOW (TYPE_SIZE (array_of)))); + if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0) + sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0); + else + sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (an_int_cst) + / TREE_INT_CST_LOW (TYPE_SIZE (array_of))); obstack_grow (&util_obstack, buffer, strlen (buffer)); encode_type (array_of, curtype, format); @@ -7104,24 +8008,66 @@ encode_array (tree type, int curtype, int format) } static void +encode_aggregate_fields (tree type, int pointed_to, int curtype, int format) +{ + tree field = TYPE_FIELDS (type); + + for (; field; field = TREE_CHAIN (field)) + { +#ifdef OBJCPLUS + /* C++ static members, and things that are not field at all, + should not appear in the encoding. */ + if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field)) + continue; +#endif + + /* Recursively encode fields of embedded base classes. */ + if (DECL_ARTIFICIAL (field) && !DECL_NAME (field) + && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) + { + encode_aggregate_fields (TREE_TYPE (field), + pointed_to, curtype, format); + continue; + } + + if (generating_instance_variables && !pointed_to) + { + tree fname = DECL_NAME (field); + + obstack_1grow (&util_obstack, '"'); + + if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (fname), + strlen (IDENTIFIER_POINTER (fname))); + + obstack_1grow (&util_obstack, '"'); + } + + encode_field_decl (field, curtype, format); + } +} + +static void encode_aggregate_within (tree type, int curtype, int format, int left, int right) { tree name; /* NB: aggregates that are pointed to have slightly different encoding rules in that you never encode the names of instance variables. */ - int pointed_to - = (obstack_object_size (&util_obstack) > 0 - && *(obstack_next_free (&util_obstack) - 1) == '^'); + int ob_size = obstack_object_size (&util_obstack); + char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0; + char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0; + int pointed_to = (c0 == '^' || (c1 == '^' && c0 == 'r')); int inline_contents = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) - && (!pointed_to || obstack_object_size (&util_obstack) - curtype == 1)); + && (!pointed_to || ob_size - curtype == (c1 == 'r' ? 2 : 1))); /* Traverse struct aliases; it is important to get the original struct and its tag name (if any). */ type = TYPE_MAIN_VARIANT (type); name = OBJC_TYPE_NAME (type); - /* Open parenth/bracket. */ + /* Open parenth/bracket. */ obstack_1grow (&util_obstack, left); /* Encode the struct/union tag name, or '?' if a tag was @@ -7142,32 +8088,10 @@ encode_aggregate_within (tree type, int curtype, int format, int left, if required. */ if (inline_contents) { - tree fields = TYPE_FIELDS (type); - obstack_1grow (&util_obstack, '='); - for (; fields; fields = TREE_CHAIN (fields)) - { -#ifdef OBJCPLUS - /* C++ static members, and things that are not fields at all, - should not appear in the encoding. */ - if (TREE_CODE (fields) != FIELD_DECL || TREE_STATIC (fields)) - continue; -#endif - if (generating_instance_variables && !pointed_to) - { - tree fname = DECL_NAME (fields); - - obstack_1grow (&util_obstack, '"'); - if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (fname), - strlen (IDENTIFIER_POINTER (fname))); - obstack_1grow (&util_obstack, '"'); - } - encode_field_decl (fields, curtype, format); - } + encode_aggregate_fields (type, pointed_to, curtype, format); } - /* Close parenth/bracket. */ + /* Close parenth/bracket. */ obstack_1grow (&util_obstack, right); } @@ -7216,6 +8140,9 @@ encode_type (tree type, int curtype, int format) enum tree_code code = TREE_CODE (type); char c; + if (type == error_mark_node) + return; + if (TYPE_READONLY (type)) obstack_1grow (&util_obstack, 'r'); @@ -7225,7 +8152,7 @@ encode_type (tree type, int curtype, int format) { case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break; case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break; - case 32: + case 32: if (type == long_unsigned_type_node || type == long_integer_type_node) c = TYPE_UNSIGNED (type) ? 'L' : 'l'; @@ -7269,6 +8196,12 @@ encode_type (tree type, int curtype, int format) else if (code == FUNCTION_TYPE) /* '?' */ obstack_1grow (&util_obstack, '?'); + + else if (code == COMPLEX_TYPE) + { + obstack_1grow (&util_obstack, 'j'); + encode_type (TREE_TYPE (type), curtype, format); + } } static void @@ -7365,10 +8298,38 @@ static GTY(()) tree objc_parmlist = NULL_TREE; static void objc_push_parm (tree parm) { - /* Convert array parameters of unknown size into pointers. */ - if (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE - && !TYPE_SIZE (TREE_TYPE (parm))) - TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (TREE_TYPE (parm))); + bool relayout_needed = false; + + if (TREE_TYPE (parm) == error_mark_node) + { + objc_parmlist = chainon (objc_parmlist, parm); + return; + } + + /* Decay arrays and functions into pointers. */ + if (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE) + { + TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (TREE_TYPE (parm))); + relayout_needed = true; + } + else if (TREE_CODE (TREE_TYPE (parm)) == FUNCTION_TYPE) + { + TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (parm)); + relayout_needed = true; + } + + if (relayout_needed) + relayout_decl (parm); + + + DECL_ARG_TYPE (parm) + = lang_hooks.types.type_promotes_to (TREE_TYPE (parm)); + + /* Record constancy and volatility. */ + c_apply_type_quals_to_decl + ((TYPE_READONLY (TREE_TYPE (parm)) ? TYPE_QUAL_CONST : 0) + | (TYPE_RESTRICT (TREE_TYPE (parm)) ? TYPE_QUAL_RESTRICT : 0) + | (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm); objc_parmlist = chainon (objc_parmlist, parm); } @@ -7400,8 +8361,9 @@ objc_get_parm_info (int have_ellipsis) { tree next = TREE_CHAIN (parm_info); - TREE_CHAIN (parm_info) = NULL_TREE; - pushdecl (parm_info); + TREE_CHAIN (parm_info) = NULL_TREE; + parm_info = pushdecl (parm_info); + finish_decl (parm_info, NULL_TREE, NULL_TREE, NULL_TREE); parm_info = next; } arg_info = get_parm_info (have_ellipsis); @@ -7450,6 +8412,15 @@ start_method_def (tree method) #endif int have_ellipsis = 0; + /* 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 + it is. */ + if(CLASS_SUPER_NAME (objc_implementation_context) + && !strcmp ("dealloc", IDENTIFIER_POINTER (METHOD_SEL_NAME (method)))) + should_call_super_dealloc = 1; + else + should_call_super_dealloc = 0; + /* Required to implement _msgSuper. */ objc_method_context = method; UOBJC_SUPER_decl = NULL_TREE; @@ -7461,9 +8432,9 @@ start_method_def (tree method) parmlist = METHOD_SEL_ARGS (method); while (parmlist) { - tree parm = build_decl (PARM_DECL, KEYWORD_ARG_NAME (parmlist), - TREE_VALUE (TREE_TYPE (parmlist))); + tree type = TREE_VALUE (TREE_TYPE (parmlist)), parm; + parm = build_decl (PARM_DECL, KEYWORD_ARG_NAME (parmlist), type); objc_push_parm (parm); parmlist = TREE_CHAIN (parmlist); } @@ -7472,13 +8443,13 @@ start_method_def (tree method) { tree akey; - for (akey = TREE_CHAIN (METHOD_ADD_ARGS (method)); + for (akey = TREE_CHAIN (METHOD_ADD_ARGS (method)); akey; akey = TREE_CHAIN (akey)) { objc_push_parm (TREE_VALUE (akey)); } - if (TREE_OVERFLOW (METHOD_ADD_ARGS (method))) + if (METHOD_ADD_ARGS_ELLIPSIS_P (method)) have_ellipsis = 1; } @@ -7487,14 +8458,6 @@ start_method_def (tree method) really_start_method (objc_method_context, parm_info); } -static void -warn_with_method (const char *message, int mtype, tree method) -{ - /* Add a readable method name to the warning. */ - warning ("%J%s %<%c%s%>", method, - message, mtype, gen_method_decl (method)); -} - /* Return 1 if TYPE1 is equivalent to TYPE2 for purposes of method overloading. */ @@ -7511,8 +8474,13 @@ objc_types_are_equivalent (tree type1, tree type2) if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)) return 0; - type1 = TYPE_PROTOCOL_LIST (type1); - type2 = TYPE_PROTOCOL_LIST (type2); + type1 = (TYPE_HAS_OBJC_INFO (type1) + ? TYPE_OBJC_PROTOCOL_LIST (type1) + : NULL_TREE); + type2 = (TYPE_HAS_OBJC_INFO (type2) + ? TYPE_OBJC_PROTOCOL_LIST (type2) + : NULL_TREE); + if (list_length (type1) == list_length (type2)) { for (; type2; type2 = TREE_CHAIN (type2)) @@ -7523,11 +8491,23 @@ objc_types_are_equivalent (tree type1, tree type2) return 0; } +/* Return 1 if TYPE1 has the same size and alignment as TYPE2. */ + +static int +objc_types_share_size_and_alignment (tree type1, tree type2) +{ + return (simple_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2)) + && TYPE_ALIGN (type1) == TYPE_ALIGN (type2)); +} + /* Return 1 if PROTO1 is equivalent to PROTO2 - for purposes of method overloading. */ + for purposes of method overloading. Ordinarily, the type signatures + should match up exactly, unless STRICT is zero, in which case we + shall allow differences in which the size and alignment of a type + is the same. */ static int -comp_proto_with_proto (tree proto1, tree proto2) +comp_proto_with_proto (tree proto1, tree proto2, int strict) { tree type1, type2; @@ -7540,7 +8520,8 @@ comp_proto_with_proto (tree proto1, tree proto2) type1 = TREE_VALUE (TREE_TYPE (proto1)); 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))) return 0; /* Compare argument types. */ @@ -7549,7 +8530,10 @@ comp_proto_with_proto (tree proto1, tree proto2) type1 && 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 + || !objc_types_share_size_and_alignment (TREE_VALUE (type1), + TREE_VALUE (type2)))) return 0; } @@ -7596,24 +8580,42 @@ objc_start_function (tree name, tree type, tree attrs, #ifdef OBJCPLUS DECL_ARGUMENTS (fndecl) = params; -#endif DECL_INITIAL (fndecl) = error_mark_node; DECL_EXTERNAL (fndecl) = 0; TREE_STATIC (fndecl) = 1; - -#ifdef OBJCPLUS retrofit_lang_decl (fndecl); cplus_decl_attributes (&fndecl, attrs, 0); start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT); #else + struct c_label_context_se *nstack_se; + struct c_label_context_vm *nstack_vm; + nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se); + nstack_se->labels_def = NULL; + nstack_se->labels_used = NULL; + nstack_se->next = label_context_stack_se; + label_context_stack_se = nstack_se; + nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm); + nstack_vm->labels_def = NULL; + nstack_vm->labels_used = NULL; + nstack_vm->scope = 0; + nstack_vm->next = label_context_stack_vm; + label_context_stack_vm = nstack_vm; + current_function_returns_value = 0; /* Assume, until we see it does. */ + current_function_returns_null = 0; + decl_attributes (&fndecl, attrs, 0); announce_function (fndecl); + DECL_INITIAL (fndecl) = error_mark_node; + DECL_EXTERNAL (fndecl) = 0; + TREE_STATIC (fndecl) = 1; current_function_decl = pushdecl (fndecl); push_scope (); declare_parm_level (); DECL_RESULT (current_function_decl) = build_decl (RESULT_DECL, NULL_TREE, TREE_TYPE (TREE_TYPE (current_function_decl))); + DECL_ARTIFICIAL (DECL_RESULT (current_function_decl)) = 1; + DECL_IGNORED_P (DECL_RESULT (current_function_decl)) = 1; start_fname_decls (); store_parm_decls_from (params); #endif @@ -7691,16 +8693,21 @@ really_start_method (tree method, tree proto = lookup_method_static (implementation_template, METHOD_SEL_NAME (method), - TREE_CODE (method) == CLASS_METHOD_DECL); + ((TREE_CODE (method) == CLASS_METHOD_DECL) + | OBJC_LOOKUP_NO_SUPER)); if (proto) { - if (!comp_proto_with_proto (method, proto)) + if (!comp_proto_with_proto (method, proto, 1)) { - char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); - - warn_with_method ("conflicting types for", type, method); - warn_with_method ("previous declaration of", type, proto); + bool type = TREE_CODE (method) == INSTANCE_METHOD_DECL; + + warning (0, "%Jconflicting types for %<%c%s%>", method, + (type ? '-' : '+'), + identifier_to_locale (gen_method_decl (method))); + inform (0, "%Jprevious declaration of %<%c%s%>", proto, + (type ? '-' : '+'), + identifier_to_locale (gen_method_decl (proto))); } } else @@ -7747,29 +8754,32 @@ get_super_receiver (void) /* This prevents `unused variable' warnings when compiling with -Wall. */ TREE_USED (UOBJC_SUPER_decl) = 1; lang_hooks.decls.pushdecl (UOBJC_SUPER_decl); - finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); + finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE, NULL_TREE); UOBJC_SUPER_scope = objc_get_current_scope (); } /* Set receiver to self. */ - super_expr = build_component_ref (UOBJC_SUPER_decl, self_id); - super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl); + super_expr = objc_build_component_ref (UOBJC_SUPER_decl, self_id); + super_expr = build_modify_expr (input_location, super_expr, NULL_TREE, + NOP_EXPR, self_decl, NULL_TREE); super_expr_list = super_expr; /* Set class to begin searching. */ - super_expr = build_component_ref (UOBJC_SUPER_decl, - get_identifier ("super_class")); + super_expr = objc_build_component_ref (UOBJC_SUPER_decl, + get_identifier ("super_class")); if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) { /* [_cls, __cls]Super are "pre-built" in synth_forward_declarations. */ - super_expr = build_modify_expr (super_expr, NOP_EXPR, + super_expr = build_modify_expr (input_location, super_expr, + NULL_TREE, NOP_EXPR, ((TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) ? ucls_super_ref - : uucls_super_ref)); + : uucls_super_ref), + NULL_TREE); } else @@ -7781,8 +8791,8 @@ get_super_receiver (void) /* Barf if super used in a category of Object. */ if (!super_name) { - error ("no super class declared in interface for %qs", - IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); + error ("no super class declared in interface for %qE", + CLASS_NAME (implementation_template)); return error_mark_node; } @@ -7796,8 +8806,9 @@ get_super_receiver (void) "isa" is the first ivar in a class (which it must be). */ super_class = build_indirect_ref - (build_c_cast (build_pointer_type (objc_class_type), - super_class), "unary *"); + (input_location, + build_c_cast (build_pointer_type (objc_class_type), + super_class), "unary *"); } else { @@ -7810,19 +8821,23 @@ get_super_receiver (void) (super_class, build_tree_list (NULL_TREE, - my_build_string (IDENTIFIER_LENGTH (super_name) + 1, - IDENTIFIER_POINTER (super_name)))); + my_build_string_pointer + (IDENTIFIER_LENGTH (super_name) + 1, + IDENTIFIER_POINTER (super_name)))); } super_expr - = build_modify_expr (super_expr, NOP_EXPR, + = build_modify_expr (input_location, super_expr, NULL_TREE, + NOP_EXPR, build_c_cast (TREE_TYPE (super_expr), - super_class)); + super_class), + NULL_TREE); } super_expr_list = build_compound_expr (super_expr_list, super_expr); - super_expr = build_unary_op (ADDR_EXPR, UOBJC_SUPER_decl, 0); + super_expr = build_unary_op (input_location, + ADDR_EXPR, UOBJC_SUPER_decl, 0); super_expr_list = build_compound_expr (super_expr_list, super_expr); return super_expr_list; @@ -7853,7 +8868,6 @@ objc_finish_method_definition (tree fndecl) /* We cannot validly inline ObjC methods, at least not without a language extension to declare that a method need not be dynamically dispatched, so suppress all thoughts of doing so. */ - DECL_INLINE (fndecl) = 0; DECL_UNINLINABLE (fndecl) = 1; #ifndef OBJCPLUS @@ -7867,23 +8881,10 @@ objc_finish_method_definition (tree fndecl) /* Required to implement _msgSuper. This must be done AFTER finish_function, since the optimizer may find "may be used before set" errors. */ objc_method_context = NULL_TREE; -} - -#if 0 -int -lang_report_error_function (tree decl) -{ - if (objc_method_context) - { - fprintf (stderr, "In method %qs\n", - IDENTIFIER_POINTER (METHOD_SEL_NAME (objc_method_context))); - return 1; - } - else - return 0; + if (should_call_super_dealloc) + warning (0, "method possibly missing a [super dealloc] call"); } -#endif /* Given a tree DECL node, produce a printable description of it in the given buffer, overwriting the buffer. */ @@ -7910,7 +8911,7 @@ gen_declaration (tree decl) sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC, TREE_INT_CST_LOW (DECL_INITIAL (decl))); } - + return errbuf; } @@ -7924,29 +8925,61 @@ gen_type_name_0 (tree type) if (TYPE_P (type) && TYPE_NAME (type)) type = TYPE_NAME (type); - else if (POINTER_TYPE_P (type)) + else if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) { - gen_type_name_0 (TREE_TYPE (type)); - - if (!POINTER_TYPE_P (TREE_TYPE (type))) + tree inner = TREE_TYPE (type); + + while (TREE_CODE (inner) == ARRAY_TYPE) + inner = TREE_TYPE (inner); + + gen_type_name_0 (inner); + + if (!POINTER_TYPE_P (inner)) strcat (errbuf, " "); - strcat (errbuf, "*"); + if (POINTER_TYPE_P (type)) + strcat (errbuf, "*"); + else + while (type != inner) + { + strcat (errbuf, "["); + + if (TYPE_DOMAIN (type)) + { + char sz[20]; + + sprintf (sz, HOST_WIDE_INT_PRINT_DEC, + (TREE_INT_CST_LOW + (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1)); + strcat (errbuf, sz); + } + + strcat (errbuf, "]"); + type = TREE_TYPE (type); + } + goto exit_function; } if (TREE_CODE (type) == TYPE_DECL && DECL_NAME (type)) type = DECL_NAME (type); - strcat (errbuf, IDENTIFIER_POINTER (type)); - proto = TYPE_PROTOCOL_LIST (orig); + strcat (errbuf, TREE_CODE (type) == IDENTIFIER_NODE + ? IDENTIFIER_POINTER (type) + : ""); + + /* For 'id' and 'Class', adopted protocols are stored in the pointee. */ + if (objc_is_id (orig)) + orig = TREE_TYPE (orig); + + proto = TYPE_HAS_OBJC_INFO (orig) ? TYPE_OBJC_PROTOCOL_LIST (orig) : NULL_TREE; if (proto) { strcat (errbuf, " <"); while (proto) { - strcat (errbuf, + strcat (errbuf, IDENTIFIER_POINTER (PROTOCOL_NAME (TREE_VALUE (proto)))); proto = TREE_CHAIN (proto); strcat (errbuf, proto ? ", " : ">"); @@ -8008,7 +9041,7 @@ gen_method_decl (tree method) chain = TREE_CHAIN (chain); } - if (TREE_OVERFLOW (METHOD_ADD_ARGS (method))) + if (METHOD_ADD_ARGS_ELLIPSIS_P (method)) strcat (errbuf, ", ..."); } } @@ -8098,7 +9131,7 @@ objc_demangle (const char *mangled) (mangled[1] == 'i' || mangled[1] == 'c') && mangled[2] == '_') { - cp = demangled = xmalloc(strlen(mangled) + 2); + cp = demangled = XNEWVEC (char, strlen(mangled) + 2); if (mangled[1] == 'i') *cp++ = '-'; /* for instance method */ else @@ -8156,7 +9189,7 @@ init_objc (void) gcc_obstack_init (&util_obstack); util_firstobj = (char *) obstack_finish (&util_obstack); - errbuf = (char *) xmalloc (1024 * 10); + errbuf = XNEWVEC (char, 1024 * 10); hash_init (); synth_module_prologue (); } @@ -8174,7 +9207,7 @@ finish_objc (void) /* A missing @end may not be detected by the parser. */ if (objc_implementation_context) { - warning ("%<@end%> missing in implementation context"); + warning (0, "%<@end%> missing in implementation context"); finish_class (objc_implementation_context); objc_ivar_chain = NULL_TREE; objc_implementation_context = NULL_TREE; @@ -8211,7 +9244,9 @@ finish_objc (void) /* all of the following reference the string pool... */ generate_ivar_lists (); generate_dispatch_tables (); - generate_shared_structures (); + generate_shared_structures (impent->has_cxx_cdtors + ? CLS_HAS_CXX_STRUCTORS + : 0); } else { @@ -8228,7 +9263,7 @@ finish_objc (void) if (protocol_chain) generate_protocols (); - if (flag_replace_objc_classes && imp_list) + if ((flag_replace_objc_classes && imp_list) || flag_objc_gc) generate_objc_image_info (); /* Arrange for ObjC data structures to be initialized at run time. */ @@ -8256,10 +9291,6 @@ finish_objc (void) for (impent = imp_list; impent; impent = impent->next) handle_impent (impent); - /* Dump the string table last. */ - - generate_strings (); - if (warn_selector) { int slot; @@ -8334,6 +9365,8 @@ handle_class_ref (tree chain) DECL_INITIAL (decl) = exp; TREE_STATIC (decl) = 1; TREE_USED (decl) = 1; + /* Force the output of the decl as this forces the reference of the class. */ + mark_decl_referenced (decl); pushdecl (decl); rest_of_decl_compilation (decl, 0, 0); @@ -8410,6 +9443,9 @@ static void generate_objc_image_info (void) { tree decl, initlist; + int flags + = ((flag_replace_objc_classes && imp_list ? 1 : 0) + | (flag_objc_gc ? 2 : 0)); decl = start_var_decl (build_array_type (integer_type_node, @@ -8417,7 +9453,7 @@ generate_objc_image_info (void) "_OBJC_IMAGE_INFO"); initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0)); - initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 1), initlist); + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, flags), initlist); initlist = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist)); finish_var_decl (decl, initlist); @@ -8454,10 +9490,15 @@ objc_lookup_ivar (tree other, tree id) /* In an instance method, a local variable (or parameter) may hide the instance variable. */ if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL - && other && other != error_mark_node && !DECL_FILE_SCOPE_P (other)) + && other && other != error_mark_node +#ifdef OBJCPLUS + && CP_DECL_CONTEXT (other) != global_namespace) +#else + && !DECL_FILE_SCOPE_P (other)) +#endif { - warning ("local declaration of %qs hides instance variable", - IDENTIFIER_POINTER (id)); + warning (0, "local declaration of %qE hides instance variable", + id); return other; } @@ -8468,4 +9509,57 @@ objc_lookup_ivar (tree other, tree id) return build_ivar_reference (id); } +/* 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. */ + +tree +objc_rewrite_function_call (tree function, tree first_param) +{ + if (TREE_CODE (function) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (function, 0), 0)) + == FUNCTION_DECL) + { + function = build3 (OBJ_TYPE_REF, TREE_TYPE (function), + TREE_OPERAND (function, 0), + first_param, size_zero_node); + } + + return function; +} + +/* 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 + of its cousins). */ + +enum gimplify_status +objc_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) +{ + enum gimplify_status r0, r1; + if (TREE_CODE (*expr_p) == OBJ_TYPE_REF + && TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0)) + == FUNCTION_DECL) + { + /* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the + value of the OBJ_TYPE_REF, so force them to be emitted + during subexpression evaluation rather than after the + OBJ_TYPE_REF. This permits objc_msgSend calls in Objective + C to use direct rather than indirect calls when the + object expression has a postincrement. */ + r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL, + is_gimple_val, fb_rvalue); + r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p, + is_gimple_val, fb_rvalue); + + return MIN (r0, r1); + } + +#ifdef OBJCPLUS + return (enum gimplify_status) cp_gimplify_expr (expr_p, pre_p, post_p); +#else + return (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p); +#endif +} + #include "gt-objc-objc-act.h"